blob: d8d5231f484e21e1bbbc3299f80f1d17284bccae [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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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
344 if (ioc->diagPending || !ioc->active)
345 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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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;
1774 ioc->diagPending = 0;
1775 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001776 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301778 mutex_init(&ioc->internal_cmds.mutex);
1779 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301780 mutex_init(&ioc->mptbase_cmds.mutex);
1781 init_completion(&ioc->mptbase_cmds.done);
1782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 /* Initialize the event logging.
1784 */
1785 ioc->eventTypes = 0; /* None */
1786 ioc->eventContext = 0;
1787 ioc->eventLogSize = 0;
1788 ioc->events = NULL;
1789
1790#ifdef MFCNT
1791 ioc->mfcnt = 0;
1792#endif
1793
1794 ioc->cached_fw = NULL;
1795
1796 /* Initilize SCSI Config Data structure
1797 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001798 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
Michael Reed05e8ec12006-01-13 14:31:54 -06001800 /* Initialize the fc rport list head.
1801 */
1802 INIT_LIST_HEAD(&ioc->fc_rports);
1803
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 /* Find lookup slot. */
1805 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001806
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301807
1808 /* Initialize workqueue */
1809 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1810 spin_lock_init(&ioc->fault_reset_work_lock);
1811
Kay Sieversaab0de22008-05-02 06:02:41 +02001812 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1813 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301814 ioc->reset_work_q =
1815 create_singlethread_workqueue(ioc->reset_work_q_name);
1816 if (!ioc->reset_work_q) {
1817 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1818 ioc->name);
1819 pci_release_selected_regions(pdev, ioc->bars);
1820 kfree(ioc);
1821 return -ENOMEM;
1822 }
1823
Eric Moore29dd3602007-09-14 18:46:51 -06001824 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1825 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301827 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1828 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1829
1830 switch (pdev->device)
1831 {
1832 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1833 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1834 ioc->errata_flag_1064 = 1;
1835 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1836 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1838 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301840 break;
1841
1842 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* 929X Chip Fix. Set Split transactions level
1845 * for PCIX. Set MOST bits to zero.
1846 */
1847 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1848 pcixcmd &= 0x8F;
1849 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1850 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 /* 929XL Chip Fix. Set MMRBC to 0x08.
1852 */
1853 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1854 pcixcmd |= 0x08;
1855 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301858 break;
1859
1860 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 /* 919X Chip Fix. Set Split transactions level
1862 * for PCIX. Set MOST bits to zero.
1863 */
1864 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1865 pcixcmd &= 0x8F;
1866 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001867 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301868 break;
1869
1870 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 /* 1030 Chip Fix. Disable Split transactions
1872 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1873 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (revision < C0_1030) {
1875 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1876 pcixcmd &= 0x8F;
1877 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1878 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301879
1880 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001881 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301882 break;
1883
1884 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1885 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001886 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301887
1888 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1889 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1890 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001891 ioc->bus_type = SAS;
1892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301894
Kashyap, Desaie3829682009-01-08 14:27:16 +05301895 switch (ioc->bus_type) {
1896
1897 case SAS:
1898 ioc->msi_enable = mpt_msi_enable_sas;
1899 break;
1900
1901 case SPI:
1902 ioc->msi_enable = mpt_msi_enable_spi;
1903 break;
1904
1905 case FC:
1906 ioc->msi_enable = mpt_msi_enable_fc;
1907 break;
1908
1909 default:
1910 ioc->msi_enable = 0;
1911 break;
1912 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001913 if (ioc->errata_flag_1064)
1914 pci_disable_io_access(pdev);
1915
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 spin_lock_init(&ioc->FreeQlock);
1917
1918 /* Disable all! */
1919 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1920 ioc->active = 0;
1921 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1922
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301923 /* Set IOC ptr in the pcidev's driver data. */
1924 pci_set_drvdata(ioc->pcidev, ioc);
1925
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 /* Set lookup ptr. */
1927 list_add_tail(&ioc->list, &ioc_list);
1928
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001929 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 */
1931 mpt_detect_bound_ports(ioc, pdev);
1932
James Bottomleyc92f2222006-03-01 09:02:49 -06001933 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1934 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001935 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1936 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001937
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001939 if (ioc->alt_ioc)
1940 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301941 iounmap(ioc->memmap);
1942 if (r != -5)
1943 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301944
1945 destroy_workqueue(ioc->reset_work_q);
1946 ioc->reset_work_q = NULL;
1947
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 kfree(ioc);
1949 pci_set_drvdata(pdev, NULL);
1950 return r;
1951 }
1952
1953 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001954 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301955 if(MptDeviceDriverHandlers[cb_idx] &&
1956 MptDeviceDriverHandlers[cb_idx]->probe) {
1957 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 }
1959 }
1960
1961#ifdef CONFIG_PROC_FS
1962 /*
1963 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1964 */
1965 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1966 if (dent) {
1967 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1968 if (ent) {
1969 ent->read_proc = procmpt_iocinfo_read;
1970 ent->data = ioc;
1971 }
1972 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1973 if (ent) {
1974 ent->read_proc = procmpt_summary_read;
1975 ent->data = ioc;
1976 }
1977 }
1978#endif
1979
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301980 if (!ioc->alt_ioc)
1981 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1982 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1983
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 return 0;
1985}
1986
1987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001988/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001989 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 */
1992
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001993void
1994mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995{
1996 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1997 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301998 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301999 unsigned long flags;
2000 struct workqueue_struct *wq;
2001
2002 /*
2003 * Stop polling ioc for fault condition
2004 */
2005 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
2006 wq = ioc->reset_work_q;
2007 ioc->reset_work_q = NULL;
2008 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
2009 cancel_delayed_work(&ioc->fault_reset_work);
2010 destroy_workqueue(wq);
2011
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
2013 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2014 remove_proc_entry(pname, NULL);
2015 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2016 remove_proc_entry(pname, NULL);
2017 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2018 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002019
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002021 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302022 if(MptDeviceDriverHandlers[cb_idx] &&
2023 MptDeviceDriverHandlers[cb_idx]->remove) {
2024 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 }
2026 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002027
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 /* Disable interrupts! */
2029 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2030
2031 ioc->active = 0;
2032 synchronize_irq(pdev->irq);
2033
2034 /* Clear any lingering interrupt */
2035 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2036
2037 CHIPREG_READ32(&ioc->chip->IntStatus);
2038
2039 mpt_adapter_dispose(ioc);
2040
2041 pci_set_drvdata(pdev, NULL);
2042}
2043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044/**************************************************************************
2045 * Power Management
2046 */
2047#ifdef CONFIG_PM
2048/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002049/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002050 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002051 * @pdev: Pointer to pci_dev structure
2052 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002054int
2055mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056{
2057 u32 device_state;
2058 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302060 device_state = pci_choose_state(pdev, state);
2061 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2062 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2063 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064
2065 /* put ioc into READY_STATE */
2066 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2067 printk(MYIOC_s_ERR_FMT
2068 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2069 }
2070
2071 /* disable interrupts */
2072 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2073 ioc->active = 0;
2074
2075 /* Clear any lingering interrupt */
2076 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2077
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302078 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002079 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302080 pci_disable_msi(ioc->pcidev);
2081 ioc->pci_irq = -1;
2082 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302084 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 return 0;
2087}
2088
2089/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002090/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002091 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002092 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002094int
2095mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096{
2097 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2098 u32 device_state = pdev->current_state;
2099 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302100 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002101
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302102 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2103 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2104 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302106 pci_set_power_state(pdev, PCI_D0);
2107 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302109 ioc->pcidev = pdev;
2110 err = mpt_mapresources(ioc);
2111 if (err)
2112 return err;
2113
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302114 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2115 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2116 ioc->add_sge = &mpt_add_sge_64bit_1078;
2117 else
2118 ioc->add_sge = &mpt_add_sge_64bit;
2119 ioc->add_chain = &mpt_add_chain_64bit;
2120 ioc->sg_addr_size = 8;
2121 } else {
2122
2123 ioc->add_sge = &mpt_add_sge;
2124 ioc->add_chain = &mpt_add_chain;
2125 ioc->sg_addr_size = 4;
2126 }
2127 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2128
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302129 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2130 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2131 CHIPREG_READ32(&ioc->chip->Doorbell));
2132
2133 /*
2134 * Errata workaround for SAS pci express:
2135 * Upon returning to the D0 state, the contents of the doorbell will be
2136 * stale data, and this will incorrectly signal to the host driver that
2137 * the firmware is ready to process mpt commands. The workaround is
2138 * to issue a diagnostic reset.
2139 */
2140 if (ioc->bus_type == SAS && (pdev->device ==
2141 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2142 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2143 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2144 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2145 ioc->name);
2146 goto out;
2147 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
2150 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302151 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2152 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2153 CAN_SLEEP);
2154 if (recovery_state != 0)
2155 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2156 "error:[%x]\n", ioc->name, recovery_state);
2157 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302159 "pci-resume: success\n", ioc->name);
2160 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302162
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163}
2164#endif
2165
James Bottomley4ff42a62006-05-17 18:06:52 -05002166static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302167mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002168{
2169 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2170 ioc->bus_type != SPI) ||
2171 (MptDriverClass[index] == MPTFC_DRIVER &&
2172 ioc->bus_type != FC) ||
2173 (MptDriverClass[index] == MPTSAS_DRIVER &&
2174 ioc->bus_type != SAS))
2175 /* make sure we only call the relevant reset handler
2176 * for the bus */
2177 return 0;
2178 return (MptResetHandlers[index])(ioc, reset_phase);
2179}
2180
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002182/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2184 * @ioc: Pointer to MPT adapter structure
2185 * @reason: Event word / reason
2186 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2187 *
2188 * This routine performs all the steps necessary to bring the IOC
2189 * to a OPERATIONAL state.
2190 *
2191 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2192 * MPT adapter.
2193 *
2194 * Returns:
2195 * 0 for success
2196 * -1 if failed to get board READY
2197 * -2 if READY but IOCFacts Failed
2198 * -3 if READY but PrimeIOCFifos Failed
2199 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302200 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302201 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 */
2203static int
2204mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2205{
2206 int hard_reset_done = 0;
2207 int alt_ioc_ready = 0;
2208 int hard;
2209 int rc=0;
2210 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302211 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 int handlers;
2213 int ret = 0;
2214 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002215 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302216 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Eric Moore29dd3602007-09-14 18:46:51 -06002218 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2219 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220
2221 /* Disable reply interrupts (also blocks FreeQ) */
2222 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2223 ioc->active = 0;
2224
2225 if (ioc->alt_ioc) {
2226 if (ioc->alt_ioc->active)
2227 reset_alt_ioc_active = 1;
2228
2229 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2230 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2231 ioc->alt_ioc->active = 0;
2232 }
2233
2234 hard = 1;
2235 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2236 hard = 0;
2237
2238 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2239 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002240 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2241 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
2243 if (reset_alt_ioc_active && ioc->alt_ioc) {
2244 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002245 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2246 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002247 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 ioc->alt_ioc->active = 1;
2249 }
2250
2251 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002252 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 }
2254 return -1;
2255 }
2256
2257 /* hard_reset_done = 0 if a soft reset was performed
2258 * and 1 if a hard reset was performed.
2259 */
2260 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2261 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2262 alt_ioc_ready = 1;
2263 else
Eric Moore29dd3602007-09-14 18:46:51 -06002264 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 }
2266
2267 for (ii=0; ii<5; ii++) {
2268 /* Get IOC facts! Allow 5 retries */
2269 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2270 break;
2271 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002272
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273
2274 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002275 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2276 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 ret = -2;
2278 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2279 MptDisplayIocCapabilities(ioc);
2280 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002281
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 if (alt_ioc_ready) {
2283 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302284 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002285 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 /* Retry - alt IOC was initialized once
2287 */
2288 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2289 }
2290 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302291 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002292 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 alt_ioc_ready = 0;
2294 reset_alt_ioc_active = 0;
2295 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2296 MptDisplayIocCapabilities(ioc->alt_ioc);
2297 }
2298 }
2299
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302300 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2301 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2302 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2303 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2304 IORESOURCE_IO);
2305 if (pci_enable_device(ioc->pcidev))
2306 return -5;
2307 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2308 "mpt"))
2309 return -5;
2310 }
2311
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002312 /*
2313 * Device is reset now. It must have de-asserted the interrupt line
2314 * (if it was asserted) and it should be safe to register for the
2315 * interrupt now.
2316 */
2317 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2318 ioc->pci_irq = -1;
2319 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302320 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002321 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002322 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302323 else
2324 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002325 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002326 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002327 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002328 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002329 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302330 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002331 pci_disable_msi(ioc->pcidev);
2332 return -EBUSY;
2333 }
2334 irq_allocated = 1;
2335 ioc->pci_irq = ioc->pcidev->irq;
2336 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002337 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2338 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002339 }
2340 }
2341
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 /* Prime reply & request queues!
2343 * (mucho alloc's) Must be done prior to
2344 * init as upper addresses are needed for init.
2345 * If fails, continue with alt-ioc processing
2346 */
2347 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2348 ret = -3;
2349
2350 /* May need to check/upload firmware & data here!
2351 * If fails, continue with alt-ioc processing
2352 */
2353 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2354 ret = -4;
2355// NEW!
2356 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002357 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2358 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 alt_ioc_ready = 0;
2360 reset_alt_ioc_active = 0;
2361 }
2362
2363 if (alt_ioc_ready) {
2364 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2365 alt_ioc_ready = 0;
2366 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002367 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2368 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 }
2370 }
2371
2372 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2373 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302374 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002375 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
2377 /* Controller is not operational, cannot do upload
2378 */
2379 if (ret == 0) {
2380 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002381 if (rc == 0) {
2382 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2383 /*
2384 * Maintain only one pointer to FW memory
2385 * so there will not be two attempt to
2386 * downloadboot onboard dual function
2387 * chips (mpt_adapter_disable,
2388 * mpt_diag_reset)
2389 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302390 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002391 "mpt_upload: alt_%s has cached_fw=%p \n",
2392 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302393 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002394 }
2395 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002396 printk(MYIOC_s_WARN_FMT
2397 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302398 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 }
2401 }
2402 }
2403
Kashyap, Desaifd761752009-05-29 16:39:06 +05302404 /* Enable MPT base driver management of EventNotification
2405 * and EventAck handling.
2406 */
2407 if ((ret == 0) && (!ioc->facts.EventState)) {
2408 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2409 "SendEventNotification\n",
2410 ioc->name));
2411 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2412 }
2413
2414 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2415 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2416
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 if (ret == 0) {
2418 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002419 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 ioc->active = 1;
2421 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302422 if (rc == 0) { /* alt ioc */
2423 if (reset_alt_ioc_active && ioc->alt_ioc) {
2424 /* (re)Enable alt-IOC! (reply interrupt) */
2425 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2426 "reply irq re-enabled\n",
2427 ioc->alt_ioc->name));
2428 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2429 MPI_HIM_DIM);
2430 ioc->alt_ioc->active = 1;
2431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 }
2433
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002435 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2437 * recursive scenario; GetLanConfigPages times out, timer expired
2438 * routine calls HardResetHandler, which calls into here again,
2439 * and we try GetLanConfigPages again...
2440 */
2441 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002442
2443 /*
2444 * Initalize link list for inactive raid volumes.
2445 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002446 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002447 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2448
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002449 if (ioc->bus_type == SAS) {
2450
2451 /* clear persistency table */
2452 if(ioc->facts.IOCExceptions &
2453 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2454 ret = mptbase_sas_persist_operation(ioc,
2455 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2456 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002457 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002458 }
2459
2460 /* Find IM volumes
2461 */
2462 mpt_findImVolumes(ioc);
2463
2464 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2466 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2467 /*
2468 * Pre-fetch the ports LAN MAC address!
2469 * (LANPage1_t stuff)
2470 */
2471 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302472 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2473 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002474 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2475 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302476
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 }
2478 } else {
2479 /* Get NVRAM and adapter maximums from SPP 0 and 2
2480 */
2481 mpt_GetScsiPortSettings(ioc, 0);
2482
2483 /* Get version and length of SDP 1
2484 */
2485 mpt_readScsiDevicePageHeaders(ioc, 0);
2486
2487 /* Find IM volumes
2488 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002489 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 mpt_findImVolumes(ioc);
2491
2492 /* Check, and possibly reset, the coalescing value
2493 */
2494 mpt_read_ioc_pg_1(ioc);
2495
2496 mpt_read_ioc_pg_4(ioc);
2497 }
2498
2499 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302500 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 }
2502
2503 /*
2504 * Call each currently registered protocol IOC reset handler
2505 * with post-reset indication.
2506 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2507 * MptResetHandlers[] registered yet.
2508 */
2509 if (hard_reset_done) {
2510 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302511 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2512 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302513 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002514 "Calling IOC post_reset handler #%d\n",
2515 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302516 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 handlers++;
2518 }
2519
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302520 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302521 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002522 "Calling IOC post_reset handler #%d\n",
2523 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302524 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 handlers++;
2526 }
2527 }
2528 /* FIXME? Examine results here? */
2529 }
2530
Eric Moore0ccdb002006-07-11 17:33:13 -06002531 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002532 if ((ret != 0) && irq_allocated) {
2533 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302534 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002535 pci_disable_msi(ioc->pcidev);
2536 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 return ret;
2538}
2539
2540/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002541/**
2542 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 * @ioc: Pointer to MPT adapter structure
2544 * @pdev: Pointer to (struct pci_dev) structure
2545 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002546 * Search for PCI bus/dev_function which matches
2547 * PCI bus/dev_function (+/-1) for newly discovered 929,
2548 * 929X, 1030 or 1035.
2549 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2551 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2552 */
2553static void
2554mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2555{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002556 struct pci_dev *peer=NULL;
2557 unsigned int slot = PCI_SLOT(pdev->devfn);
2558 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 MPT_ADAPTER *ioc_srch;
2560
Prakash, Sathya436ace72007-07-24 15:42:08 +05302561 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002562 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002563 ioc->name, pci_name(pdev), pdev->bus->number,
2564 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002565
2566 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2567 if (!peer) {
2568 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2569 if (!peer)
2570 return;
2571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
2573 list_for_each_entry(ioc_srch, &ioc_list, list) {
2574 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002575 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 /* Paranoia checks */
2577 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002578 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002579 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 break;
2581 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002582 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002583 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 break;
2585 }
Eric Moore29dd3602007-09-14 18:46:51 -06002586 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002587 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 ioc_srch->alt_ioc = ioc;
2589 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 }
2591 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002592 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593}
2594
2595/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002596/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002598 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 */
2600static void
2601mpt_adapter_disable(MPT_ADAPTER *ioc)
2602{
2603 int sz;
2604 int ret;
2605
2606 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302607 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002608 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302609 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2610 ioc->cached_fw, CAN_SLEEP)) < 0) {
2611 printk(MYIOC_s_WARN_FMT
2612 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002613 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 }
2615 }
2616
2617 /* Disable adapter interrupts! */
2618 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2619 ioc->active = 0;
2620 /* Clear any lingering interrupt */
2621 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2622
2623 if (ioc->alloc != NULL) {
2624 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002625 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2626 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 pci_free_consistent(ioc->pcidev, sz,
2628 ioc->alloc, ioc->alloc_dma);
2629 ioc->reply_frames = NULL;
2630 ioc->req_frames = NULL;
2631 ioc->alloc = NULL;
2632 ioc->alloc_total -= sz;
2633 }
2634
2635 if (ioc->sense_buf_pool != NULL) {
2636 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2637 pci_free_consistent(ioc->pcidev, sz,
2638 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2639 ioc->sense_buf_pool = NULL;
2640 ioc->alloc_total -= sz;
2641 }
2642
2643 if (ioc->events != NULL){
2644 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2645 kfree(ioc->events);
2646 ioc->events = NULL;
2647 ioc->alloc_total -= sz;
2648 }
2649
Prakash, Sathya984621b2008-01-11 14:42:17 +05302650 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002652 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002653 mpt_inactive_raid_list_free(ioc);
2654 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002655 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002656 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002657 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658
2659 if (ioc->spi_data.pIocPg4 != NULL) {
2660 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302661 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 ioc->spi_data.pIocPg4,
2663 ioc->spi_data.IocPg4_dma);
2664 ioc->spi_data.pIocPg4 = NULL;
2665 ioc->alloc_total -= sz;
2666 }
2667
2668 if (ioc->ReqToChain != NULL) {
2669 kfree(ioc->ReqToChain);
2670 kfree(ioc->RequestNB);
2671 ioc->ReqToChain = NULL;
2672 }
2673
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002674 kfree(ioc->ChainToChain);
2675 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002676
2677 if (ioc->HostPageBuffer != NULL) {
2678 if((ret = mpt_host_page_access_control(ioc,
2679 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002680 printk(MYIOC_s_ERR_FMT
2681 "host page buffers free failed (%d)!\n",
2682 ioc->name, ret);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002683 }
Eric Moore29dd3602007-09-14 18:46:51 -06002684 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002685 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2686 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002687 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002688 ioc->HostPageBuffer = NULL;
2689 ioc->HostPageBuffer_sz = 0;
2690 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692}
2693
2694/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002695/**
2696 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 * @ioc: Pointer to MPT adapter structure
2698 *
2699 * This routine unregisters h/w resources and frees all alloc'd memory
2700 * associated with a MPT adapter structure.
2701 */
2702static void
2703mpt_adapter_dispose(MPT_ADAPTER *ioc)
2704{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002705 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002707 if (ioc == NULL)
2708 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002710 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002712 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002714 if (ioc->pci_irq != -1) {
2715 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302716 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002717 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002718 ioc->pci_irq = -1;
2719 }
2720
2721 if (ioc->memmap != NULL) {
2722 iounmap(ioc->memmap);
2723 ioc->memmap = NULL;
2724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302726 pci_disable_device(ioc->pcidev);
2727 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2728
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002730 if (ioc->mtrr_reg > 0) {
2731 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002732 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734#endif
2735
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002736 /* Zap the adapter lookup ptr! */
2737 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002739 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002740 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2741 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002742
2743 if (ioc->alt_ioc)
2744 ioc->alt_ioc->alt_ioc = NULL;
2745
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002746 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747}
2748
2749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002750/**
2751 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 * @ioc: Pointer to MPT adapter structure
2753 */
2754static void
2755MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2756{
2757 int i = 0;
2758
2759 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302760 if (ioc->prod_name)
2761 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 printk("Capabilities={");
2763
2764 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2765 printk("Initiator");
2766 i++;
2767 }
2768
2769 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2770 printk("%sTarget", i ? "," : "");
2771 i++;
2772 }
2773
2774 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2775 printk("%sLAN", i ? "," : "");
2776 i++;
2777 }
2778
2779#if 0
2780 /*
2781 * This would probably evoke more questions than it's worth
2782 */
2783 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2784 printk("%sLogBusAddr", i ? "," : "");
2785 i++;
2786 }
2787#endif
2788
2789 printk("}\n");
2790}
2791
2792/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002793/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2795 * @ioc: Pointer to MPT_ADAPTER structure
2796 * @force: Force hard KickStart of IOC
2797 * @sleepFlag: Specifies whether the process can sleep
2798 *
2799 * Returns:
2800 * 1 - DIAG reset and READY
2801 * 0 - READY initially OR soft reset and READY
2802 * -1 - Any failure on KickStart
2803 * -2 - Msg Unit Reset Failed
2804 * -3 - IO Unit Reset Failed
2805 * -4 - IOC owned by a PEER
2806 */
2807static int
2808MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2809{
2810 u32 ioc_state;
2811 int statefault = 0;
2812 int cntdn;
2813 int hard_reset_done = 0;
2814 int r;
2815 int ii;
2816 int whoinit;
2817
2818 /* Get current [raw] IOC state */
2819 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002820 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
2822 /*
2823 * Check to see if IOC got left/stuck in doorbell handshake
2824 * grip of death. If so, hard reset the IOC.
2825 */
2826 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2827 statefault = 1;
2828 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2829 ioc->name);
2830 }
2831
2832 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002833 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 return 0;
2835
2836 /*
2837 * Check to see if IOC is in FAULT state.
2838 */
2839 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2840 statefault = 2;
2841 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002842 ioc->name);
2843 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2844 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 }
2846
2847 /*
2848 * Hmmm... Did it get left operational?
2849 */
2850 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302851 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 ioc->name));
2853
2854 /* Check WhoInit.
2855 * If PCI Peer, exit.
2856 * Else, if no fault conditions are present, issue a MessageUnitReset
2857 * Else, fall through to KickStart case
2858 */
2859 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002860 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2861 "whoinit 0x%x statefault %d force %d\n",
2862 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 if (whoinit == MPI_WHOINIT_PCI_PEER)
2864 return -4;
2865 else {
2866 if ((statefault == 0 ) && (force == 0)) {
2867 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2868 return 0;
2869 }
2870 statefault = 3;
2871 }
2872 }
2873
2874 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2875 if (hard_reset_done < 0)
2876 return -1;
2877
2878 /*
2879 * Loop here waiting for IOC to come READY.
2880 */
2881 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002882 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
2884 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2885 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2886 /*
2887 * BIOS or previous driver load left IOC in OP state.
2888 * Reset messaging FIFOs.
2889 */
2890 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2891 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2892 return -2;
2893 }
2894 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2895 /*
2896 * Something is wrong. Try to get IOC back
2897 * to a known state.
2898 */
2899 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2900 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2901 return -3;
2902 }
2903 }
2904
2905 ii++; cntdn--;
2906 if (!cntdn) {
2907 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2908 ioc->name, (int)((ii+5)/HZ));
2909 return -ETIME;
2910 }
2911
2912 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002913 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 } else {
2915 mdelay (1); /* 1 msec delay */
2916 }
2917
2918 }
2919
2920 if (statefault < 3) {
2921 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2922 ioc->name,
2923 statefault==1 ? "stuck handshake" : "IOC FAULT");
2924 }
2925
2926 return hard_reset_done;
2927}
2928
2929/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002930/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 * mpt_GetIocState - Get the current state of a MPT adapter.
2932 * @ioc: Pointer to MPT_ADAPTER structure
2933 * @cooked: Request raw or cooked IOC state
2934 *
2935 * Returns all IOC Doorbell register bits if cooked==0, else just the
2936 * Doorbell bits in MPI_IOC_STATE_MASK.
2937 */
2938u32
2939mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2940{
2941 u32 s, sc;
2942
2943 /* Get! */
2944 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 sc = s & MPI_IOC_STATE_MASK;
2946
2947 /* Save! */
2948 ioc->last_state = sc;
2949
2950 return cooked ? sc : s;
2951}
2952
2953/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002954/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 * GetIocFacts - Send IOCFacts request to MPT adapter.
2956 * @ioc: Pointer to MPT_ADAPTER structure
2957 * @sleepFlag: Specifies whether the process can sleep
2958 * @reason: If recovery, only update facts.
2959 *
2960 * Returns 0 for success, non-zero for failure.
2961 */
2962static int
2963GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2964{
2965 IOCFacts_t get_facts;
2966 IOCFactsReply_t *facts;
2967 int r;
2968 int req_sz;
2969 int reply_sz;
2970 int sz;
2971 u32 status, vv;
2972 u8 shiftFactor=1;
2973
2974 /* IOC *must* NOT be in RESET state! */
2975 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002976 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2977 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 return -44;
2979 }
2980
2981 facts = &ioc->facts;
2982
2983 /* Destination (reply area)... */
2984 reply_sz = sizeof(*facts);
2985 memset(facts, 0, reply_sz);
2986
2987 /* Request area (get_facts on the stack right now!) */
2988 req_sz = sizeof(get_facts);
2989 memset(&get_facts, 0, req_sz);
2990
2991 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2992 /* Assert: All other get_facts fields are zero! */
2993
Prakash, Sathya436ace72007-07-24 15:42:08 +05302994 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002995 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 ioc->name, req_sz, reply_sz));
2997
2998 /* No non-zero fields in the get_facts request are greater than
2999 * 1 byte in size, so we can just fire it off as is.
3000 */
3001 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3002 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3003 if (r != 0)
3004 return r;
3005
3006 /*
3007 * Now byte swap (GRRR) the necessary fields before any further
3008 * inspection of reply contents.
3009 *
3010 * But need to do some sanity checks on MsgLength (byte) field
3011 * to make sure we don't zero IOC's req_sz!
3012 */
3013 /* Did we get a valid reply? */
3014 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3015 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3016 /*
3017 * If not been here, done that, save off first WhoInit value
3018 */
3019 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3020 ioc->FirstWhoInit = facts->WhoInit;
3021 }
3022
3023 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3024 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3025 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3026 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3027 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003028 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 /* CHECKME! IOCStatus, IOCLogInfo */
3030
3031 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3032 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3033
3034 /*
3035 * FC f/w version changed between 1.1 and 1.2
3036 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3037 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3038 */
3039 if (facts->MsgVersion < 0x0102) {
3040 /*
3041 * Handle old FC f/w style, convert to new...
3042 */
3043 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3044 facts->FWVersion.Word =
3045 ((oldv<<12) & 0xFF000000) |
3046 ((oldv<<8) & 0x000FFF00);
3047 } else
3048 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3049
3050 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07003051 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3052 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3053 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 facts->CurrentHostMfaHighAddr =
3055 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3056 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3057 facts->CurrentSenseBufferHighAddr =
3058 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3059 facts->CurReplyFrameSize =
3060 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003061 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
3063 /*
3064 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3065 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3066 * to 14 in MPI-1.01.0x.
3067 */
3068 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
3069 facts->MsgVersion > 0x0100) {
3070 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3071 }
3072
3073 sz = facts->FWImageSize;
3074 if ( sz & 0x01 )
3075 sz += 1;
3076 if ( sz & 0x02 )
3077 sz += 2;
3078 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003079
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 if (!facts->RequestFrameSize) {
3081 /* Something is wrong! */
3082 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3083 ioc->name);
3084 return -55;
3085 }
3086
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003087 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 vv = ((63 / (sz * 4)) + 1) & 0x03;
3089 ioc->NB_for_64_byte_frame = vv;
3090 while ( sz )
3091 {
3092 shiftFactor++;
3093 sz = sz >> 1;
3094 }
3095 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303096 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003097 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3098 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003099
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3101 /*
3102 * Set values for this IOC's request & reply frame sizes,
3103 * and request & reply queue depths...
3104 */
3105 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3106 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3107 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3108 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3109
Prakash, Sathya436ace72007-07-24 15:42:08 +05303110 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303112 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 ioc->name, ioc->req_sz, ioc->req_depth));
3114
3115 /* Get port facts! */
3116 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3117 return r;
3118 }
3119 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003120 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3122 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3123 RequestFrameSize)/sizeof(u32)));
3124 return -66;
3125 }
3126
3127 return 0;
3128}
3129
3130/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003131/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 * GetPortFacts - Send PortFacts request to MPT adapter.
3133 * @ioc: Pointer to MPT_ADAPTER structure
3134 * @portnum: Port number
3135 * @sleepFlag: Specifies whether the process can sleep
3136 *
3137 * Returns 0 for success, non-zero for failure.
3138 */
3139static int
3140GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3141{
3142 PortFacts_t get_pfacts;
3143 PortFactsReply_t *pfacts;
3144 int ii;
3145 int req_sz;
3146 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003147 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148
3149 /* IOC *must* NOT be in RESET state! */
3150 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003151 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3152 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 return -4;
3154 }
3155
3156 pfacts = &ioc->pfacts[portnum];
3157
3158 /* Destination (reply area)... */
3159 reply_sz = sizeof(*pfacts);
3160 memset(pfacts, 0, reply_sz);
3161
3162 /* Request area (get_pfacts on the stack right now!) */
3163 req_sz = sizeof(get_pfacts);
3164 memset(&get_pfacts, 0, req_sz);
3165
3166 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3167 get_pfacts.PortNumber = portnum;
3168 /* Assert: All other get_pfacts fields are zero! */
3169
Prakash, Sathya436ace72007-07-24 15:42:08 +05303170 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 ioc->name, portnum));
3172
3173 /* No non-zero fields in the get_pfacts request are greater than
3174 * 1 byte in size, so we can just fire it off as is.
3175 */
3176 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3177 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3178 if (ii != 0)
3179 return ii;
3180
3181 /* Did we get a valid reply? */
3182
3183 /* Now byte swap the necessary fields in the response. */
3184 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3185 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3186 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3187 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3188 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3189 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3190 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3191 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3192 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3193
Eric Moore793955f2007-01-29 09:42:20 -07003194 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3195 pfacts->MaxDevices;
3196 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3197 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3198
3199 /*
3200 * Place all the devices on channels
3201 *
3202 * (for debuging)
3203 */
3204 if (mpt_channel_mapping) {
3205 ioc->devices_per_bus = 1;
3206 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3207 }
3208
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 return 0;
3210}
3211
3212/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003213/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 * SendIocInit - Send IOCInit request to MPT adapter.
3215 * @ioc: Pointer to MPT_ADAPTER structure
3216 * @sleepFlag: Specifies whether the process can sleep
3217 *
3218 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3219 *
3220 * Returns 0 for success, non-zero for failure.
3221 */
3222static int
3223SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3224{
3225 IOCInit_t ioc_init;
3226 MPIDefaultReply_t init_reply;
3227 u32 state;
3228 int r;
3229 int count;
3230 int cntdn;
3231
3232 memset(&ioc_init, 0, sizeof(ioc_init));
3233 memset(&init_reply, 0, sizeof(init_reply));
3234
3235 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3236 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3237
3238 /* If we are in a recovery mode and we uploaded the FW image,
3239 * then this pointer is not NULL. Skip the upload a second time.
3240 * Set this flag if cached_fw set for either IOC.
3241 */
3242 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3243 ioc->upload_fw = 1;
3244 else
3245 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303246 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3248
Eric Moore793955f2007-01-29 09:42:20 -07003249 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3250 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303251 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003252 ioc->name, ioc->facts.MsgVersion));
3253 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3254 // set MsgVersion and HeaderVersion host driver was built with
3255 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3256 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003258 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3259 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3260 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3261 return -99;
3262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3264
3265 if (sizeof(dma_addr_t) == sizeof(u64)) {
3266 /* Save the upper 32-bits of the request
3267 * (reply) and sense buffers.
3268 */
3269 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3270 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3271 } else {
3272 /* Force 32-bit addressing */
3273 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3274 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3275 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003276
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3278 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003279 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3280 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281
Prakash, Sathya436ace72007-07-24 15:42:08 +05303282 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 ioc->name, &ioc_init));
3284
3285 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3286 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003287 if (r != 0) {
3288 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291
3292 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003293 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 */
3295
Prakash, Sathya436ace72007-07-24 15:42:08 +05303296 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003298
3299 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3300 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303
3304 /* YIKES! SUPER IMPORTANT!!!
3305 * Poll IocState until _OPERATIONAL while IOC is doing
3306 * LoopInit and TargetDiscovery!
3307 */
3308 count = 0;
3309 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3310 state = mpt_GetIocState(ioc, 1);
3311 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3312 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003313 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 } else {
3315 mdelay(1);
3316 }
3317
3318 if (!cntdn) {
3319 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3320 ioc->name, (int)((count+5)/HZ));
3321 return -9;
3322 }
3323
3324 state = mpt_GetIocState(ioc, 1);
3325 count++;
3326 }
Eric Moore29dd3602007-09-14 18:46:51 -06003327 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 ioc->name, count));
3329
Eric Mooreba856d32006-07-11 17:34:01 -06003330 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 return r;
3332}
3333
3334/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003335/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 * SendPortEnable - Send PortEnable request to MPT adapter port.
3337 * @ioc: Pointer to MPT_ADAPTER structure
3338 * @portnum: Port number to enable
3339 * @sleepFlag: Specifies whether the process can sleep
3340 *
3341 * Send PortEnable to bring IOC to OPERATIONAL state.
3342 *
3343 * Returns 0 for success, non-zero for failure.
3344 */
3345static int
3346SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3347{
3348 PortEnable_t port_enable;
3349 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003350 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 int req_sz;
3352 int reply_sz;
3353
3354 /* Destination... */
3355 reply_sz = sizeof(MPIDefaultReply_t);
3356 memset(&reply_buf, 0, reply_sz);
3357
3358 req_sz = sizeof(PortEnable_t);
3359 memset(&port_enable, 0, req_sz);
3360
3361 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3362 port_enable.PortNumber = portnum;
3363/* port_enable.ChainOffset = 0; */
3364/* port_enable.MsgFlags = 0; */
3365/* port_enable.MsgContext = 0; */
3366
Prakash, Sathya436ace72007-07-24 15:42:08 +05303367 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 ioc->name, portnum, &port_enable));
3369
3370 /* RAID FW may take a long time to enable
3371 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003372 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003373 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3374 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3375 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003376 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003377 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3378 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3379 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003381 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382}
3383
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003384/**
3385 * mpt_alloc_fw_memory - allocate firmware memory
3386 * @ioc: Pointer to MPT_ADAPTER structure
3387 * @size: total FW bytes
3388 *
3389 * If memory has already been allocated, the same (cached) value
3390 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303391 *
3392 * Return 0 if successfull, or non-zero for failure
3393 **/
3394int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3396{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303397 int rc;
3398
3399 if (ioc->cached_fw) {
3400 rc = 0; /* use already allocated memory */
3401 goto out;
3402 }
3403 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3405 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303406 rc = 0;
3407 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303409 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3410 if (!ioc->cached_fw) {
3411 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3412 ioc->name);
3413 rc = -1;
3414 } else {
3415 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3416 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3417 ioc->alloc_total += size;
3418 rc = 0;
3419 }
3420 out:
3421 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303423
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003424/**
3425 * mpt_free_fw_memory - free firmware memory
3426 * @ioc: Pointer to MPT_ADAPTER structure
3427 *
3428 * If alt_img is NULL, delete from ioc structure.
3429 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303430 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431void
3432mpt_free_fw_memory(MPT_ADAPTER *ioc)
3433{
3434 int sz;
3435
Prakash, Sathya984621b2008-01-11 14:42:17 +05303436 if (!ioc->cached_fw)
3437 return;
3438
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303440 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3441 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003442 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303443 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445}
3446
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003448/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3450 * @ioc: Pointer to MPT_ADAPTER structure
3451 * @sleepFlag: Specifies whether the process can sleep
3452 *
3453 * Returns 0 for success, >0 for handshake failure
3454 * <0 for fw upload failure.
3455 *
3456 * Remark: If bound IOC and a successful FWUpload was performed
3457 * on the bound IOC, the second image is discarded
3458 * and memory is free'd. Both channels must upload to prevent
3459 * IOC from running in degraded mode.
3460 */
3461static int
3462mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3463{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 u8 reply[sizeof(FWUploadReply_t)];
3465 FWUpload_t *prequest;
3466 FWUploadReply_t *preply;
3467 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 u32 flagsLength;
3469 int ii, sz, reply_sz;
3470 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303471 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 /* If the image size is 0, we are done.
3473 */
3474 if ((sz = ioc->facts.FWImageSize) == 0)
3475 return 0;
3476
Prakash, Sathya984621b2008-01-11 14:42:17 +05303477 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3478 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479
Eric Moore29dd3602007-09-14 18:46:51 -06003480 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3481 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003482
Eric Moorebc6e0892007-09-29 10:16:28 -06003483 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3484 kzalloc(ioc->req_sz, GFP_KERNEL);
3485 if (!prequest) {
3486 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3487 "while allocating memory \n", ioc->name));
3488 mpt_free_fw_memory(ioc);
3489 return -ENOMEM;
3490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
Eric Moorebc6e0892007-09-29 10:16:28 -06003492 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
3494 reply_sz = sizeof(reply);
3495 memset(preply, 0, reply_sz);
3496
3497 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3498 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3499
3500 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3501 ptcsge->DetailsLength = 12;
3502 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3503 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003504 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303507 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3508 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3509 ioc->SGE_size;
3510 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3511 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3512 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003513 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303515 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3516 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
Eric Moore29dd3602007-09-14 18:46:51 -06003518 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519
3520 cmdStatus = -EFAULT;
3521 if (ii == 0) {
3522 /* Handshake transfer was complete and successful.
3523 * Check the Reply Frame.
3524 */
3525 int status, transfer_sz;
3526 status = le16_to_cpu(preply->IOCStatus);
3527 if (status == MPI_IOCSTATUS_SUCCESS) {
3528 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3529 if (transfer_sz == sz)
3530 cmdStatus = 0;
3531 }
3532 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303533 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 ioc->name, cmdStatus));
3535
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003536
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 if (cmdStatus) {
3538
Prakash, Sathya436ace72007-07-24 15:42:08 +05303539 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 ioc->name));
3541 mpt_free_fw_memory(ioc);
3542 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003543 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544
3545 return cmdStatus;
3546}
3547
3548/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003549/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 * mpt_downloadboot - DownloadBoot code
3551 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003552 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 * @sleepFlag: Specifies whether the process can sleep
3554 *
3555 * FwDownloadBoot requires Programmed IO access.
3556 *
3557 * Returns 0 for success
3558 * -1 FW Image size is 0
3559 * -2 No valid cached_fw Pointer
3560 * <0 for fw upload failure.
3561 */
3562static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003563mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 MpiExtImageHeader_t *pExtImage;
3566 u32 fwSize;
3567 u32 diag0val;
3568 int count;
3569 u32 *ptrFw;
3570 u32 diagRwData;
3571 u32 nextImage;
3572 u32 load_addr;
3573 u32 ioc_state=0;
3574
Prakash, Sathya436ace72007-07-24 15:42:08 +05303575 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003576 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003577
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3579 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3580 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3581 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3582 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3583 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3584
3585 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3586
3587 /* wait 1 msec */
3588 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003589 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 } else {
3591 mdelay (1);
3592 }
3593
3594 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3595 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3596
3597 for (count = 0; count < 30; count ++) {
3598 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3599 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303600 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 ioc->name, count));
3602 break;
3603 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003604 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003606 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003608 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 }
3610 }
3611
3612 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303613 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003614 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 ioc->name, diag0val));
3616 return -3;
3617 }
3618
3619 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3620 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3621 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3622 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3623 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3624 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3625
3626 /* Set the DiagRwEn and Disable ARM bits */
3627 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3628
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 fwSize = (pFwHeader->ImageSize + 3)/4;
3630 ptrFw = (u32 *) pFwHeader;
3631
3632 /* Write the LoadStartAddress to the DiagRw Address Register
3633 * using Programmed IO
3634 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003635 if (ioc->errata_flag_1064)
3636 pci_enable_io_access(ioc->pcidev);
3637
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303639 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 ioc->name, pFwHeader->LoadStartAddress));
3641
Prakash, Sathya436ace72007-07-24 15:42:08 +05303642 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 ioc->name, fwSize*4, ptrFw));
3644 while (fwSize--) {
3645 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3646 }
3647
3648 nextImage = pFwHeader->NextImageHeaderOffset;
3649 while (nextImage) {
3650 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3651
3652 load_addr = pExtImage->LoadStartAddress;
3653
3654 fwSize = (pExtImage->ImageSize + 3) >> 2;
3655 ptrFw = (u32 *)pExtImage;
3656
Prakash, Sathya436ace72007-07-24 15:42:08 +05303657 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 +02003658 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3660
3661 while (fwSize--) {
3662 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3663 }
3664 nextImage = pExtImage->NextImageHeaderOffset;
3665 }
3666
3667 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303668 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3670
3671 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303672 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3674
3675 /* Clear the internal flash bad bit - autoincrementing register,
3676 * so must do two writes.
3677 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003678 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003679 /*
3680 * 1030 and 1035 H/W errata, workaround to access
3681 * the ClearFlashBadSignatureBit
3682 */
3683 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3684 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3685 diagRwData |= 0x40000000;
3686 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3687 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3688
3689 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3690 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3691 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3692 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3693
3694 /* wait 1 msec */
3695 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003696 msleep (1);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003697 } else {
3698 mdelay (1);
3699 }
3700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003702 if (ioc->errata_flag_1064)
3703 pci_disable_io_access(ioc->pcidev);
3704
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303706 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003707 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003709 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303710 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 ioc->name, diag0val));
3712 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3713
3714 /* Write 0xFF to reset the sequencer */
3715 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3716
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003717 if (ioc->bus_type == SAS) {
3718 ioc_state = mpt_GetIocState(ioc, 0);
3719 if ( (GetIocFacts(ioc, sleepFlag,
3720 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303721 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003722 ioc->name, ioc_state));
3723 return -EFAULT;
3724 }
3725 }
3726
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 for (count=0; count<HZ*20; count++) {
3728 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303729 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3730 "downloadboot successful! (count=%d) IocState=%x\n",
3731 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003732 if (ioc->bus_type == SAS) {
3733 return 0;
3734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303736 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3737 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 ioc->name));
3739 return -EFAULT;
3740 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303741 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3742 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 ioc->name));
3744 return 0;
3745 }
3746 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003747 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 } else {
3749 mdelay (10);
3750 }
3751 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303752 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3753 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 return -EFAULT;
3755}
3756
3757/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003758/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 * KickStart - Perform hard reset of MPT adapter.
3760 * @ioc: Pointer to MPT_ADAPTER structure
3761 * @force: Force hard reset
3762 * @sleepFlag: Specifies whether the process can sleep
3763 *
3764 * This routine places MPT adapter in diagnostic mode via the
3765 * WriteSequence register, and then performs a hard reset of adapter
3766 * via the Diagnostic register.
3767 *
3768 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3769 * or NO_SLEEP (interrupt thread, use mdelay)
3770 * force - 1 if doorbell active, board fault state
3771 * board operational, IOC_RECOVERY or
3772 * IOC_BRINGUP and there is an alt_ioc.
3773 * 0 else
3774 *
3775 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003776 * 1 - hard reset, READY
3777 * 0 - no reset due to History bit, READY
3778 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 * OR reset but failed to come READY
3780 * -2 - no reset, could not enter DIAG mode
3781 * -3 - reset but bad FW bit
3782 */
3783static int
3784KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3785{
3786 int hard_reset_done = 0;
3787 u32 ioc_state=0;
3788 int cnt,cntdn;
3789
Eric Moore29dd3602007-09-14 18:46:51 -06003790 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003791 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 /* Always issue a Msg Unit Reset first. This will clear some
3793 * SCSI bus hang conditions.
3794 */
3795 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3796
3797 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003798 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 } else {
3800 mdelay (1000);
3801 }
3802 }
3803
3804 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3805 if (hard_reset_done < 0)
3806 return hard_reset_done;
3807
Prakash, Sathya436ace72007-07-24 15:42:08 +05303808 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003809 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
3811 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3812 for (cnt=0; cnt<cntdn; cnt++) {
3813 ioc_state = mpt_GetIocState(ioc, 1);
3814 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303815 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 ioc->name, cnt));
3817 return hard_reset_done;
3818 }
3819 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003820 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 } else {
3822 mdelay (10);
3823 }
3824 }
3825
Eric Moore29dd3602007-09-14 18:46:51 -06003826 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3827 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 return -1;
3829}
3830
3831/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003832/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 * mpt_diag_reset - Perform hard reset of the adapter.
3834 * @ioc: Pointer to MPT_ADAPTER structure
3835 * @ignore: Set if to honor and clear to ignore
3836 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003837 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 * else set to NO_SLEEP (use mdelay instead)
3839 *
3840 * This routine places the adapter in diagnostic mode via the
3841 * WriteSequence register and then performs a hard reset of adapter
3842 * via the Diagnostic register. Adapter should be in ready state
3843 * upon successful completion.
3844 *
3845 * Returns: 1 hard reset successful
3846 * 0 no reset performed because reset history bit set
3847 * -2 enabling diagnostic mode failed
3848 * -3 diagnostic reset failed
3849 */
3850static int
3851mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3852{
3853 u32 diag0val;
3854 u32 doorbell;
3855 int hard_reset_done = 0;
3856 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303858 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859
Eric Moorecd2c6192007-01-29 09:47:47 -07003860 /* Clear any existing interrupts */
3861 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3862
Eric Moore87cf8982006-06-27 16:09:26 -06003863 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303864 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003865 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003866 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3867 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3868 if (sleepFlag == CAN_SLEEP)
3869 msleep(1);
3870 else
3871 mdelay(1);
3872
3873 for (count = 0; count < 60; count ++) {
3874 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3875 doorbell &= MPI_IOC_STATE_MASK;
3876
Prakash, Sathya436ace72007-07-24 15:42:08 +05303877 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003878 "looking for READY STATE: doorbell=%x"
3879 " count=%d\n",
3880 ioc->name, doorbell, count));
3881 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003882 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003883 }
3884
3885 /* wait 1 sec */
3886 if (sleepFlag == CAN_SLEEP)
3887 msleep(1000);
3888 else
3889 mdelay(1000);
3890 }
3891 return -1;
3892 }
3893
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 /* Use "Diagnostic reset" method! (only thing available!) */
3895 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3896
Prakash, Sathya436ace72007-07-24 15:42:08 +05303897 if (ioc->debug_level & MPT_DEBUG) {
3898 if (ioc->alt_ioc)
3899 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3900 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903
3904 /* Do the reset if we are told to ignore the reset history
3905 * or if the reset history is 0
3906 */
3907 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3908 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3909 /* Write magic sequence to WriteSequence register
3910 * Loop until in diagnostic mode
3911 */
3912 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3913 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3914 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3915 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3916 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3917 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3918
3919 /* wait 100 msec */
3920 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003921 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 } else {
3923 mdelay (100);
3924 }
3925
3926 count++;
3927 if (count > 20) {
3928 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3929 ioc->name, diag0val);
3930 return -2;
3931
3932 }
3933
3934 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3935
Prakash, Sathya436ace72007-07-24 15:42:08 +05303936 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 ioc->name, diag0val));
3938 }
3939
Prakash, Sathya436ace72007-07-24 15:42:08 +05303940 if (ioc->debug_level & MPT_DEBUG) {
3941 if (ioc->alt_ioc)
3942 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3943 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 /*
3947 * Disable the ARM (Bug fix)
3948 *
3949 */
3950 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003951 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952
3953 /*
3954 * Now hit the reset bit in the Diagnostic register
3955 * (THE BIG HAMMER!) (Clears DRWE bit).
3956 */
3957 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3958 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303959 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 ioc->name));
3961
3962 /*
3963 * Call each currently registered protocol IOC reset handler
3964 * with pre-reset indication.
3965 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3966 * MptResetHandlers[] registered yet.
3967 */
3968 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303969 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 int r = 0;
3971
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303972 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3973 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303974 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3975 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303976 ioc->name, cb_idx));
3977 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303979 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3980 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303981 ioc->name, ioc->alt_ioc->name, cb_idx));
3982 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 }
3984 }
3985 }
3986 /* FIXME? Examine results here? */
3987 }
3988
Eric Moore0ccdb002006-07-11 17:33:13 -06003989 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303990 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003991 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303992 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3993 else
3994 cached_fw = NULL;
3995 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 /* If the DownloadBoot operation fails, the
3997 * IOC will be left unusable. This is a fatal error
3998 * case. _diag_reset will return < 0
3999 */
4000 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304001 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4003 break;
4004 }
4005
Prakash, Sathya436ace72007-07-24 15:42:08 +05304006 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304007 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 /* wait 1 sec */
4009 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004010 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 } else {
4012 mdelay (1000);
4013 }
4014 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304015 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004016 printk(MYIOC_s_WARN_FMT
4017 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 }
4019
4020 } else {
4021 /* Wait for FW to reload and for board
4022 * to go to the READY state.
4023 * Maximum wait is 60 seconds.
4024 * If fail, no error will check again
4025 * with calling program.
4026 */
4027 for (count = 0; count < 60; count ++) {
4028 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4029 doorbell &= MPI_IOC_STATE_MASK;
4030
4031 if (doorbell == MPI_IOC_STATE_READY) {
4032 break;
4033 }
4034
4035 /* wait 1 sec */
4036 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004037 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 } else {
4039 mdelay (1000);
4040 }
4041 }
4042 }
4043 }
4044
4045 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304046 if (ioc->debug_level & MPT_DEBUG) {
4047 if (ioc->alt_ioc)
4048 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4049 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4050 ioc->name, diag0val, diag1val));
4051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052
4053 /* Clear RESET_HISTORY bit! Place board in the
4054 * diagnostic mode to update the diag register.
4055 */
4056 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4057 count = 0;
4058 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4059 /* Write magic sequence to WriteSequence register
4060 * Loop until in diagnostic mode
4061 */
4062 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4063 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4064 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4065 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4066 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4067 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4068
4069 /* wait 100 msec */
4070 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004071 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 } else {
4073 mdelay (100);
4074 }
4075
4076 count++;
4077 if (count > 20) {
4078 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4079 ioc->name, diag0val);
4080 break;
4081 }
4082 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4083 }
4084 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4085 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4086 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4087 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4088 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4089 ioc->name);
4090 }
4091
4092 /* Disable Diagnostic Mode
4093 */
4094 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4095
4096 /* Check FW reload status flags.
4097 */
4098 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4099 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4100 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4101 ioc->name, diag0val);
4102 return -3;
4103 }
4104
Prakash, Sathya436ace72007-07-24 15:42:08 +05304105 if (ioc->debug_level & MPT_DEBUG) {
4106 if (ioc->alt_ioc)
4107 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4108 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
4112 /*
4113 * Reset flag that says we've enabled event notification
4114 */
4115 ioc->facts.EventState = 0;
4116
4117 if (ioc->alt_ioc)
4118 ioc->alt_ioc->facts.EventState = 0;
4119
4120 return hard_reset_done;
4121}
4122
4123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004124/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 * SendIocReset - Send IOCReset request to MPT adapter.
4126 * @ioc: Pointer to MPT_ADAPTER structure
4127 * @reset_type: reset type, expected values are
4128 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004129 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 *
4131 * Send IOCReset request to the MPT adapter.
4132 *
4133 * Returns 0 for success, non-zero for failure.
4134 */
4135static int
4136SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4137{
4138 int r;
4139 u32 state;
4140 int cntdn, count;
4141
Prakash, Sathya436ace72007-07-24 15:42:08 +05304142 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 ioc->name, reset_type));
4144 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4145 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4146 return r;
4147
4148 /* FW ACK'd request, wait for READY state
4149 */
4150 count = 0;
4151 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4152
4153 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4154 cntdn--;
4155 count++;
4156 if (!cntdn) {
4157 if (sleepFlag != CAN_SLEEP)
4158 count *= 10;
4159
Eric Moore29dd3602007-09-14 18:46:51 -06004160 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
4161 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 return -ETIME;
4163 }
4164
4165 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004166 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 } else {
4168 mdelay (1); /* 1 msec delay */
4169 }
4170 }
4171
4172 /* TODO!
4173 * Cleanup all event stuff for this IOC; re-issue EventNotification
4174 * request if needed.
4175 */
4176 if (ioc->facts.Function)
4177 ioc->facts.EventState = 0;
4178
4179 return 0;
4180}
4181
4182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004183/**
4184 * initChainBuffers - Allocate memory for and initialize chain buffers
4185 * @ioc: Pointer to MPT_ADAPTER structure
4186 *
4187 * Allocates memory for and initializes chain buffers,
4188 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 */
4190static int
4191initChainBuffers(MPT_ADAPTER *ioc)
4192{
4193 u8 *mem;
4194 int sz, ii, num_chain;
4195 int scale, num_sge, numSGE;
4196
4197 /* ReqToChain size must equal the req_depth
4198 * index = req_idx
4199 */
4200 if (ioc->ReqToChain == NULL) {
4201 sz = ioc->req_depth * sizeof(int);
4202 mem = kmalloc(sz, GFP_ATOMIC);
4203 if (mem == NULL)
4204 return -1;
4205
4206 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304207 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 ioc->name, mem, sz));
4209 mem = kmalloc(sz, GFP_ATOMIC);
4210 if (mem == NULL)
4211 return -1;
4212
4213 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304214 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 ioc->name, mem, sz));
4216 }
4217 for (ii = 0; ii < ioc->req_depth; ii++) {
4218 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4219 }
4220
4221 /* ChainToChain size must equal the total number
4222 * of chain buffers to be allocated.
4223 * index = chain_idx
4224 *
4225 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004226 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 *
4228 * num_sge = num sge in request frame + last chain buffer
4229 * scale = num sge per chain buffer if no chain element
4230 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304231 scale = ioc->req_sz / ioc->SGE_size;
4232 if (ioc->sg_addr_size == sizeof(u64))
4233 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304235 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304237 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304239 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304241 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4242 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304244 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 ioc->name, num_sge, numSGE));
4246
4247 if ( numSGE > MPT_SCSI_SG_DEPTH )
4248 numSGE = MPT_SCSI_SG_DEPTH;
4249
4250 num_chain = 1;
4251 while (numSGE - num_sge > 0) {
4252 num_chain++;
4253 num_sge += (scale - 1);
4254 }
4255 num_chain++;
4256
Prakash, Sathya436ace72007-07-24 15:42:08 +05304257 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 ioc->name, numSGE, num_sge, num_chain));
4259
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004260 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 num_chain *= MPT_SCSI_CAN_QUEUE;
4262 else
4263 num_chain *= MPT_FC_CAN_QUEUE;
4264
4265 ioc->num_chain = num_chain;
4266
4267 sz = num_chain * sizeof(int);
4268 if (ioc->ChainToChain == NULL) {
4269 mem = kmalloc(sz, GFP_ATOMIC);
4270 if (mem == NULL)
4271 return -1;
4272
4273 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304274 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 ioc->name, mem, sz));
4276 } else {
4277 mem = (u8 *) ioc->ChainToChain;
4278 }
4279 memset(mem, 0xFF, sz);
4280 return num_chain;
4281}
4282
4283/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004284/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4286 * @ioc: Pointer to MPT_ADAPTER structure
4287 *
4288 * This routine allocates memory for the MPT reply and request frame
4289 * pools (if necessary), and primes the IOC reply FIFO with
4290 * reply frames.
4291 *
4292 * Returns 0 for success, non-zero for failure.
4293 */
4294static int
4295PrimeIocFifos(MPT_ADAPTER *ioc)
4296{
4297 MPT_FRAME_HDR *mf;
4298 unsigned long flags;
4299 dma_addr_t alloc_dma;
4300 u8 *mem;
4301 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304302 u64 dma_mask;
4303
4304 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305
4306 /* Prime reply FIFO... */
4307
4308 if (ioc->reply_frames == NULL) {
4309 if ( (num_chain = initChainBuffers(ioc)) < 0)
4310 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304311 /*
4312 * 1078 errata workaround for the 36GB limitation
4313 */
4314 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4315 ioc->dma_mask > DMA_35BIT_MASK) {
4316 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4317 && !pci_set_consistent_dma_mask(ioc->pcidev,
4318 DMA_BIT_MASK(32))) {
4319 dma_mask = DMA_35BIT_MASK;
4320 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4321 "setting 35 bit addressing for "
4322 "Request/Reply/Chain and Sense Buffers\n",
4323 ioc->name));
4324 } else {
4325 /*Reseting DMA mask to 64 bit*/
4326 pci_set_dma_mask(ioc->pcidev,
4327 DMA_BIT_MASK(64));
4328 pci_set_consistent_dma_mask(ioc->pcidev,
4329 DMA_BIT_MASK(64));
4330
4331 printk(MYIOC_s_ERR_FMT
4332 "failed setting 35 bit addressing for "
4333 "Request/Reply/Chain and Sense Buffers\n",
4334 ioc->name);
4335 return -1;
4336 }
4337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
4339 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304340 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304342 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 ioc->name, reply_sz, reply_sz));
4344
4345 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304346 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304348 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 ioc->name, sz, sz));
4350 total_size += sz;
4351
4352 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304353 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304355 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 ioc->name, sz, sz, num_chain));
4357
4358 total_size += sz;
4359 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4360 if (mem == NULL) {
4361 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4362 ioc->name);
4363 goto out_fail;
4364 }
4365
Prakash, Sathya436ace72007-07-24 15:42:08 +05304366 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4368
4369 memset(mem, 0, total_size);
4370 ioc->alloc_total += total_size;
4371 ioc->alloc = mem;
4372 ioc->alloc_dma = alloc_dma;
4373 ioc->alloc_sz = total_size;
4374 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4375 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4376
Prakash, Sathya436ace72007-07-24 15:42:08 +05304377 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004378 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4379
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 alloc_dma += reply_sz;
4381 mem += reply_sz;
4382
4383 /* Request FIFO - WE manage this! */
4384
4385 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4386 ioc->req_frames_dma = alloc_dma;
4387
Prakash, Sathya436ace72007-07-24 15:42:08 +05304388 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 ioc->name, mem, (void *)(ulong)alloc_dma));
4390
4391 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4392
4393#if defined(CONFIG_MTRR) && 0
4394 /*
4395 * Enable Write Combining MTRR for IOC's memory region.
4396 * (at least as much as we can; "size and base must be
4397 * multiples of 4 kiB"
4398 */
4399 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4400 sz,
4401 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304402 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 ioc->name, ioc->req_frames_dma, sz));
4404#endif
4405
4406 for (i = 0; i < ioc->req_depth; i++) {
4407 alloc_dma += ioc->req_sz;
4408 mem += ioc->req_sz;
4409 }
4410
4411 ioc->ChainBuffer = mem;
4412 ioc->ChainBufferDMA = alloc_dma;
4413
Prakash, Sathya436ace72007-07-24 15:42:08 +05304414 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4416
4417 /* Initialize the free chain Q.
4418 */
4419
4420 INIT_LIST_HEAD(&ioc->FreeChainQ);
4421
4422 /* Post the chain buffers to the FreeChainQ.
4423 */
4424 mem = (u8 *)ioc->ChainBuffer;
4425 for (i=0; i < num_chain; i++) {
4426 mf = (MPT_FRAME_HDR *) mem;
4427 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4428 mem += ioc->req_sz;
4429 }
4430
4431 /* Initialize Request frames linked list
4432 */
4433 alloc_dma = ioc->req_frames_dma;
4434 mem = (u8 *) ioc->req_frames;
4435
4436 spin_lock_irqsave(&ioc->FreeQlock, flags);
4437 INIT_LIST_HEAD(&ioc->FreeQ);
4438 for (i = 0; i < ioc->req_depth; i++) {
4439 mf = (MPT_FRAME_HDR *) mem;
4440
4441 /* Queue REQUESTs *internally*! */
4442 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4443
4444 mem += ioc->req_sz;
4445 }
4446 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4447
4448 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4449 ioc->sense_buf_pool =
4450 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4451 if (ioc->sense_buf_pool == NULL) {
4452 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4453 ioc->name);
4454 goto out_fail;
4455 }
4456
4457 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4458 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304459 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4461
4462 }
4463
4464 /* Post Reply frames to FIFO
4465 */
4466 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304467 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4469
4470 for (i = 0; i < ioc->reply_depth; i++) {
4471 /* Write each address to the IOC! */
4472 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4473 alloc_dma += ioc->reply_sz;
4474 }
4475
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304476 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4477 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4478 ioc->dma_mask))
4479 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4480 "restoring 64 bit addressing\n", ioc->name));
4481
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 return 0;
4483
4484out_fail:
4485 if (ioc->alloc != NULL) {
4486 sz = ioc->alloc_sz;
4487 pci_free_consistent(ioc->pcidev,
4488 sz,
4489 ioc->alloc, ioc->alloc_dma);
4490 ioc->reply_frames = NULL;
4491 ioc->req_frames = NULL;
4492 ioc->alloc_total -= sz;
4493 }
4494 if (ioc->sense_buf_pool != NULL) {
4495 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4496 pci_free_consistent(ioc->pcidev,
4497 sz,
4498 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4499 ioc->sense_buf_pool = NULL;
4500 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304501
4502 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4503 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4504 DMA_BIT_MASK(64)))
4505 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4506 "restoring 64 bit addressing\n", ioc->name));
4507
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 return -1;
4509}
4510
4511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4512/**
4513 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4514 * from IOC via doorbell handshake method.
4515 * @ioc: Pointer to MPT_ADAPTER structure
4516 * @reqBytes: Size of the request in bytes
4517 * @req: Pointer to MPT request frame
4518 * @replyBytes: Expected size of the reply in bytes
4519 * @u16reply: Pointer to area where reply should be written
4520 * @maxwait: Max wait time for a reply (in seconds)
4521 * @sleepFlag: Specifies whether the process can sleep
4522 *
4523 * NOTES: It is the callers responsibility to byte-swap fields in the
4524 * request which are greater than 1 byte in size. It is also the
4525 * callers responsibility to byte-swap response fields which are
4526 * greater than 1 byte in size.
4527 *
4528 * Returns 0 for success, non-zero for failure.
4529 */
4530static int
4531mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004532 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533{
4534 MPIDefaultReply_t *mptReply;
4535 int failcnt = 0;
4536 int t;
4537
4538 /*
4539 * Get ready to cache a handshake reply
4540 */
4541 ioc->hs_reply_idx = 0;
4542 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4543 mptReply->MsgLength = 0;
4544
4545 /*
4546 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4547 * then tell IOC that we want to handshake a request of N words.
4548 * (WRITE u32val to Doorbell reg).
4549 */
4550 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4551 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4552 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4553 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4554
4555 /*
4556 * Wait for IOC's doorbell handshake int
4557 */
4558 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4559 failcnt++;
4560
Prakash, Sathya436ace72007-07-24 15:42:08 +05304561 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4563
4564 /* Read doorbell and check for active bit */
4565 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4566 return -1;
4567
4568 /*
4569 * Clear doorbell int (WRITE 0 to IntStatus reg),
4570 * then wait for IOC to ACKnowledge that it's ready for
4571 * our handshake request.
4572 */
4573 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4574 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4575 failcnt++;
4576
4577 if (!failcnt) {
4578 int ii;
4579 u8 *req_as_bytes = (u8 *) req;
4580
4581 /*
4582 * Stuff request words via doorbell handshake,
4583 * with ACK from IOC for each.
4584 */
4585 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4586 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4587 (req_as_bytes[(ii*4) + 1] << 8) |
4588 (req_as_bytes[(ii*4) + 2] << 16) |
4589 (req_as_bytes[(ii*4) + 3] << 24));
4590
4591 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4592 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4593 failcnt++;
4594 }
4595
Prakash, Sathya436ace72007-07-24 15:42:08 +05304596 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004597 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598
Prakash, Sathya436ace72007-07-24 15:42:08 +05304599 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4601
4602 /*
4603 * Wait for completion of doorbell handshake reply from the IOC
4604 */
4605 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4606 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004607
Prakash, Sathya436ace72007-07-24 15:42:08 +05304608 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4610
4611 /*
4612 * Copy out the cached reply...
4613 */
4614 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4615 u16reply[ii] = ioc->hs_reply[ii];
4616 } else {
4617 return -99;
4618 }
4619
4620 return -failcnt;
4621}
4622
4623/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004624/**
4625 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 * @ioc: Pointer to MPT_ADAPTER structure
4627 * @howlong: How long to wait (in seconds)
4628 * @sleepFlag: Specifies whether the process can sleep
4629 *
4630 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004631 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4632 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 *
4634 * Returns a negative value on failure, else wait loop count.
4635 */
4636static int
4637WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4638{
4639 int cntdn;
4640 int count = 0;
4641 u32 intstat=0;
4642
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004643 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644
4645 if (sleepFlag == CAN_SLEEP) {
4646 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004647 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4649 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4650 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 count++;
4652 }
4653 } else {
4654 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004655 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4657 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4658 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 count++;
4660 }
4661 }
4662
4663 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304664 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 ioc->name, count));
4666 return count;
4667 }
4668
4669 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4670 ioc->name, count, intstat);
4671 return -1;
4672}
4673
4674/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004675/**
4676 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 * @ioc: Pointer to MPT_ADAPTER structure
4678 * @howlong: How long to wait (in seconds)
4679 * @sleepFlag: Specifies whether the process can sleep
4680 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004681 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4682 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683 *
4684 * Returns a negative value on failure, else wait loop count.
4685 */
4686static int
4687WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4688{
4689 int cntdn;
4690 int count = 0;
4691 u32 intstat=0;
4692
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004693 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 if (sleepFlag == CAN_SLEEP) {
4695 while (--cntdn) {
4696 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4697 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4698 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004699 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700 count++;
4701 }
4702 } else {
4703 while (--cntdn) {
4704 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4705 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4706 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004707 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 count++;
4709 }
4710 }
4711
4712 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304713 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 ioc->name, count, howlong));
4715 return count;
4716 }
4717
4718 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4719 ioc->name, count, intstat);
4720 return -1;
4721}
4722
4723/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004724/**
4725 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 * @ioc: Pointer to MPT_ADAPTER structure
4727 * @howlong: How long to wait (in seconds)
4728 * @sleepFlag: Specifies whether the process can sleep
4729 *
4730 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4731 * Reply is cached to IOC private area large enough to hold a maximum
4732 * of 128 bytes of reply data.
4733 *
4734 * Returns a negative value on failure, else size of reply in WORDS.
4735 */
4736static int
4737WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4738{
4739 int u16cnt = 0;
4740 int failcnt = 0;
4741 int t;
4742 u16 *hs_reply = ioc->hs_reply;
4743 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4744 u16 hword;
4745
4746 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4747
4748 /*
4749 * Get first two u16's so we can look at IOC's intended reply MsgLength
4750 */
4751 u16cnt=0;
4752 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4753 failcnt++;
4754 } else {
4755 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4756 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4757 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4758 failcnt++;
4759 else {
4760 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4761 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4762 }
4763 }
4764
Prakash, Sathya436ace72007-07-24 15:42:08 +05304765 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004766 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4768
4769 /*
4770 * If no error (and IOC said MsgLength is > 0), piece together
4771 * reply 16 bits at a time.
4772 */
4773 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4774 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4775 failcnt++;
4776 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4777 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004778 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 hs_reply[u16cnt] = hword;
4780 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4781 }
4782
4783 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4784 failcnt++;
4785 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4786
4787 if (failcnt) {
4788 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4789 ioc->name);
4790 return -failcnt;
4791 }
4792#if 0
4793 else if (u16cnt != (2 * mptReply->MsgLength)) {
4794 return -101;
4795 }
4796 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4797 return -102;
4798 }
4799#endif
4800
Prakash, Sathya436ace72007-07-24 15:42:08 +05304801 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004802 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803
Prakash, Sathya436ace72007-07-24 15:42:08 +05304804 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 ioc->name, t, u16cnt/2));
4806 return u16cnt/2;
4807}
4808
4809/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004810/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 * GetLanConfigPages - Fetch LANConfig pages.
4812 * @ioc: Pointer to MPT_ADAPTER structure
4813 *
4814 * Return: 0 for success
4815 * -ENOMEM if no memory available
4816 * -EPERM if not allowed due to ISR context
4817 * -EAGAIN if no msg frames currently available
4818 * -EFAULT for non-successful reply or no reply (timeout)
4819 */
4820static int
4821GetLanConfigPages(MPT_ADAPTER *ioc)
4822{
4823 ConfigPageHeader_t hdr;
4824 CONFIGPARMS cfg;
4825 LANPage0_t *ppage0_alloc;
4826 dma_addr_t page0_dma;
4827 LANPage1_t *ppage1_alloc;
4828 dma_addr_t page1_dma;
4829 int rc = 0;
4830 int data_sz;
4831 int copy_sz;
4832
4833 /* Get LAN Page 0 header */
4834 hdr.PageVersion = 0;
4835 hdr.PageLength = 0;
4836 hdr.PageNumber = 0;
4837 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004838 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 cfg.physAddr = -1;
4840 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4841 cfg.dir = 0;
4842 cfg.pageAddr = 0;
4843 cfg.timeout = 0;
4844
4845 if ((rc = mpt_config(ioc, &cfg)) != 0)
4846 return rc;
4847
4848 if (hdr.PageLength > 0) {
4849 data_sz = hdr.PageLength * 4;
4850 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4851 rc = -ENOMEM;
4852 if (ppage0_alloc) {
4853 memset((u8 *)ppage0_alloc, 0, data_sz);
4854 cfg.physAddr = page0_dma;
4855 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4856
4857 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4858 /* save the data */
4859 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4860 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4861
4862 }
4863
4864 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4865
4866 /* FIXME!
4867 * Normalize endianness of structure data,
4868 * by byte-swapping all > 1 byte fields!
4869 */
4870
4871 }
4872
4873 if (rc)
4874 return rc;
4875 }
4876
4877 /* Get LAN Page 1 header */
4878 hdr.PageVersion = 0;
4879 hdr.PageLength = 0;
4880 hdr.PageNumber = 1;
4881 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004882 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 cfg.physAddr = -1;
4884 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4885 cfg.dir = 0;
4886 cfg.pageAddr = 0;
4887
4888 if ((rc = mpt_config(ioc, &cfg)) != 0)
4889 return rc;
4890
4891 if (hdr.PageLength == 0)
4892 return 0;
4893
4894 data_sz = hdr.PageLength * 4;
4895 rc = -ENOMEM;
4896 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4897 if (ppage1_alloc) {
4898 memset((u8 *)ppage1_alloc, 0, data_sz);
4899 cfg.physAddr = page1_dma;
4900 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4901
4902 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4903 /* save the data */
4904 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4905 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4906 }
4907
4908 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4909
4910 /* FIXME!
4911 * Normalize endianness of structure data,
4912 * by byte-swapping all > 1 byte fields!
4913 */
4914
4915 }
4916
4917 return rc;
4918}
4919
4920/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004921/**
4922 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004923 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004924 * @persist_opcode: see below
4925 *
4926 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4927 * devices not currently present.
4928 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4929 *
4930 * NOTE: Don't use not this function during interrupt time.
4931 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004932 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004933 */
4934
4935/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4936int
4937mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4938{
4939 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4940 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4941 MPT_FRAME_HDR *mf = NULL;
4942 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304943 int ret = 0;
4944 unsigned long timeleft;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004945
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304946 mutex_lock(&ioc->mptbase_cmds.mutex);
4947
4948 /* init the internal cmd struct */
4949 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
4950 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004951
4952 /* insure garbage is not sent to fw */
4953 switch(persist_opcode) {
4954
4955 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4956 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4957 break;
4958
4959 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304960 ret = -1;
4961 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004962 }
4963
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304964 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
4965 __func__, persist_opcode);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004966
4967 /* Get a MF for this command.
4968 */
4969 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304970 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
4971 ret = -1;
4972 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004973 }
4974
4975 mpi_hdr = (MPIHeader_t *) mf;
4976 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4977 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4978 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4979 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4980 sasIoUnitCntrReq->Operation = persist_opcode;
4981
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004982 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304983 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
4984 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4985 ret = -ETIME;
4986 printk(KERN_DEBUG "%s: failed\n", __func__);
4987 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4988 goto out;
4989 if (!timeleft) {
4990 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
4991 ioc->name, __func__);
4992 mpt_HardResetHandler(ioc, CAN_SLEEP);
4993 mpt_free_msg_frame(ioc, mf);
4994 }
4995 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004996 }
4997
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304998 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4999 ret = -1;
5000 goto out;
5001 }
5002
5003 sasIoUnitCntrReply =
5004 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5005 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5006 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5007 __func__, sasIoUnitCntrReply->IOCStatus,
5008 sasIoUnitCntrReply->IOCLogInfo);
5009 printk(KERN_DEBUG "%s: failed\n", __func__);
5010 ret = -1;
5011 } else
5012 printk(KERN_DEBUG "%s: success\n", __func__);
5013 out:
5014
5015 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5016 mutex_unlock(&ioc->mptbase_cmds.mutex);
5017 return ret;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005018}
5019
5020/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005021
5022static void
5023mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5024 MpiEventDataRaid_t * pRaidEventData)
5025{
5026 int volume;
5027 int reason;
5028 int disk;
5029 int status;
5030 int flags;
5031 int state;
5032
5033 volume = pRaidEventData->VolumeID;
5034 reason = pRaidEventData->ReasonCode;
5035 disk = pRaidEventData->PhysDiskNum;
5036 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5037 flags = (status >> 0) & 0xff;
5038 state = (status >> 8) & 0xff;
5039
5040 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5041 return;
5042 }
5043
5044 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5045 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5046 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005047 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5048 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005049 } else {
5050 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5051 ioc->name, volume);
5052 }
5053
5054 switch(reason) {
5055 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5056 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5057 ioc->name);
5058 break;
5059
5060 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5061
5062 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5063 ioc->name);
5064 break;
5065
5066 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5067 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5068 ioc->name);
5069 break;
5070
5071 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5072 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5073 ioc->name,
5074 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5075 ? "optimal"
5076 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5077 ? "degraded"
5078 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5079 ? "failed"
5080 : "state unknown",
5081 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5082 ? ", enabled" : "",
5083 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5084 ? ", quiesced" : "",
5085 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5086 ? ", resync in progress" : "" );
5087 break;
5088
5089 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5090 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5091 ioc->name, disk);
5092 break;
5093
5094 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5095 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5096 ioc->name);
5097 break;
5098
5099 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5100 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5101 ioc->name);
5102 break;
5103
5104 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5105 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5106 ioc->name);
5107 break;
5108
5109 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5110 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5111 ioc->name,
5112 state == MPI_PHYSDISK0_STATUS_ONLINE
5113 ? "online"
5114 : state == MPI_PHYSDISK0_STATUS_MISSING
5115 ? "missing"
5116 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5117 ? "not compatible"
5118 : state == MPI_PHYSDISK0_STATUS_FAILED
5119 ? "failed"
5120 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5121 ? "initializing"
5122 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5123 ? "offline requested"
5124 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5125 ? "failed requested"
5126 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5127 ? "offline"
5128 : "state unknown",
5129 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5130 ? ", out of sync" : "",
5131 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5132 ? ", quiesced" : "" );
5133 break;
5134
5135 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5136 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5137 ioc->name, disk);
5138 break;
5139
5140 case MPI_EVENT_RAID_RC_SMART_DATA:
5141 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5142 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5143 break;
5144
5145 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5146 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5147 ioc->name, disk);
5148 break;
5149 }
5150}
5151
5152/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005153/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5155 * @ioc: Pointer to MPT_ADAPTER structure
5156 *
5157 * Returns: 0 for success
5158 * -ENOMEM if no memory available
5159 * -EPERM if not allowed due to ISR context
5160 * -EAGAIN if no msg frames currently available
5161 * -EFAULT for non-successful reply or no reply (timeout)
5162 */
5163static int
5164GetIoUnitPage2(MPT_ADAPTER *ioc)
5165{
5166 ConfigPageHeader_t hdr;
5167 CONFIGPARMS cfg;
5168 IOUnitPage2_t *ppage_alloc;
5169 dma_addr_t page_dma;
5170 int data_sz;
5171 int rc;
5172
5173 /* Get the page header */
5174 hdr.PageVersion = 0;
5175 hdr.PageLength = 0;
5176 hdr.PageNumber = 2;
5177 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005178 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179 cfg.physAddr = -1;
5180 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5181 cfg.dir = 0;
5182 cfg.pageAddr = 0;
5183 cfg.timeout = 0;
5184
5185 if ((rc = mpt_config(ioc, &cfg)) != 0)
5186 return rc;
5187
5188 if (hdr.PageLength == 0)
5189 return 0;
5190
5191 /* Read the config page */
5192 data_sz = hdr.PageLength * 4;
5193 rc = -ENOMEM;
5194 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5195 if (ppage_alloc) {
5196 memset((u8 *)ppage_alloc, 0, data_sz);
5197 cfg.physAddr = page_dma;
5198 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5199
5200 /* If Good, save data */
5201 if ((rc = mpt_config(ioc, &cfg)) == 0)
5202 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5203
5204 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5205 }
5206
5207 return rc;
5208}
5209
5210/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005211/**
5212 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 * @ioc: Pointer to a Adapter Strucutre
5214 * @portnum: IOC port number
5215 *
5216 * Return: -EFAULT if read of config page header fails
5217 * or if no nvram
5218 * If read of SCSI Port Page 0 fails,
5219 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5220 * Adapter settings: async, narrow
5221 * Return 1
5222 * If read of SCSI Port Page 2 fails,
5223 * Adapter settings valid
5224 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5225 * Return 1
5226 * Else
5227 * Both valid
5228 * Return 0
5229 * CHECK - what type of locking mechanisms should be used????
5230 */
5231static int
5232mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5233{
5234 u8 *pbuf;
5235 dma_addr_t buf_dma;
5236 CONFIGPARMS cfg;
5237 ConfigPageHeader_t header;
5238 int ii;
5239 int data, rc = 0;
5240
5241 /* Allocate memory
5242 */
5243 if (!ioc->spi_data.nvram) {
5244 int sz;
5245 u8 *mem;
5246 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5247 mem = kmalloc(sz, GFP_ATOMIC);
5248 if (mem == NULL)
5249 return -EFAULT;
5250
5251 ioc->spi_data.nvram = (int *) mem;
5252
Prakash, Sathya436ace72007-07-24 15:42:08 +05305253 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 ioc->name, ioc->spi_data.nvram, sz));
5255 }
5256
5257 /* Invalidate NVRAM information
5258 */
5259 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5260 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5261 }
5262
5263 /* Read SPP0 header, allocate memory, then read page.
5264 */
5265 header.PageVersion = 0;
5266 header.PageLength = 0;
5267 header.PageNumber = 0;
5268 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005269 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270 cfg.physAddr = -1;
5271 cfg.pageAddr = portnum;
5272 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5273 cfg.dir = 0;
5274 cfg.timeout = 0; /* use default */
5275 if (mpt_config(ioc, &cfg) != 0)
5276 return -EFAULT;
5277
5278 if (header.PageLength > 0) {
5279 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5280 if (pbuf) {
5281 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5282 cfg.physAddr = buf_dma;
5283 if (mpt_config(ioc, &cfg) != 0) {
5284 ioc->spi_data.maxBusWidth = MPT_NARROW;
5285 ioc->spi_data.maxSyncOffset = 0;
5286 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5287 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5288 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305289 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5290 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005291 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 } else {
5293 /* Save the Port Page 0 data
5294 */
5295 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5296 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5297 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5298
5299 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5300 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005301 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5302 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 ioc->name, pPP0->Capabilities));
5304 }
5305 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5306 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5307 if (data) {
5308 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5309 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5310 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305311 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5312 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005313 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 } else {
5315 ioc->spi_data.maxSyncOffset = 0;
5316 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5317 }
5318
5319 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5320
5321 /* Update the minSyncFactor based on bus type.
5322 */
5323 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5324 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5325
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005326 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305328 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5329 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005330 ioc->name, ioc->spi_data.minSyncFactor));
5331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 }
5333 }
5334 if (pbuf) {
5335 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5336 }
5337 }
5338 }
5339
5340 /* SCSI Port Page 2 - Read the header then the page.
5341 */
5342 header.PageVersion = 0;
5343 header.PageLength = 0;
5344 header.PageNumber = 2;
5345 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005346 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 cfg.physAddr = -1;
5348 cfg.pageAddr = portnum;
5349 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5350 cfg.dir = 0;
5351 if (mpt_config(ioc, &cfg) != 0)
5352 return -EFAULT;
5353
5354 if (header.PageLength > 0) {
5355 /* Allocate memory and read SCSI Port Page 2
5356 */
5357 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5358 if (pbuf) {
5359 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5360 cfg.physAddr = buf_dma;
5361 if (mpt_config(ioc, &cfg) != 0) {
5362 /* Nvram data is left with INVALID mark
5363 */
5364 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005365 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5366
5367 /* This is an ATTO adapter, read Page2 accordingly
5368 */
5369 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5370 ATTODeviceInfo_t *pdevice = NULL;
5371 u16 ATTOFlags;
5372
5373 /* Save the Port Page 2 data
5374 * (reformat into a 32bit quantity)
5375 */
5376 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5377 pdevice = &pPP2->DeviceSettings[ii];
5378 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5379 data = 0;
5380
5381 /* Translate ATTO device flags to LSI format
5382 */
5383 if (ATTOFlags & ATTOFLAG_DISC)
5384 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5385 if (ATTOFlags & ATTOFLAG_ID_ENB)
5386 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5387 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5388 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5389 if (ATTOFlags & ATTOFLAG_TAGGED)
5390 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5391 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5392 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5393
5394 data = (data << 16) | (pdevice->Period << 8) | 10;
5395 ioc->spi_data.nvram[ii] = data;
5396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 } else {
5398 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5399 MpiDeviceInfo_t *pdevice = NULL;
5400
Moore, Ericd8e925d2006-01-16 18:53:06 -07005401 /*
5402 * Save "Set to Avoid SCSI Bus Resets" flag
5403 */
5404 ioc->spi_data.bus_reset =
5405 (le32_to_cpu(pPP2->PortFlags) &
5406 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5407 0 : 1 ;
5408
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 /* Save the Port Page 2 data
5410 * (reformat into a 32bit quantity)
5411 */
5412 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5413 ioc->spi_data.PortFlags = data;
5414 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5415 pdevice = &pPP2->DeviceSettings[ii];
5416 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5417 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5418 ioc->spi_data.nvram[ii] = data;
5419 }
5420 }
5421
5422 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5423 }
5424 }
5425
5426 /* Update Adapter limits with those from NVRAM
5427 * Comment: Don't need to do this. Target performance
5428 * parameters will never exceed the adapters limits.
5429 */
5430
5431 return rc;
5432}
5433
5434/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005435/**
5436 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 * @ioc: Pointer to a Adapter Strucutre
5438 * @portnum: IOC port number
5439 *
5440 * Return: -EFAULT if read of config page header fails
5441 * or 0 if success.
5442 */
5443static int
5444mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5445{
5446 CONFIGPARMS cfg;
5447 ConfigPageHeader_t header;
5448
5449 /* Read the SCSI Device Page 1 header
5450 */
5451 header.PageVersion = 0;
5452 header.PageLength = 0;
5453 header.PageNumber = 1;
5454 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005455 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 cfg.physAddr = -1;
5457 cfg.pageAddr = portnum;
5458 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5459 cfg.dir = 0;
5460 cfg.timeout = 0;
5461 if (mpt_config(ioc, &cfg) != 0)
5462 return -EFAULT;
5463
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005464 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5465 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466
5467 header.PageVersion = 0;
5468 header.PageLength = 0;
5469 header.PageNumber = 0;
5470 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5471 if (mpt_config(ioc, &cfg) != 0)
5472 return -EFAULT;
5473
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005474 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5475 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476
Prakash, Sathya436ace72007-07-24 15:42:08 +05305477 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5479
Prakash, Sathya436ace72007-07-24 15:42:08 +05305480 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5482 return 0;
5483}
5484
Eric Mooreb506ade2007-01-29 09:45:37 -07005485/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005486 * mpt_inactive_raid_list_free - This clears this link list.
5487 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005488 **/
5489static void
5490mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5491{
5492 struct inactive_raid_component_info *component_info, *pNext;
5493
5494 if (list_empty(&ioc->raid_data.inactive_list))
5495 return;
5496
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005497 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005498 list_for_each_entry_safe(component_info, pNext,
5499 &ioc->raid_data.inactive_list, list) {
5500 list_del(&component_info->list);
5501 kfree(component_info);
5502 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005503 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005504}
5505
5506/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005507 * 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 -07005508 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005509 * @ioc : pointer to per adapter structure
5510 * @channel : volume channel
5511 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005512 **/
5513static void
5514mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5515{
5516 CONFIGPARMS cfg;
5517 ConfigPageHeader_t hdr;
5518 dma_addr_t dma_handle;
5519 pRaidVolumePage0_t buffer = NULL;
5520 int i;
5521 RaidPhysDiskPage0_t phys_disk;
5522 struct inactive_raid_component_info *component_info;
5523 int handle_inactive_volumes;
5524
5525 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5526 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5527 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5528 cfg.pageAddr = (channel << 8) + id;
5529 cfg.cfghdr.hdr = &hdr;
5530 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5531
5532 if (mpt_config(ioc, &cfg) != 0)
5533 goto out;
5534
5535 if (!hdr.PageLength)
5536 goto out;
5537
5538 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5539 &dma_handle);
5540
5541 if (!buffer)
5542 goto out;
5543
5544 cfg.physAddr = dma_handle;
5545 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5546
5547 if (mpt_config(ioc, &cfg) != 0)
5548 goto out;
5549
5550 if (!buffer->NumPhysDisks)
5551 goto out;
5552
5553 handle_inactive_volumes =
5554 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5555 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5556 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5557 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5558
5559 if (!handle_inactive_volumes)
5560 goto out;
5561
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005562 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005563 for (i = 0; i < buffer->NumPhysDisks; i++) {
5564 if(mpt_raid_phys_disk_pg0(ioc,
5565 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5566 continue;
5567
5568 if ((component_info = kmalloc(sizeof (*component_info),
5569 GFP_KERNEL)) == NULL)
5570 continue;
5571
5572 component_info->volumeID = id;
5573 component_info->volumeBus = channel;
5574 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5575 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5576 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5577 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5578
5579 list_add_tail(&component_info->list,
5580 &ioc->raid_data.inactive_list);
5581 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005582 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005583
5584 out:
5585 if (buffer)
5586 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5587 dma_handle);
5588}
5589
5590/**
5591 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5592 * @ioc: Pointer to a Adapter Structure
5593 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5594 * @phys_disk: requested payload data returned
5595 *
5596 * Return:
5597 * 0 on success
5598 * -EFAULT if read of config page header fails or data pointer not NULL
5599 * -ENOMEM if pci_alloc failed
5600 **/
5601int
5602mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5603{
5604 CONFIGPARMS cfg;
5605 ConfigPageHeader_t hdr;
5606 dma_addr_t dma_handle;
5607 pRaidPhysDiskPage0_t buffer = NULL;
5608 int rc;
5609
5610 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5611 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5612
5613 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5614 cfg.cfghdr.hdr = &hdr;
5615 cfg.physAddr = -1;
5616 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5617
5618 if (mpt_config(ioc, &cfg) != 0) {
5619 rc = -EFAULT;
5620 goto out;
5621 }
5622
5623 if (!hdr.PageLength) {
5624 rc = -EFAULT;
5625 goto out;
5626 }
5627
5628 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5629 &dma_handle);
5630
5631 if (!buffer) {
5632 rc = -ENOMEM;
5633 goto out;
5634 }
5635
5636 cfg.physAddr = dma_handle;
5637 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5638 cfg.pageAddr = phys_disk_num;
5639
5640 if (mpt_config(ioc, &cfg) != 0) {
5641 rc = -EFAULT;
5642 goto out;
5643 }
5644
5645 rc = 0;
5646 memcpy(phys_disk, buffer, sizeof(*buffer));
5647 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5648
5649 out:
5650
5651 if (buffer)
5652 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5653 dma_handle);
5654
5655 return rc;
5656}
5657
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658/**
5659 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5660 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 *
5662 * Return:
5663 * 0 on success
5664 * -EFAULT if read of config page header fails or data pointer not NULL
5665 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005666 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667int
5668mpt_findImVolumes(MPT_ADAPTER *ioc)
5669{
5670 IOCPage2_t *pIoc2;
5671 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672 dma_addr_t ioc2_dma;
5673 CONFIGPARMS cfg;
5674 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 int rc = 0;
5676 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005677 int i;
5678
5679 if (!ioc->ir_firmware)
5680 return 0;
5681
5682 /* Free the old page
5683 */
5684 kfree(ioc->raid_data.pIocPg2);
5685 ioc->raid_data.pIocPg2 = NULL;
5686 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687
5688 /* Read IOCP2 header then the page.
5689 */
5690 header.PageVersion = 0;
5691 header.PageLength = 0;
5692 header.PageNumber = 2;
5693 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005694 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695 cfg.physAddr = -1;
5696 cfg.pageAddr = 0;
5697 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5698 cfg.dir = 0;
5699 cfg.timeout = 0;
5700 if (mpt_config(ioc, &cfg) != 0)
5701 return -EFAULT;
5702
5703 if (header.PageLength == 0)
5704 return -EFAULT;
5705
5706 iocpage2sz = header.PageLength * 4;
5707 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5708 if (!pIoc2)
5709 return -ENOMEM;
5710
5711 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5712 cfg.physAddr = ioc2_dma;
5713 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005714 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715
Eric Mooreb506ade2007-01-29 09:45:37 -07005716 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5717 if (!mem)
5718 goto out;
5719
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005721 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722
Eric Mooreb506ade2007-01-29 09:45:37 -07005723 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724
Eric Mooreb506ade2007-01-29 09:45:37 -07005725 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5726 mpt_inactive_raid_volumes(ioc,
5727 pIoc2->RaidVolume[i].VolumeBus,
5728 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729
Eric Mooreb506ade2007-01-29 09:45:37 -07005730 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5732
5733 return rc;
5734}
5735
Moore, Ericc972c702006-03-14 09:14:06 -07005736static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5738{
5739 IOCPage3_t *pIoc3;
5740 u8 *mem;
5741 CONFIGPARMS cfg;
5742 ConfigPageHeader_t header;
5743 dma_addr_t ioc3_dma;
5744 int iocpage3sz = 0;
5745
5746 /* Free the old page
5747 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005748 kfree(ioc->raid_data.pIocPg3);
5749 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750
5751 /* There is at least one physical disk.
5752 * Read and save IOC Page 3
5753 */
5754 header.PageVersion = 0;
5755 header.PageLength = 0;
5756 header.PageNumber = 3;
5757 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005758 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 cfg.physAddr = -1;
5760 cfg.pageAddr = 0;
5761 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5762 cfg.dir = 0;
5763 cfg.timeout = 0;
5764 if (mpt_config(ioc, &cfg) != 0)
5765 return 0;
5766
5767 if (header.PageLength == 0)
5768 return 0;
5769
5770 /* Read Header good, alloc memory
5771 */
5772 iocpage3sz = header.PageLength * 4;
5773 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5774 if (!pIoc3)
5775 return 0;
5776
5777 /* Read the Page and save the data
5778 * into malloc'd memory.
5779 */
5780 cfg.physAddr = ioc3_dma;
5781 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5782 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005783 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 if (mem) {
5785 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005786 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787 }
5788 }
5789
5790 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5791
5792 return 0;
5793}
5794
5795static void
5796mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5797{
5798 IOCPage4_t *pIoc4;
5799 CONFIGPARMS cfg;
5800 ConfigPageHeader_t header;
5801 dma_addr_t ioc4_dma;
5802 int iocpage4sz;
5803
5804 /* Read and save IOC Page 4
5805 */
5806 header.PageVersion = 0;
5807 header.PageLength = 0;
5808 header.PageNumber = 4;
5809 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005810 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 cfg.physAddr = -1;
5812 cfg.pageAddr = 0;
5813 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5814 cfg.dir = 0;
5815 cfg.timeout = 0;
5816 if (mpt_config(ioc, &cfg) != 0)
5817 return;
5818
5819 if (header.PageLength == 0)
5820 return;
5821
5822 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5823 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5824 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5825 if (!pIoc4)
5826 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005827 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828 } else {
5829 ioc4_dma = ioc->spi_data.IocPg4_dma;
5830 iocpage4sz = ioc->spi_data.IocPg4Sz;
5831 }
5832
5833 /* Read the Page into dma memory.
5834 */
5835 cfg.physAddr = ioc4_dma;
5836 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5837 if (mpt_config(ioc, &cfg) == 0) {
5838 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5839 ioc->spi_data.IocPg4_dma = ioc4_dma;
5840 ioc->spi_data.IocPg4Sz = iocpage4sz;
5841 } else {
5842 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5843 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005844 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845 }
5846}
5847
5848static void
5849mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5850{
5851 IOCPage1_t *pIoc1;
5852 CONFIGPARMS cfg;
5853 ConfigPageHeader_t header;
5854 dma_addr_t ioc1_dma;
5855 int iocpage1sz = 0;
5856 u32 tmp;
5857
5858 /* Check the Coalescing Timeout in IOC Page 1
5859 */
5860 header.PageVersion = 0;
5861 header.PageLength = 0;
5862 header.PageNumber = 1;
5863 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005864 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865 cfg.physAddr = -1;
5866 cfg.pageAddr = 0;
5867 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5868 cfg.dir = 0;
5869 cfg.timeout = 0;
5870 if (mpt_config(ioc, &cfg) != 0)
5871 return;
5872
5873 if (header.PageLength == 0)
5874 return;
5875
5876 /* Read Header good, alloc memory
5877 */
5878 iocpage1sz = header.PageLength * 4;
5879 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5880 if (!pIoc1)
5881 return;
5882
5883 /* Read the Page and check coalescing timeout
5884 */
5885 cfg.physAddr = ioc1_dma;
5886 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5887 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305888
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5890 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5891 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5892
Prakash, Sathya436ace72007-07-24 15:42:08 +05305893 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 ioc->name, tmp));
5895
5896 if (tmp > MPT_COALESCING_TIMEOUT) {
5897 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5898
5899 /* Write NVRAM and current
5900 */
5901 cfg.dir = 1;
5902 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5903 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305904 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 ioc->name, MPT_COALESCING_TIMEOUT));
5906
5907 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5908 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305909 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5910 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 ioc->name, MPT_COALESCING_TIMEOUT));
5912 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305913 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5914 "Reset NVRAM Coalescing Timeout Failed\n",
5915 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916 }
5917
5918 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305919 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5920 "Reset of Current Coalescing Timeout Failed!\n",
5921 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922 }
5923 }
5924
5925 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305926 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927 }
5928 }
5929
5930 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5931
5932 return;
5933}
5934
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305935static void
5936mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5937{
5938 CONFIGPARMS cfg;
5939 ConfigPageHeader_t hdr;
5940 dma_addr_t buf_dma;
5941 ManufacturingPage0_t *pbuf = NULL;
5942
5943 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5944 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5945
5946 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5947 cfg.cfghdr.hdr = &hdr;
5948 cfg.physAddr = -1;
5949 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5950 cfg.timeout = 10;
5951
5952 if (mpt_config(ioc, &cfg) != 0)
5953 goto out;
5954
5955 if (!cfg.cfghdr.hdr->PageLength)
5956 goto out;
5957
5958 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5959 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5960 if (!pbuf)
5961 goto out;
5962
5963 cfg.physAddr = buf_dma;
5964
5965 if (mpt_config(ioc, &cfg) != 0)
5966 goto out;
5967
5968 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5969 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5970 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5971
5972 out:
5973
5974 if (pbuf)
5975 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5976}
5977
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005979/**
5980 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 * @ioc: Pointer to MPT_ADAPTER structure
5982 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05305983 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 */
5985static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05305986SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987{
Kashyap, Desaifd761752009-05-29 16:39:06 +05305988 EventNotification_t evn;
5989 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990
Kashyap, Desaifd761752009-05-29 16:39:06 +05305991 memset(&evn, 0, sizeof(EventNotification_t));
5992 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993
Kashyap, Desaifd761752009-05-29 16:39:06 +05305994 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5995 evn.Switch = EvSwitch;
5996 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997
Kashyap, Desaifd761752009-05-29 16:39:06 +05305998 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5999 "Sending EventNotification (%d) request %p\n",
6000 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001
Kashyap, Desaifd761752009-05-29 16:39:06 +05306002 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6003 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6004 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005}
6006
6007/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6008/**
6009 * SendEventAck - Send EventAck request to MPT adapter.
6010 * @ioc: Pointer to MPT_ADAPTER structure
6011 * @evnp: Pointer to original EventNotification request
6012 */
6013static int
6014SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6015{
6016 EventAck_t *pAck;
6017
6018 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306019 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306020 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 return -1;
6022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023
Prakash, Sathya436ace72007-07-24 15:42:08 +05306024 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025
6026 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6027 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006028 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006030 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 pAck->Event = evnp->Event;
6032 pAck->EventContext = evnp->EventContext;
6033
6034 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6035
6036 return 0;
6037}
6038
6039/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6040/**
6041 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006042 * @ioc: Pointer to an adapter structure
6043 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 * action, page address, direction, physical address
6045 * and pointer to a configuration page header
6046 * Page header is updated.
6047 *
6048 * Returns 0 for success
6049 * -EPERM if not allowed due to ISR context
6050 * -EAGAIN if no msg frames currently available
6051 * -EFAULT for non-successful reply or no reply (timeout)
6052 */
6053int
6054mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6055{
6056 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306057 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006058 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306060 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006061 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306062 long timeout;
6063 int ret;
6064 u8 page_type = 0, extend_page;
6065 unsigned long timeleft;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306067 u8 issue_hard_reset = 0;
6068 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006070 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 * to be in ISR context, because that is fatal!
6072 */
6073 in_isr = in_interrupt();
6074 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306075 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076 ioc->name));
6077 return -EPERM;
6078 }
6079
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306080 /* don't send if no chance of success */
6081 if (!ioc->active ||
6082 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6083 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6084 "%s: ioc not operational, %d, %xh\n",
6085 ioc->name, __func__, ioc->active,
6086 mpt_GetIocState(ioc, 0)));
6087 return -EFAULT;
6088 }
6089
6090 retry_config:
6091 mutex_lock(&ioc->mptbase_cmds.mutex);
6092 /* init the internal cmd struct */
6093 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6094 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6095
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 /* Get and Populate a free Frame
6097 */
6098 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306099 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6100 "mpt_config: no msg frames!\n", ioc->name));
6101 ret = -EAGAIN;
6102 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306104
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 pReq = (Config_t *)mf;
6106 pReq->Action = pCfg->action;
6107 pReq->Reserved = 0;
6108 pReq->ChainOffset = 0;
6109 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006110
6111 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112 pReq->ExtPageLength = 0;
6113 pReq->ExtPageType = 0;
6114 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006115
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116 for (ii=0; ii < 8; ii++)
6117 pReq->Reserved2[ii] = 0;
6118
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006119 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6120 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6121 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6122 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6123
6124 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6125 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6126 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6127 pReq->ExtPageType = pExtHdr->ExtPageType;
6128 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6129
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306130 /* Page Length must be treated as a reserved field for the
6131 * extended header.
6132 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006133 pReq->Header.PageLength = 0;
6134 }
6135
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6137
6138 /* Add a SGE to the config request.
6139 */
6140 if (pCfg->dir)
6141 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6142 else
6143 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6144
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306145 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6146 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006147 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306148 page_type = pReq->ExtPageType;
6149 extend_page = 1;
6150 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006151 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306152 page_type = pReq->Header.PageType;
6153 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306156 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6157 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6158 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6159
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306160 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306161 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006162 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306163 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6164 timeout);
6165 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6166 ret = -ETIME;
6167 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6168 "Failed Sending Config request type 0x%x, page 0x%x,"
6169 " action %d, status %xh, time left %ld\n\n",
6170 ioc->name, page_type, pReq->Header.PageNumber,
6171 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6172 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6173 goto out;
6174 if (!timeleft)
6175 issue_hard_reset = 1;
6176 goto out;
6177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306179 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6180 ret = -1;
6181 goto out;
6182 }
6183 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6184 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6185 if (ret == MPI_IOCSTATUS_SUCCESS) {
6186 if (extend_page) {
6187 pCfg->cfghdr.ehdr->ExtPageLength =
6188 le16_to_cpu(pReply->ExtPageLength);
6189 pCfg->cfghdr.ehdr->ExtPageType =
6190 pReply->ExtPageType;
6191 }
6192 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6193 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6194 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6195 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306199 if (retry_count)
6200 printk(MYIOC_s_INFO_FMT "Retry completed "
6201 "ret=0x%x timeleft=%ld\n",
6202 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306204 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6205 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306207out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306209 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6210 mutex_unlock(&ioc->mptbase_cmds.mutex);
6211 if (issue_hard_reset) {
6212 issue_hard_reset = 0;
6213 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6214 ioc->name, __func__);
6215 mpt_HardResetHandler(ioc, CAN_SLEEP);
6216 mpt_free_msg_frame(ioc, mf);
6217 /* attempt one retry for a timed out command */
6218 if (!retry_count) {
6219 printk(MYIOC_s_INFO_FMT
6220 "Attempting Retry Config request"
6221 " type 0x%x, page 0x%x,"
6222 " action %d\n", ioc->name, page_type,
6223 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6224 retry_count++;
6225 goto retry_config;
6226 }
6227 }
6228 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230}
6231
6232/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006233/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234 * mpt_ioc_reset - Base cleanup for hard reset
6235 * @ioc: Pointer to the adapter structure
6236 * @reset_phase: Indicates pre- or post-reset functionality
6237 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006238 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239 */
6240static int
6241mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6242{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306243 switch (reset_phase) {
6244 case MPT_IOC_SETUP_RESET:
6245 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6246 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6247 break;
6248 case MPT_IOC_PRE_RESET:
6249 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6250 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6251 break;
6252 case MPT_IOC_POST_RESET:
6253 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6254 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6255/* wake up mptbase_cmds */
6256 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6257 ioc->mptbase_cmds.status |=
6258 MPT_MGMT_STATUS_DID_IOCRESET;
6259 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306261 break;
6262 default:
6263 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 }
6265
6266 return 1; /* currently means nothing really */
6267}
6268
6269
6270#ifdef CONFIG_PROC_FS /* { */
6271/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6272/*
6273 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6274 */
6275/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006276/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6278 *
6279 * Returns 0 for success, non-zero for failure.
6280 */
6281static int
6282procmpt_create(void)
6283{
6284 struct proc_dir_entry *ent;
6285
6286 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6287 if (mpt_proc_root_dir == NULL)
6288 return -ENOTDIR;
6289
6290 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6291 if (ent)
6292 ent->read_proc = procmpt_summary_read;
6293
6294 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6295 if (ent)
6296 ent->read_proc = procmpt_version_read;
6297
6298 return 0;
6299}
6300
6301/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006302/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6304 *
6305 * Returns 0 for success, non-zero for failure.
6306 */
6307static void
6308procmpt_destroy(void)
6309{
6310 remove_proc_entry("version", mpt_proc_root_dir);
6311 remove_proc_entry("summary", mpt_proc_root_dir);
6312 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6313}
6314
6315/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006316/**
6317 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318 * @buf: Pointer to area to write information
6319 * @start: Pointer to start pointer
6320 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006321 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322 * @eof: Pointer to EOF integer
6323 * @data: Pointer
6324 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006325 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326 * Returns number of characters written to process performing the read.
6327 */
6328static int
6329procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6330{
6331 MPT_ADAPTER *ioc;
6332 char *out = buf;
6333 int len;
6334
6335 if (data) {
6336 int more = 0;
6337
6338 ioc = data;
6339 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6340
6341 out += more;
6342 } else {
6343 list_for_each_entry(ioc, &ioc_list, list) {
6344 int more = 0;
6345
6346 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6347
6348 out += more;
6349 if ((out-buf) >= request)
6350 break;
6351 }
6352 }
6353
6354 len = out - buf;
6355
6356 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6357}
6358
6359/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006360/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361 * procmpt_version_read - Handle read request from /proc/mpt/version.
6362 * @buf: Pointer to area to write information
6363 * @start: Pointer to start pointer
6364 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006365 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366 * @eof: Pointer to EOF integer
6367 * @data: Pointer
6368 *
6369 * Returns number of characters written to process performing the read.
6370 */
6371static int
6372procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6373{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306374 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006375 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376 char *drvname;
6377 int len;
6378
6379 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6380 len += sprintf(buf+len, " Fusion MPT base driver\n");
6381
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006382 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006383 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306385 if (MptCallbacks[cb_idx]) {
6386 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006387 case MPTSPI_DRIVER:
6388 if (!scsi++) drvname = "SPI host";
6389 break;
6390 case MPTFC_DRIVER:
6391 if (!fc++) drvname = "FC host";
6392 break;
6393 case MPTSAS_DRIVER:
6394 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006395 break;
6396 case MPTLAN_DRIVER:
6397 if (!lan++) drvname = "LAN";
6398 break;
6399 case MPTSTM_DRIVER:
6400 if (!targ++) drvname = "SCSI target";
6401 break;
6402 case MPTCTL_DRIVER:
6403 if (!ctl++) drvname = "ioctl";
6404 break;
6405 }
6406
6407 if (drvname)
6408 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6409 }
6410 }
6411
6412 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6413}
6414
6415/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006416/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006417 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6418 * @buf: Pointer to area to write information
6419 * @start: Pointer to start pointer
6420 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006421 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422 * @eof: Pointer to EOF integer
6423 * @data: Pointer
6424 *
6425 * Returns number of characters written to process performing the read.
6426 */
6427static int
6428procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6429{
6430 MPT_ADAPTER *ioc = data;
6431 int len;
6432 char expVer[32];
6433 int sz;
6434 int p;
6435
6436 mpt_get_fw_exp_ver(expVer, ioc);
6437
6438 len = sprintf(buf, "%s:", ioc->name);
6439 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6440 len += sprintf(buf+len, " (f/w download boot flag set)");
6441// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6442// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6443
6444 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6445 ioc->facts.ProductID,
6446 ioc->prod_name);
6447 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6448 if (ioc->facts.FWImageSize)
6449 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6450 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6451 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6452 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6453
6454 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6455 ioc->facts.CurrentHostMfaHighAddr);
6456 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6457 ioc->facts.CurrentSenseBufferHighAddr);
6458
6459 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6460 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6461
6462 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6463 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6464 /*
6465 * Rounding UP to nearest 4-kB boundary here...
6466 */
6467 sz = (ioc->req_sz * ioc->req_depth) + 128;
6468 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6469 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6470 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6471 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6472 4*ioc->facts.RequestFrameSize,
6473 ioc->facts.GlobalCredits);
6474
6475 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6476 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6477 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6478 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6479 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6480 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6481 ioc->facts.CurReplyFrameSize,
6482 ioc->facts.ReplyQueueDepth);
6483
6484 len += sprintf(buf+len, " MaxDevices = %d\n",
6485 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6486 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6487
6488 /* per-port info */
6489 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6490 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6491 p+1,
6492 ioc->facts.NumberOfPorts);
6493 if (ioc->bus_type == FC) {
6494 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6495 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6496 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6497 a[5], a[4], a[3], a[2], a[1], a[0]);
6498 }
6499 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6500 ioc->fc_port_page0[p].WWNN.High,
6501 ioc->fc_port_page0[p].WWNN.Low,
6502 ioc->fc_port_page0[p].WWPN.High,
6503 ioc->fc_port_page0[p].WWPN.Low);
6504 }
6505 }
6506
6507 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6508}
6509
6510#endif /* CONFIG_PROC_FS } */
6511
6512/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6513static void
6514mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6515{
6516 buf[0] ='\0';
6517 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6518 sprintf(buf, " (Exp %02d%02d)",
6519 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6520 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6521
6522 /* insider hack! */
6523 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6524 strcat(buf, " [MDBG]");
6525 }
6526}
6527
6528/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6529/**
6530 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6531 * @ioc: Pointer to MPT_ADAPTER structure
6532 * @buffer: Pointer to buffer where IOC summary info should be written
6533 * @size: Pointer to number of bytes we wrote (set by this routine)
6534 * @len: Offset at which to start writing in buffer
6535 * @showlan: Display LAN stuff?
6536 *
6537 * This routine writes (english readable) ASCII text, which represents
6538 * a summary of IOC information, to a buffer.
6539 */
6540void
6541mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6542{
6543 char expVer[32];
6544 int y;
6545
6546 mpt_get_fw_exp_ver(expVer, ioc);
6547
6548 /*
6549 * Shorter summary of attached ioc's...
6550 */
6551 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6552 ioc->name,
6553 ioc->prod_name,
6554 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6555 ioc->facts.FWVersion.Word,
6556 expVer,
6557 ioc->facts.NumberOfPorts,
6558 ioc->req_depth);
6559
6560 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6561 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6562 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6563 a[5], a[4], a[3], a[2], a[1], a[0]);
6564 }
6565
Linus Torvalds1da177e2005-04-16 15:20:36 -07006566 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006567
6568 if (!ioc->active)
6569 y += sprintf(buffer+len+y, " (disabled)");
6570
6571 y += sprintf(buffer+len+y, "\n");
6572
6573 *size = y;
6574}
6575
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306576
6577/**
6578 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6579 * the kernel
6580 * @ioc: Pointer to MPT_ADAPTER structure
6581 *
6582 **/
6583void
6584mpt_halt_firmware(MPT_ADAPTER *ioc)
6585{
6586 u32 ioc_raw_state;
6587
6588 ioc_raw_state = mpt_GetIocState(ioc, 0);
6589
6590 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6591 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6592 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6593 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6594 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6595 } else {
6596 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6597 panic("%s: Firmware is halted due to command timeout\n",
6598 ioc->name);
6599 }
6600}
6601EXPORT_SYMBOL(mpt_halt_firmware);
6602
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6604/*
6605 * Reset Handling
6606 */
6607/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6608/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006609 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006610 * @ioc: Pointer to MPT_ADAPTER structure
6611 * @sleepFlag: Indicates if sleep or schedule must be called.
6612 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006613 * Issues SCSI Task Management call based on input arg values.
6614 * If TaskMgmt fails, returns associated SCSI request.
6615 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006616 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6617 * or a non-interrupt thread. In the former, must not call schedule().
6618 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006619 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006620 * FW reload/initialization failed.
6621 *
6622 * Returns 0 for SUCCESS or -1 if FAILED.
6623 */
6624int
6625mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6626{
6627 int rc;
6628 unsigned long flags;
6629
Prakash, Sathya436ace72007-07-24 15:42:08 +05306630 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631#ifdef MFCNT
6632 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6633 printk("MF count 0x%x !\n", ioc->mfcnt);
6634#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306635 if (mpt_fwfault_debug)
6636 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006637
6638 /* Reset the adapter. Prevent more than 1 call to
6639 * mpt_do_ioc_recovery at any instant in time.
6640 */
6641 spin_lock_irqsave(&ioc->diagLock, flags);
6642 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6643 spin_unlock_irqrestore(&ioc->diagLock, flags);
6644 return 0;
6645 } else {
6646 ioc->diagPending = 1;
6647 }
6648 spin_unlock_irqrestore(&ioc->diagLock, flags);
6649
6650 /* FIXME: If do_ioc_recovery fails, repeat....
6651 */
6652
6653 /* The SCSI driver needs to adjust timeouts on all current
6654 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006655 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006656 * For all other protocol drivers, this is a no-op.
6657 */
6658 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306659 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006660 int r = 0;
6661
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306662 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6663 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306664 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306665 ioc->name, cb_idx));
6666 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306668 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306669 ioc->name, ioc->alt_ioc->name, cb_idx));
6670 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671 }
6672 }
6673 }
6674 }
6675
6676 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006677 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006678 }
6679 ioc->reload_fw = 0;
6680 if (ioc->alt_ioc)
6681 ioc->alt_ioc->reload_fw = 0;
6682
6683 spin_lock_irqsave(&ioc->diagLock, flags);
6684 ioc->diagPending = 0;
6685 if (ioc->alt_ioc)
6686 ioc->alt_ioc->diagPending = 0;
6687 spin_unlock_irqrestore(&ioc->diagLock, flags);
6688
Prakash, Sathya436ace72007-07-24 15:42:08 +05306689 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006690
6691 return rc;
6692}
6693
6694/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006695static void
6696EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006697{
Eric Moore509e5e52006-04-26 13:22:37 -06006698 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006699
6700 switch(event) {
6701 case MPI_EVENT_NONE:
6702 ds = "None";
6703 break;
6704 case MPI_EVENT_LOG_DATA:
6705 ds = "Log Data";
6706 break;
6707 case MPI_EVENT_STATE_CHANGE:
6708 ds = "State Change";
6709 break;
6710 case MPI_EVENT_UNIT_ATTENTION:
6711 ds = "Unit Attention";
6712 break;
6713 case MPI_EVENT_IOC_BUS_RESET:
6714 ds = "IOC Bus Reset";
6715 break;
6716 case MPI_EVENT_EXT_BUS_RESET:
6717 ds = "External Bus Reset";
6718 break;
6719 case MPI_EVENT_RESCAN:
6720 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006721 break;
6722 case MPI_EVENT_LINK_STATUS_CHANGE:
6723 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6724 ds = "Link Status(FAILURE) Change";
6725 else
6726 ds = "Link Status(ACTIVE) Change";
6727 break;
6728 case MPI_EVENT_LOOP_STATE_CHANGE:
6729 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6730 ds = "Loop State(LIP) Change";
6731 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006732 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733 else
Eric Moore509e5e52006-04-26 13:22:37 -06006734 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735 break;
6736 case MPI_EVENT_LOGOUT:
6737 ds = "Logout";
6738 break;
6739 case MPI_EVENT_EVENT_CHANGE:
6740 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006741 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006743 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006744 break;
6745 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006746 {
6747 u8 ReasonCode = (u8)(evData0 >> 16);
6748 switch (ReasonCode) {
6749 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6750 ds = "Integrated Raid: Volume Created";
6751 break;
6752 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6753 ds = "Integrated Raid: Volume Deleted";
6754 break;
6755 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6756 ds = "Integrated Raid: Volume Settings Changed";
6757 break;
6758 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6759 ds = "Integrated Raid: Volume Status Changed";
6760 break;
6761 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6762 ds = "Integrated Raid: Volume Physdisk Changed";
6763 break;
6764 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6765 ds = "Integrated Raid: Physdisk Created";
6766 break;
6767 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6768 ds = "Integrated Raid: Physdisk Deleted";
6769 break;
6770 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6771 ds = "Integrated Raid: Physdisk Settings Changed";
6772 break;
6773 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6774 ds = "Integrated Raid: Physdisk Status Changed";
6775 break;
6776 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6777 ds = "Integrated Raid: Domain Validation Needed";
6778 break;
6779 case MPI_EVENT_RAID_RC_SMART_DATA :
6780 ds = "Integrated Raid; Smart Data";
6781 break;
6782 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6783 ds = "Integrated Raid: Replace Action Started";
6784 break;
6785 default:
6786 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006787 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006788 }
6789 break;
6790 }
6791 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6792 ds = "SCSI Device Status Change";
6793 break;
6794 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6795 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006796 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006797 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006798 u8 ReasonCode = (u8)(evData0 >> 16);
6799 switch (ReasonCode) {
6800 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006801 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006802 "SAS Device Status Change: Added: "
6803 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006804 break;
6805 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006806 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006807 "SAS Device Status Change: Deleted: "
6808 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006809 break;
6810 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006811 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006812 "SAS Device Status Change: SMART Data: "
6813 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006814 break;
6815 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006816 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006817 "SAS Device Status Change: No Persistancy: "
6818 "id=%d channel=%d", id, channel);
6819 break;
6820 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6821 snprintf(evStr, EVENT_DESCR_STR_SZ,
6822 "SAS Device Status Change: Unsupported Device "
6823 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006824 break;
6825 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6826 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006827 "SAS Device Status Change: Internal Device "
6828 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006829 break;
6830 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6831 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006832 "SAS Device Status Change: Internal Task "
6833 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006834 break;
6835 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6836 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006837 "SAS Device Status Change: Internal Abort "
6838 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006839 break;
6840 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6841 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006842 "SAS Device Status Change: Internal Clear "
6843 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006844 break;
6845 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6846 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006847 "SAS Device Status Change: Internal Query "
6848 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006849 break;
6850 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006851 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006852 "SAS Device Status Change: Unknown: "
6853 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006854 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006855 }
6856 break;
6857 }
6858 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6859 ds = "Bus Timer Expired";
6860 break;
6861 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006862 {
6863 u16 curr_depth = (u16)(evData0 >> 16);
6864 u8 channel = (u8)(evData0 >> 8);
6865 u8 id = (u8)(evData0);
6866
6867 snprintf(evStr, EVENT_DESCR_STR_SZ,
6868 "Queue Full: channel=%d id=%d depth=%d",
6869 channel, id, curr_depth);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006870 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006871 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006872 case MPI_EVENT_SAS_SES:
6873 ds = "SAS SES Event";
6874 break;
6875 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6876 ds = "Persistent Table Full";
6877 break;
6878 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006879 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006880 u8 LinkRates = (u8)(evData0 >> 8);
6881 u8 PhyNumber = (u8)(evData0);
6882 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6883 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6884 switch (LinkRates) {
6885 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006886 snprintf(evStr, EVENT_DESCR_STR_SZ,
6887 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006888 " Rate Unknown",PhyNumber);
6889 break;
6890 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006891 snprintf(evStr, EVENT_DESCR_STR_SZ,
6892 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006893 " Phy Disabled",PhyNumber);
6894 break;
6895 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006896 snprintf(evStr, EVENT_DESCR_STR_SZ,
6897 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006898 " Failed Speed Nego",PhyNumber);
6899 break;
6900 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006901 snprintf(evStr, EVENT_DESCR_STR_SZ,
6902 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006903 " Sata OOB Completed",PhyNumber);
6904 break;
6905 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006906 snprintf(evStr, EVENT_DESCR_STR_SZ,
6907 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006908 " Rate 1.5 Gbps",PhyNumber);
6909 break;
6910 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006911 snprintf(evStr, EVENT_DESCR_STR_SZ,
6912 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006913 " Rate 3.0 Gpbs",PhyNumber);
6914 break;
6915 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006916 snprintf(evStr, EVENT_DESCR_STR_SZ,
6917 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006918 break;
6919 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006920 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006921 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006922 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6923 ds = "SAS Discovery Error";
6924 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006925 case MPI_EVENT_IR_RESYNC_UPDATE:
6926 {
6927 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006928 snprintf(evStr, EVENT_DESCR_STR_SZ,
6929 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006930 break;
6931 }
6932 case MPI_EVENT_IR2:
6933 {
6934 u8 ReasonCode = (u8)(evData0 >> 16);
6935 switch (ReasonCode) {
6936 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6937 ds = "IR2: LD State Changed";
6938 break;
6939 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6940 ds = "IR2: PD State Changed";
6941 break;
6942 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6943 ds = "IR2: Bad Block Table Full";
6944 break;
6945 case MPI_EVENT_IR2_RC_PD_INSERTED:
6946 ds = "IR2: PD Inserted";
6947 break;
6948 case MPI_EVENT_IR2_RC_PD_REMOVED:
6949 ds = "IR2: PD Removed";
6950 break;
6951 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6952 ds = "IR2: Foreign CFG Detected";
6953 break;
6954 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6955 ds = "IR2: Rebuild Medium Error";
6956 break;
6957 default:
6958 ds = "IR2";
6959 break;
6960 }
6961 break;
6962 }
6963 case MPI_EVENT_SAS_DISCOVERY:
6964 {
6965 if (evData0)
6966 ds = "SAS Discovery: Start";
6967 else
6968 ds = "SAS Discovery: Stop";
6969 break;
6970 }
6971 case MPI_EVENT_LOG_ENTRY_ADDED:
6972 ds = "SAS Log Entry Added";
6973 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006974
Eric Moorec6c727a2007-01-29 09:44:54 -07006975 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6976 {
6977 u8 phy_num = (u8)(evData0);
6978 u8 port_num = (u8)(evData0 >> 8);
6979 u8 port_width = (u8)(evData0 >> 16);
6980 u8 primative = (u8)(evData0 >> 24);
6981 snprintf(evStr, EVENT_DESCR_STR_SZ,
6982 "SAS Broadcase Primative: phy=%d port=%d "
6983 "width=%d primative=0x%02x",
6984 phy_num, port_num, port_width, primative);
6985 break;
6986 }
6987
6988 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6989 {
6990 u8 reason = (u8)(evData0);
6991 u8 port_num = (u8)(evData0 >> 8);
6992 u16 handle = le16_to_cpu(evData0 >> 16);
6993
6994 snprintf(evStr, EVENT_DESCR_STR_SZ,
6995 "SAS Initiator Device Status Change: reason=0x%02x "
6996 "port=%d handle=0x%04x",
6997 reason, port_num, handle);
6998 break;
6999 }
7000
7001 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7002 {
7003 u8 max_init = (u8)(evData0);
7004 u8 current_init = (u8)(evData0 >> 8);
7005
7006 snprintf(evStr, EVENT_DESCR_STR_SZ,
7007 "SAS Initiator Device Table Overflow: max initiators=%02d "
7008 "current initators=%02d",
7009 max_init, current_init);
7010 break;
7011 }
7012 case MPI_EVENT_SAS_SMP_ERROR:
7013 {
7014 u8 status = (u8)(evData0);
7015 u8 port_num = (u8)(evData0 >> 8);
7016 u8 result = (u8)(evData0 >> 16);
7017
7018 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7019 snprintf(evStr, EVENT_DESCR_STR_SZ,
7020 "SAS SMP Error: port=%d result=0x%02x",
7021 port_num, result);
7022 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7023 snprintf(evStr, EVENT_DESCR_STR_SZ,
7024 "SAS SMP Error: port=%d : CRC Error",
7025 port_num);
7026 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7027 snprintf(evStr, EVENT_DESCR_STR_SZ,
7028 "SAS SMP Error: port=%d : Timeout",
7029 port_num);
7030 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7031 snprintf(evStr, EVENT_DESCR_STR_SZ,
7032 "SAS SMP Error: port=%d : No Destination",
7033 port_num);
7034 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7035 snprintf(evStr, EVENT_DESCR_STR_SZ,
7036 "SAS SMP Error: port=%d : Bad Destination",
7037 port_num);
7038 else
7039 snprintf(evStr, EVENT_DESCR_STR_SZ,
7040 "SAS SMP Error: port=%d : status=0x%02x",
7041 port_num, status);
7042 break;
7043 }
7044
Linus Torvalds1da177e2005-04-16 15:20:36 -07007045 /*
7046 * MPT base "custom" events may be added here...
7047 */
7048 default:
7049 ds = "Unknown";
7050 break;
7051 }
Eric Moore509e5e52006-04-26 13:22:37 -06007052 if (ds)
7053 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007054}
7055
7056/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007057/**
7058 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007059 * @ioc: Pointer to MPT_ADAPTER structure
7060 * @pEventReply: Pointer to EventNotification reply frame
7061 * @evHandlers: Pointer to integer, number of event handlers
7062 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007063 * Routes a received EventNotificationReply to all currently registered
7064 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065 * Returns sum of event handlers return values.
7066 */
7067static int
7068ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7069{
7070 u16 evDataLen;
7071 u32 evData0 = 0;
7072// u32 evCtx;
7073 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307074 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007075 int r = 0;
7076 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06007077 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007078 u8 event;
7079
7080 /*
7081 * Do platform normalization of values
7082 */
7083 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7084// evCtx = le32_to_cpu(pEventReply->EventContext);
7085 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7086 if (evDataLen) {
7087 evData0 = le32_to_cpu(pEventReply->Data[0]);
7088 }
7089
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007090 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05307091 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007092 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07007093 event,
7094 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095
Prakash, Sathya436ace72007-07-24 15:42:08 +05307096#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06007097 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7098 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007099 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05307100 devtverboseprintk(ioc, printk(" %08x",
7101 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06007102 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007103#endif
7104
7105 /*
7106 * Do general / base driver event processing
7107 */
7108 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007109 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7110 if (evDataLen) {
7111 u8 evState = evData0 & 0xFF;
7112
7113 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7114
7115 /* Update EventState field in cached IocFacts */
7116 if (ioc->facts.Function) {
7117 ioc->facts.EventState = evState;
7118 }
7119 }
7120 break;
Moore, Ericece50912006-01-16 18:53:19 -07007121 case MPI_EVENT_INTEGRATED_RAID:
7122 mptbase_raid_process_event_data(ioc,
7123 (MpiEventDataRaid_t *)pEventReply->Data);
7124 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007125 default:
7126 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007127 }
7128
7129 /*
7130 * Should this event be logged? Events are written sequentially.
7131 * When buffer is full, start again at the top.
7132 */
7133 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7134 int idx;
7135
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007136 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137
7138 ioc->events[idx].event = event;
7139 ioc->events[idx].eventContext = ioc->eventContext;
7140
7141 for (ii = 0; ii < 2; ii++) {
7142 if (ii < evDataLen)
7143 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7144 else
7145 ioc->events[idx].data[ii] = 0;
7146 }
7147
7148 ioc->eventContext++;
7149 }
7150
7151
7152 /*
7153 * Call each currently registered protocol event handler.
7154 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007155 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307156 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307157 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307158 ioc->name, cb_idx));
7159 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007160 handlers++;
7161 }
7162 }
7163 /* FIXME? Examine results here? */
7164
7165 /*
7166 * If needed, send (a single) EventAck.
7167 */
7168 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307169 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007170 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007171 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307172 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007173 ioc->name, ii));
7174 }
7175 }
7176
7177 *evHandlers = handlers;
7178 return r;
7179}
7180
7181/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007182/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7184 * @ioc: Pointer to MPT_ADAPTER structure
7185 * @log_info: U32 LogInfo reply word from the IOC
7186 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007187 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188 */
7189static void
7190mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7191{
Eric Moore7c431e52007-06-13 16:34:36 -06007192 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007193
Eric Moore7c431e52007-06-13 16:34:36 -06007194 switch (log_info & 0xFF000000) {
7195 case MPI_IOCLOGINFO_FC_INIT_BASE:
7196 desc = "FCP Initiator";
7197 break;
7198 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7199 desc = "FCP Target";
7200 break;
7201 case MPI_IOCLOGINFO_FC_LAN_BASE:
7202 desc = "LAN";
7203 break;
7204 case MPI_IOCLOGINFO_FC_MSG_BASE:
7205 desc = "MPI Message Layer";
7206 break;
7207 case MPI_IOCLOGINFO_FC_LINK_BASE:
7208 desc = "FC Link";
7209 break;
7210 case MPI_IOCLOGINFO_FC_CTX_BASE:
7211 desc = "Context Manager";
7212 break;
7213 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7214 desc = "Invalid Field Offset";
7215 break;
7216 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7217 desc = "State Change Info";
7218 break;
7219 }
7220
7221 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7222 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007223}
7224
7225/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007226/**
Moore, Eric335a9412006-01-17 17:06:23 -07007227 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007228 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007229 * @log_info: U32 LogInfo word from the IOC
7230 *
7231 * Refer to lsi/sp_log.h.
7232 */
7233static void
Moore, Eric335a9412006-01-17 17:06:23 -07007234mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007235{
7236 u32 info = log_info & 0x00FF0000;
7237 char *desc = "unknown";
7238
7239 switch (info) {
7240 case 0x00010000:
7241 desc = "bug! MID not found";
7242 if (ioc->reload_fw == 0)
7243 ioc->reload_fw++;
7244 break;
7245
7246 case 0x00020000:
7247 desc = "Parity Error";
7248 break;
7249
7250 case 0x00030000:
7251 desc = "ASYNC Outbound Overrun";
7252 break;
7253
7254 case 0x00040000:
7255 desc = "SYNC Offset Error";
7256 break;
7257
7258 case 0x00050000:
7259 desc = "BM Change";
7260 break;
7261
7262 case 0x00060000:
7263 desc = "Msg In Overflow";
7264 break;
7265
7266 case 0x00070000:
7267 desc = "DMA Error";
7268 break;
7269
7270 case 0x00080000:
7271 desc = "Outbound DMA Overrun";
7272 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007273
Linus Torvalds1da177e2005-04-16 15:20:36 -07007274 case 0x00090000:
7275 desc = "Task Management";
7276 break;
7277
7278 case 0x000A0000:
7279 desc = "Device Problem";
7280 break;
7281
7282 case 0x000B0000:
7283 desc = "Invalid Phase Change";
7284 break;
7285
7286 case 0x000C0000:
7287 desc = "Untagged Table Size";
7288 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007289
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290 }
7291
7292 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7293}
7294
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007295/* strings for sas loginfo */
7296 static char *originator_str[] = {
7297 "IOP", /* 00h */
7298 "PL", /* 01h */
7299 "IR" /* 02h */
7300 };
7301 static char *iop_code_str[] = {
7302 NULL, /* 00h */
7303 "Invalid SAS Address", /* 01h */
7304 NULL, /* 02h */
7305 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007306 "Diag Message Error", /* 04h */
7307 "Task Terminated", /* 05h */
7308 "Enclosure Management", /* 06h */
7309 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007310 };
7311 static char *pl_code_str[] = {
7312 NULL, /* 00h */
7313 "Open Failure", /* 01h */
7314 "Invalid Scatter Gather List", /* 02h */
7315 "Wrong Relative Offset or Frame Length", /* 03h */
7316 "Frame Transfer Error", /* 04h */
7317 "Transmit Frame Connected Low", /* 05h */
7318 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7319 "SATA Read Log Receive Data Error", /* 07h */
7320 "SATA NCQ Fail All Commands After Error", /* 08h */
7321 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7322 "Receive Frame Invalid Message", /* 0Ah */
7323 "Receive Context Message Valid Error", /* 0Bh */
7324 "Receive Frame Current Frame Error", /* 0Ch */
7325 "SATA Link Down", /* 0Dh */
7326 "Discovery SATA Init W IOS", /* 0Eh */
7327 "Config Invalid Page", /* 0Fh */
7328 "Discovery SATA Init Timeout", /* 10h */
7329 "Reset", /* 11h */
7330 "Abort", /* 12h */
7331 "IO Not Yet Executed", /* 13h */
7332 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007333 "Persistent Reservation Out Not Affiliation "
7334 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007335 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007336 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007337 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007338 NULL, /* 19h */
7339 NULL, /* 1Ah */
7340 NULL, /* 1Bh */
7341 NULL, /* 1Ch */
7342 NULL, /* 1Dh */
7343 NULL, /* 1Eh */
7344 NULL, /* 1Fh */
7345 "Enclosure Management" /* 20h */
7346 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007347 static char *ir_code_str[] = {
7348 "Raid Action Error", /* 00h */
7349 NULL, /* 00h */
7350 NULL, /* 01h */
7351 NULL, /* 02h */
7352 NULL, /* 03h */
7353 NULL, /* 04h */
7354 NULL, /* 05h */
7355 NULL, /* 06h */
7356 NULL /* 07h */
7357 };
7358 static char *raid_sub_code_str[] = {
7359 NULL, /* 00h */
7360 "Volume Creation Failed: Data Passed too "
7361 "Large", /* 01h */
7362 "Volume Creation Failed: Duplicate Volumes "
7363 "Attempted", /* 02h */
7364 "Volume Creation Failed: Max Number "
7365 "Supported Volumes Exceeded", /* 03h */
7366 "Volume Creation Failed: DMA Error", /* 04h */
7367 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7368 "Volume Creation Failed: Error Reading "
7369 "MFG Page 4", /* 06h */
7370 "Volume Creation Failed: Creating Internal "
7371 "Structures", /* 07h */
7372 NULL, /* 08h */
7373 NULL, /* 09h */
7374 NULL, /* 0Ah */
7375 NULL, /* 0Bh */
7376 NULL, /* 0Ch */
7377 NULL, /* 0Dh */
7378 NULL, /* 0Eh */
7379 NULL, /* 0Fh */
7380 "Activation failed: Already Active Volume", /* 10h */
7381 "Activation failed: Unsupported Volume Type", /* 11h */
7382 "Activation failed: Too Many Active Volumes", /* 12h */
7383 "Activation failed: Volume ID in Use", /* 13h */
7384 "Activation failed: Reported Failure", /* 14h */
7385 "Activation failed: Importing a Volume", /* 15h */
7386 NULL, /* 16h */
7387 NULL, /* 17h */
7388 NULL, /* 18h */
7389 NULL, /* 19h */
7390 NULL, /* 1Ah */
7391 NULL, /* 1Bh */
7392 NULL, /* 1Ch */
7393 NULL, /* 1Dh */
7394 NULL, /* 1Eh */
7395 NULL, /* 1Fh */
7396 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7397 "Phys Disk failed: Data Passed too Large", /* 21h */
7398 "Phys Disk failed: DMA Error", /* 22h */
7399 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7400 "Phys Disk failed: Creating Phys Disk Config "
7401 "Page", /* 24h */
7402 NULL, /* 25h */
7403 NULL, /* 26h */
7404 NULL, /* 27h */
7405 NULL, /* 28h */
7406 NULL, /* 29h */
7407 NULL, /* 2Ah */
7408 NULL, /* 2Bh */
7409 NULL, /* 2Ch */
7410 NULL, /* 2Dh */
7411 NULL, /* 2Eh */
7412 NULL, /* 2Fh */
7413 "Compatibility Error: IR Disabled", /* 30h */
7414 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7415 "Compatibility Error: Device not Direct Access "
7416 "Device ", /* 32h */
7417 "Compatibility Error: Removable Device Found", /* 33h */
7418 "Compatibility Error: Device SCSI Version not "
7419 "2 or Higher", /* 34h */
7420 "Compatibility Error: SATA Device, 48 BIT LBA "
7421 "not Supported", /* 35h */
7422 "Compatibility Error: Device doesn't have "
7423 "512 Byte Block Sizes", /* 36h */
7424 "Compatibility Error: Volume Type Check Failed", /* 37h */
7425 "Compatibility Error: Volume Type is "
7426 "Unsupported by FW", /* 38h */
7427 "Compatibility Error: Disk Drive too Small for "
7428 "use in Volume", /* 39h */
7429 "Compatibility Error: Phys Disk for Create "
7430 "Volume not Found", /* 3Ah */
7431 "Compatibility Error: Too Many or too Few "
7432 "Disks for Volume Type", /* 3Bh */
7433 "Compatibility Error: Disk stripe Sizes "
7434 "Must be 64KB", /* 3Ch */
7435 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7436 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007437
7438/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007439/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007440 * mpt_sas_log_info - Log information returned from SAS IOC.
7441 * @ioc: Pointer to MPT_ADAPTER structure
7442 * @log_info: U32 LogInfo reply word from the IOC
7443 *
7444 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007445 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007446static void
7447mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7448{
7449union loginfo_type {
7450 u32 loginfo;
7451 struct {
7452 u32 subcode:16;
7453 u32 code:8;
7454 u32 originator:4;
7455 u32 bus_type:4;
7456 }dw;
7457};
7458 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007459 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007460 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007461 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007462
7463 sas_loginfo.loginfo = log_info;
7464 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007465 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007466 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007467
7468 originator_desc = originator_str[sas_loginfo.dw.originator];
7469
7470 switch (sas_loginfo.dw.originator) {
7471
7472 case 0: /* IOP */
7473 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007474 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007475 code_desc = iop_code_str[sas_loginfo.dw.code];
7476 break;
7477 case 1: /* PL */
7478 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007479 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007480 code_desc = pl_code_str[sas_loginfo.dw.code];
7481 break;
7482 case 2: /* IR */
7483 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007484 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007485 break;
7486 code_desc = ir_code_str[sas_loginfo.dw.code];
7487 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007488 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007489 break;
7490 if (sas_loginfo.dw.code == 0)
7491 sub_code_desc =
7492 raid_sub_code_str[sas_loginfo.dw.subcode];
7493 break;
7494 default:
7495 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007496 }
7497
Eric Moorec6c727a2007-01-29 09:44:54 -07007498 if (sub_code_desc != NULL)
7499 printk(MYIOC_s_INFO_FMT
7500 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7501 " SubCode={%s}\n",
7502 ioc->name, log_info, originator_desc, code_desc,
7503 sub_code_desc);
7504 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007505 printk(MYIOC_s_INFO_FMT
7506 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7507 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007508 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007509 sas_loginfo.dw.subcode);
7510 else
7511 printk(MYIOC_s_INFO_FMT
7512 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7513 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007514 ioc->name, log_info, originator_desc,
7515 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007516}
7517
Linus Torvalds1da177e2005-04-16 15:20:36 -07007518/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007519/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007520 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7521 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007522 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007523 * @mf: Pointer to MPT request frame
7524 *
7525 * Refer to lsi/mpi.h.
7526 **/
7527static void
7528mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7529{
7530 Config_t *pReq = (Config_t *)mf;
7531 char extend_desc[EVENT_DESCR_STR_SZ];
7532 char *desc = NULL;
7533 u32 form;
7534 u8 page_type;
7535
7536 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7537 page_type = pReq->ExtPageType;
7538 else
7539 page_type = pReq->Header.PageType;
7540
7541 /*
7542 * ignore invalid page messages for GET_NEXT_HANDLE
7543 */
7544 form = le32_to_cpu(pReq->PageAddress);
7545 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7546 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7547 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7548 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7549 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7550 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7551 return;
7552 }
7553 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7554 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7555 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7556 return;
7557 }
7558
7559 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7560 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7561 page_type, pReq->Header.PageNumber, pReq->Action, form);
7562
7563 switch (ioc_status) {
7564
7565 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7566 desc = "Config Page Invalid Action";
7567 break;
7568
7569 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7570 desc = "Config Page Invalid Type";
7571 break;
7572
7573 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7574 desc = "Config Page Invalid Page";
7575 break;
7576
7577 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7578 desc = "Config Page Invalid Data";
7579 break;
7580
7581 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7582 desc = "Config Page No Defaults";
7583 break;
7584
7585 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7586 desc = "Config Page Can't Commit";
7587 break;
7588 }
7589
7590 if (!desc)
7591 return;
7592
Eric Moore29dd3602007-09-14 18:46:51 -06007593 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7594 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007595}
7596
7597/**
7598 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007599 * @ioc: Pointer to MPT_ADAPTER structure
7600 * @ioc_status: U32 IOCStatus word from IOC
7601 * @mf: Pointer to MPT request frame
7602 *
7603 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007604 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007606mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007607{
7608 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007609 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007610
7611 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007612
7613/****************************************************************************/
7614/* Common IOCStatus values for all replies */
7615/****************************************************************************/
7616
Linus Torvalds1da177e2005-04-16 15:20:36 -07007617 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7618 desc = "Invalid Function";
7619 break;
7620
7621 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7622 desc = "Busy";
7623 break;
7624
7625 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7626 desc = "Invalid SGL";
7627 break;
7628
7629 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7630 desc = "Internal Error";
7631 break;
7632
7633 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7634 desc = "Reserved";
7635 break;
7636
7637 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7638 desc = "Insufficient Resources";
7639 break;
7640
7641 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7642 desc = "Invalid Field";
7643 break;
7644
7645 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7646 desc = "Invalid State";
7647 break;
7648
Eric Moorec6c727a2007-01-29 09:44:54 -07007649/****************************************************************************/
7650/* Config IOCStatus values */
7651/****************************************************************************/
7652
Linus Torvalds1da177e2005-04-16 15:20:36 -07007653 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7654 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7655 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7656 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7657 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7658 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007659 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007660 break;
7661
Eric Moorec6c727a2007-01-29 09:44:54 -07007662/****************************************************************************/
7663/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7664/* */
7665/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7666/* */
7667/****************************************************************************/
7668
Linus Torvalds1da177e2005-04-16 15:20:36 -07007669 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007670 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007671 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7672 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7673 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7674 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007675 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007676 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007679 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007680 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007681 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007682 break;
7683
Eric Moorec6c727a2007-01-29 09:44:54 -07007684/****************************************************************************/
7685/* SCSI Target values */
7686/****************************************************************************/
7687
7688 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7689 desc = "Target: Priority IO";
7690 break;
7691
7692 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7693 desc = "Target: Invalid Port";
7694 break;
7695
7696 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7697 desc = "Target Invalid IO Index:";
7698 break;
7699
7700 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7701 desc = "Target: Aborted";
7702 break;
7703
7704 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7705 desc = "Target: No Conn Retryable";
7706 break;
7707
7708 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7709 desc = "Target: No Connection";
7710 break;
7711
7712 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7713 desc = "Target: Transfer Count Mismatch";
7714 break;
7715
7716 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7717 desc = "Target: STS Data not Sent";
7718 break;
7719
7720 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7721 desc = "Target: Data Offset Error";
7722 break;
7723
7724 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7725 desc = "Target: Too Much Write Data";
7726 break;
7727
7728 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7729 desc = "Target: IU Too Short";
7730 break;
7731
7732 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7733 desc = "Target: ACK NAK Timeout";
7734 break;
7735
7736 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7737 desc = "Target: Nak Received";
7738 break;
7739
7740/****************************************************************************/
7741/* Fibre Channel Direct Access values */
7742/****************************************************************************/
7743
7744 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7745 desc = "FC: Aborted";
7746 break;
7747
7748 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7749 desc = "FC: RX ID Invalid";
7750 break;
7751
7752 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7753 desc = "FC: DID Invalid";
7754 break;
7755
7756 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7757 desc = "FC: Node Logged Out";
7758 break;
7759
7760 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7761 desc = "FC: Exchange Canceled";
7762 break;
7763
7764/****************************************************************************/
7765/* LAN values */
7766/****************************************************************************/
7767
7768 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7769 desc = "LAN: Device not Found";
7770 break;
7771
7772 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7773 desc = "LAN: Device Failure";
7774 break;
7775
7776 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7777 desc = "LAN: Transmit Error";
7778 break;
7779
7780 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7781 desc = "LAN: Transmit Aborted";
7782 break;
7783
7784 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7785 desc = "LAN: Receive Error";
7786 break;
7787
7788 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7789 desc = "LAN: Receive Aborted";
7790 break;
7791
7792 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7793 desc = "LAN: Partial Packet";
7794 break;
7795
7796 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7797 desc = "LAN: Canceled";
7798 break;
7799
7800/****************************************************************************/
7801/* Serial Attached SCSI values */
7802/****************************************************************************/
7803
7804 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7805 desc = "SAS: SMP Request Failed";
7806 break;
7807
7808 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7809 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007810 break;
7811
7812 default:
7813 desc = "Others";
7814 break;
7815 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007816
7817 if (!desc)
7818 return;
7819
Eric Moore29dd3602007-09-14 18:46:51 -06007820 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7821 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007822}
7823
7824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007825EXPORT_SYMBOL(mpt_attach);
7826EXPORT_SYMBOL(mpt_detach);
7827#ifdef CONFIG_PM
7828EXPORT_SYMBOL(mpt_resume);
7829EXPORT_SYMBOL(mpt_suspend);
7830#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007831EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007832EXPORT_SYMBOL(mpt_register);
7833EXPORT_SYMBOL(mpt_deregister);
7834EXPORT_SYMBOL(mpt_event_register);
7835EXPORT_SYMBOL(mpt_event_deregister);
7836EXPORT_SYMBOL(mpt_reset_register);
7837EXPORT_SYMBOL(mpt_reset_deregister);
7838EXPORT_SYMBOL(mpt_device_driver_register);
7839EXPORT_SYMBOL(mpt_device_driver_deregister);
7840EXPORT_SYMBOL(mpt_get_msg_frame);
7841EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307842EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007843EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007844EXPORT_SYMBOL(mpt_send_handshake_request);
7845EXPORT_SYMBOL(mpt_verify_adapter);
7846EXPORT_SYMBOL(mpt_GetIocState);
7847EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007848EXPORT_SYMBOL(mpt_HardResetHandler);
7849EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007850EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007851EXPORT_SYMBOL(mpt_alloc_fw_memory);
7852EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007853EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007854EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007855
Linus Torvalds1da177e2005-04-16 15:20:36 -07007856/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007857/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007858 * fusion_init - Fusion MPT base driver initialization routine.
7859 *
7860 * Returns 0 for success, non-zero for failure.
7861 */
7862static int __init
7863fusion_init(void)
7864{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307865 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007866
7867 show_mptmod_ver(my_NAME, my_VERSION);
7868 printk(KERN_INFO COPYRIGHT "\n");
7869
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307870 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7871 MptCallbacks[cb_idx] = NULL;
7872 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7873 MptEvHandlers[cb_idx] = NULL;
7874 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007875 }
7876
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007877 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007878 * EventNotification handling.
7879 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05307880 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007881
7882 /* Register for hard reset handling callbacks.
7883 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307884 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007885
7886#ifdef CONFIG_PROC_FS
7887 (void) procmpt_create();
7888#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007889 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007890}
7891
7892/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007893/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007894 * fusion_exit - Perform driver unload cleanup.
7895 *
7896 * This routine frees all resources associated with each MPT adapter
7897 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7898 */
7899static void __exit
7900fusion_exit(void)
7901{
7902
Linus Torvalds1da177e2005-04-16 15:20:36 -07007903 mpt_reset_deregister(mpt_base_index);
7904
7905#ifdef CONFIG_PROC_FS
7906 procmpt_destroy();
7907#endif
7908}
7909
Linus Torvalds1da177e2005-04-16 15:20:36 -07007910module_init(fusion_init);
7911module_exit(fusion_exit);