blob: 5382b5a44affe0a4a4a6551c34c7af17d06ce0c5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05308 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053082
83static int mpt_msi_enable_spi;
84module_param(mpt_msi_enable_spi, int, 0);
85MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
86 controllers (default=0)");
87
88static int mpt_msi_enable_fc;
89module_param(mpt_msi_enable_fc, int, 0);
90MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
91 controllers (default=0)");
92
93static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080094module_param(mpt_msi_enable_sas, int, 0);
Kashyap, Desaie3829682009-01-08 14:27:16 +053095MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
Yinghai Lu5ce78682009-02-18 11:25:32 -080096 controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053097
Christoph Hellwig4ddce142006-01-17 13:44:29 +000098
Eric Moore793955f2007-01-29 09:42:20 -070099static int mpt_channel_mapping;
100module_param(mpt_channel_mapping, int, 0);
101MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
102
Prakash, Sathya436ace72007-07-24 15:42:08 +0530103static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400104static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
105module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
106 &mpt_debug_level, 0600);
Kashyap, Desaie3829682009-01-08 14:27:16 +0530107MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
108 - (default=0)");
109
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530110int mpt_fwfault_debug;
111EXPORT_SYMBOL(mpt_fwfault_debug);
112module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
113 &mpt_fwfault_debug, 0600);
114MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
115 " and halt Firmware on fault - (default=0)");
116
117
Prakash, Sathya436ace72007-07-24 15:42:08 +0530118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#ifdef MFCNT
120static int mfcounter = 0;
121#define PRINT_MF_COUNT 20000
122#endif
123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * Public data...
127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129#define WHOINIT_UNKNOWN 0xAA
130
131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
132/*
133 * Private data...
134 */
135 /* Adapter link list */
136LIST_HEAD(ioc_list);
137 /* Callback lookup table */
138static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
139 /* Protocol driver class lookup table */
140static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Event handler lookup table */
142static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
143 /* Reset handler lookup table */
144static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
146
Erik Ekmane47c11c2009-12-14 21:21:56 +0100147#ifdef CONFIG_PROC_FS
148static struct proc_dir_entry *mpt_proc_root_dir;
149#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530151/*
152 * Driver Callback Index's
153 */
154static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
155static u8 last_drv_idx;
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
158/*
159 * Forward protos...
160 */
David Howells7d12e782006-10-05 14:55:46 +0100161static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530162static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
163 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
165 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
166 int sleepFlag);
167static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
168static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
169static void mpt_adapter_disable(MPT_ADAPTER *ioc);
170static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
171
172static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
173static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
175static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
176static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
177static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
178static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200179static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
181static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
182static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
183static int PrimeIocFifos(MPT_ADAPTER *ioc);
184static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
185static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
187static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200189int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
191static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
192static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
193static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530194static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530195static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
196 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200198static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
199static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201#ifdef CONFIG_PROC_FS
202static int procmpt_summary_read(char *buf, char **start, off_t offset,
203 int request, int *eof, void *data);
204static int procmpt_version_read(char *buf, char **start, off_t offset,
205 int request, int *eof, void *data);
206static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
207 int request, int *eof, void *data);
208#endif
209static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
210
Kashyap, Desaifd761752009-05-29 16:39:06 +0530211static int ProcessEventNotification(MPT_ADAPTER *ioc,
212 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700213static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700215static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600216static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700217static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700218static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221static int __init fusion_init (void);
222static void __exit fusion_exit (void);
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224#define CHIPREG_READ32(addr) readl_relaxed(addr)
225#define CHIPREG_READ32_dmasync(addr) readl(addr)
226#define CHIPREG_WRITE32(addr,val) writel(val, addr)
227#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
228#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
229
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600230static void
231pci_disable_io_access(struct pci_dev *pdev)
232{
233 u16 command_reg;
234
235 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
236 command_reg &= ~1;
237 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
238}
239
240static void
241pci_enable_io_access(struct pci_dev *pdev)
242{
243 u16 command_reg;
244
245 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
246 command_reg |= 1;
247 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
248}
249
James Bottomleydb47c2d2007-07-28 13:40:21 -0400250static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
251{
252 int ret = param_set_int(val, kp);
253 MPT_ADAPTER *ioc;
254
255 if (ret)
256 return ret;
257
258 list_for_each_entry(ioc, &ioc_list, list)
259 ioc->debug_level = mpt_debug_level;
260 return 0;
261}
262
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530263/**
264 * mpt_get_cb_idx - obtain cb_idx for registered driver
265 * @dclass: class driver enum
266 *
267 * Returns cb_idx, or zero means it wasn't found
268 **/
269static u8
270mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
271{
272 u8 cb_idx;
273
274 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
275 if (MptDriverClass[cb_idx] == dclass)
276 return cb_idx;
277 return 0;
278}
279
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530280/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530281 * mpt_is_discovery_complete - determine if discovery has completed
282 * @ioc: per adatper instance
283 *
284 * Returns 1 when discovery completed, else zero.
285 */
286static int
287mpt_is_discovery_complete(MPT_ADAPTER *ioc)
288{
289 ConfigExtendedPageHeader_t hdr;
290 CONFIGPARMS cfg;
291 SasIOUnitPage0_t *buffer;
292 dma_addr_t dma_handle;
293 int rc = 0;
294
295 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
296 memset(&cfg, 0, sizeof(CONFIGPARMS));
297 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
298 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
299 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
300 cfg.cfghdr.ehdr = &hdr;
301 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
302
303 if ((mpt_config(ioc, &cfg)))
304 goto out;
305 if (!hdr.ExtPageLength)
306 goto out;
307
308 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
309 &dma_handle);
310 if (!buffer)
311 goto out;
312
313 cfg.physAddr = dma_handle;
314 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
315
316 if ((mpt_config(ioc, &cfg)))
317 goto out_free_consistent;
318
319 if (!(buffer->PhyData[0].PortFlags &
320 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
321 rc = 1;
322
323 out_free_consistent:
324 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
325 buffer, dma_handle);
326 out:
327 return rc;
328}
329
330/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530331 * mpt_fault_reset_work - work performed on workq after ioc fault
332 * @work: input argument, used to derive ioc
333 *
334**/
335static void
336mpt_fault_reset_work(struct work_struct *work)
337{
338 MPT_ADAPTER *ioc =
339 container_of(work, MPT_ADAPTER, fault_reset_work.work);
340 u32 ioc_raw_state;
341 int rc;
342 unsigned long flags;
343
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530344 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530345 goto out;
346
347 ioc_raw_state = mpt_GetIocState(ioc, 0);
348 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
349 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700350 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530351 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700352 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530353 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
354 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700355 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530356 ioc_raw_state = mpt_GetIocState(ioc, 0);
357 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
358 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
359 "reset (%04xh)\n", ioc->name, ioc_raw_state &
360 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530361 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
362 if ((mpt_is_discovery_complete(ioc))) {
363 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
364 "discovery_quiesce_io flag\n", ioc->name));
365 ioc->sas_discovery_quiesce_io = 0;
366 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530367 }
368
369 out:
370 /*
371 * Take turns polling alternate controller
372 */
373 if (ioc->alt_ioc)
374 ioc = ioc->alt_ioc;
375
376 /* rearm the timer */
Kashyap, Desai2f187862009-05-29 16:52:37 +0530377 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530378 if (ioc->reset_work_q)
379 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
380 msecs_to_jiffies(MPT_POLLING_INTERVAL));
Kashyap, Desai2f187862009-05-29 16:52:37 +0530381 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530382}
383
384
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600385/*
386 * Process turbo (context) reply...
387 */
388static void
389mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
390{
391 MPT_FRAME_HDR *mf = NULL;
392 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530393 u16 req_idx = 0;
394 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600395
Prakash, Sathya436ace72007-07-24 15:42:08 +0530396 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600397 ioc->name, pa));
398
399 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
400 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
401 req_idx = pa & 0x0000FFFF;
402 cb_idx = (pa & 0x00FF0000) >> 16;
403 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
404 break;
405 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530406 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600407 /*
408 * Blind set of mf to NULL here was fatal
409 * after lan_reply says "freeme"
410 * Fix sort of combined with an optimization here;
411 * added explicit check for case where lan_reply
412 * was just returning 1 and doing nothing else.
413 * For this case skip the callback, but set up
414 * proper mf value first here:-)
415 */
416 if ((pa & 0x58000000) == 0x58000000) {
417 req_idx = pa & 0x0000FFFF;
418 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
419 mpt_free_msg_frame(ioc, mf);
420 mb();
421 return;
422 break;
423 }
424 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
425 break;
426 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530427 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600428 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
429 break;
430 default:
431 cb_idx = 0;
432 BUG();
433 }
434
435 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530436 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600437 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600438 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700439 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600440 goto out;
441 }
442
443 if (MptCallbacks[cb_idx](ioc, mf, mr))
444 mpt_free_msg_frame(ioc, mf);
445 out:
446 mb();
447}
448
449static void
450mpt_reply(MPT_ADAPTER *ioc, u32 pa)
451{
452 MPT_FRAME_HDR *mf;
453 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530454 u16 req_idx;
455 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600456 int freeme;
457
458 u32 reply_dma_low;
459 u16 ioc_stat;
460
461 /* non-TURBO reply! Hmmm, something may be up...
462 * Newest turbo reply mechanism; get address
463 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
464 */
465
466 /* Map DMA address of reply header to cpu address.
467 * pa is 32 bits - but the dma address may be 32 or 64 bits
468 * get offset based only only the low addresses
469 */
470
471 reply_dma_low = (pa <<= 1);
472 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
473 (reply_dma_low - ioc->reply_frames_low_dma));
474
475 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
476 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
477 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
478
Prakash, Sathya436ace72007-07-24 15:42:08 +0530479 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600480 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600481 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600482
483 /* Check/log IOC log info
484 */
485 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
486 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
487 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
488 if (ioc->bus_type == FC)
489 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700490 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700491 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600492 else if (ioc->bus_type == SAS)
493 mpt_sas_log_info(ioc, log_info);
494 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600495
Eric Moorec6c727a2007-01-29 09:44:54 -0700496 if (ioc_stat & MPI_IOCSTATUS_MASK)
497 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600498
499 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530500 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600501 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600502 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700503 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600504 freeme = 0;
505 goto out;
506 }
507
508 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
509
510 out:
511 /* Flush (non-TURBO) reply with a WRITE! */
512 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
513
514 if (freeme)
515 mpt_free_msg_frame(ioc, mf);
516 mb();
517}
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800520/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
522 * @irq: irq number (not used)
523 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 *
525 * This routine is registered via the request_irq() kernel API call,
526 * and handles all interrupts generated from a specific MPT adapter
527 * (also referred to as a IO Controller or IOC).
528 * This routine must clear the interrupt from the adapter and does
529 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200530 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 *
532 * This routine handles register-level access of the adapter but
533 * dispatches (calls) a protocol-specific callback routine to handle
534 * the protocol-specific details of the MPT request completion.
535 */
536static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100537mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600539 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600540 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
541
542 if (pa == 0xFFFFFFFF)
543 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 /*
546 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600548 do {
549 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600550 mpt_reply(ioc, pa);
551 else
552 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600553 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
554 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 return IRQ_HANDLED;
557}
558
559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800560/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530561 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530563 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
565 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800566 * MPT base driver's callback routine; all base driver
567 * "internal" request/reply processing is routed here.
568 * Currently used for EventNotification and EventAck handling.
569 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200570 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 * should be freed, or 0 if it shouldn't.
572 */
573static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530574mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530576 EventNotificationReply_t *pEventReply;
577 u8 event;
578 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530581 switch (reply->u.hdr.Function) {
582 case MPI_FUNCTION_EVENT_NOTIFICATION:
583 pEventReply = (EventNotificationReply_t *)reply;
584 evHandlers = 0;
585 ProcessEventNotification(ioc, pEventReply, &evHandlers);
586 event = le32_to_cpu(pEventReply->Event) & 0xFF;
587 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530589 if (event != MPI_EVENT_EVENT_CHANGE)
590 break;
591 case MPI_FUNCTION_CONFIG:
592 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
593 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
594 if (reply) {
595 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
596 memcpy(ioc->mptbase_cmds.reply, reply,
597 min(MPT_DEFAULT_FRAME_SIZE,
598 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200599 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530600 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
601 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
602 complete(&ioc->mptbase_cmds.done);
603 } else
604 freereq = 0;
605 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
606 freereq = 1;
607 break;
608 case MPI_FUNCTION_EVENT_ACK:
609 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
610 "EventAck reply received\n", ioc->name));
611 break;
612 default:
613 printk(MYIOC_s_ERR_FMT
614 "Unexpected msg function (=%02Xh) reply received!\n",
615 ioc->name, reply->u.hdr.Function);
616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618
619 /*
620 * Conditionally tell caller to free the original
621 * EventNotification/EventAck/unexpected request frame!
622 */
623 return freereq;
624}
625
626/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
627/**
628 * mpt_register - Register protocol-specific main callback handler.
629 * @cbfunc: callback function pointer
630 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
631 *
632 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800633 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 * protocol-specific driver must do this before it will be able to
635 * use any IOC resources, such as obtaining request frames.
636 *
637 * NOTES: The SCSI protocol driver currently calls this routine thrice
638 * in order to register separate callbacks; one for "normal" SCSI IO;
639 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
640 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530641 * Returns u8 valued "handle" in the range (and S.O.D. order)
642 * {N,...,7,6,5,...,1} if successful.
643 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
644 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530646u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
648{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530649 u8 cb_idx;
650 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 /*
653 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
654 * (slot/handle 0 is reserved!)
655 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530656 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
657 if (MptCallbacks[cb_idx] == NULL) {
658 MptCallbacks[cb_idx] = cbfunc;
659 MptDriverClass[cb_idx] = dclass;
660 MptEvHandlers[cb_idx] = NULL;
661 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 break;
663 }
664 }
665
666 return last_drv_idx;
667}
668
669/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
670/**
671 * mpt_deregister - Deregister a protocol drivers resources.
672 * @cb_idx: previously registered callback handle
673 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800674 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 * module is unloaded.
676 */
677void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530678mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600680 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 MptCallbacks[cb_idx] = NULL;
682 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
683 MptEvHandlers[cb_idx] = NULL;
684
685 last_drv_idx++;
686 }
687}
688
689/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
690/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800691 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 * @cb_idx: previously registered (via mpt_register) callback handle
693 * @ev_cbfunc: callback function
694 *
695 * This routine can be called by one or more protocol-specific drivers
696 * if/when they choose to be notified of MPT events.
697 *
698 * Returns 0 for success.
699 */
700int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530701mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600703 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return -1;
705
706 MptEvHandlers[cb_idx] = ev_cbfunc;
707 return 0;
708}
709
710/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
711/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800712 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 * @cb_idx: previously registered callback handle
714 *
715 * Each protocol-specific driver should call this routine
716 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800717 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600722 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return;
724
725 MptEvHandlers[cb_idx] = NULL;
726}
727
728/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
729/**
730 * mpt_reset_register - Register protocol-specific IOC reset handler.
731 * @cb_idx: previously registered (via mpt_register) callback handle
732 * @reset_func: reset function
733 *
734 * This routine can be called by one or more protocol-specific drivers
735 * if/when they choose to be notified of IOC resets.
736 *
737 * Returns 0 for success.
738 */
739int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530740mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530742 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return -1;
744
745 MptResetHandlers[cb_idx] = reset_func;
746 return 0;
747}
748
749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
750/**
751 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
752 * @cb_idx: previously registered callback handle
753 *
754 * Each protocol-specific driver should call this routine
755 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800756 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 */
758void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530759mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530761 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return;
763
764 MptResetHandlers[cb_idx] = NULL;
765}
766
767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
768/**
769 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800770 * @dd_cbfunc: driver callbacks struct
771 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 */
773int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530774mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600777 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Eric Moore8d6d83e2007-09-14 18:47:40 -0600779 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400780 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
783
784 /* call per pci device probe entry point */
785 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600786 id = ioc->pcidev->driver ?
787 ioc->pcidev->driver->id_table : NULL;
788 if (dd_cbfunc->probe)
789 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400792 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
796/**
797 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800798 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 */
800void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530801mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 struct mpt_pci_driver *dd_cbfunc;
804 MPT_ADAPTER *ioc;
805
Eric Moore8d6d83e2007-09-14 18:47:40 -0600806 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 return;
808
809 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
810
811 list_for_each_entry(ioc, &ioc_list, list) {
812 if (dd_cbfunc->remove)
813 dd_cbfunc->remove(ioc->pcidev);
814 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 MptDeviceDriverHandlers[cb_idx] = NULL;
817}
818
819
820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
821/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800822 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530823 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * @ioc: Pointer to MPT adapter structure
825 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800826 * Obtain an MPT request frame from the pool (of 1024) that are
827 * allocated per MPT adapter.
828 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 * Returns pointer to a MPT request frame or %NULL if none are available
830 * or IOC is not active.
831 */
832MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 MPT_FRAME_HDR *mf;
836 unsigned long flags;
837 u16 req_idx; /* Request index */
838
839 /* validate handle and ioc identifier */
840
841#ifdef MFCNT
842 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600843 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
844 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845#endif
846
847 /* If interrupts are not attached, do not return a request frame */
848 if (!ioc->active)
849 return NULL;
850
851 spin_lock_irqsave(&ioc->FreeQlock, flags);
852 if (!list_empty(&ioc->FreeQ)) {
853 int req_offset;
854
855 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
856 u.frame.linkage.list);
857 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200858 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530859 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
861 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500862 req_idx = req_offset / ioc->req_sz;
863 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600865 /* Default, will be changed if necessary in SG generation */
866 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867#ifdef MFCNT
868 ioc->mfcnt++;
869#endif
870 }
871 else
872 mf = NULL;
873 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
874
875#ifdef MFCNT
876 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600877 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
878 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
879 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 mfcounter++;
881 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600882 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
883 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884#endif
885
Eric Moore29dd3602007-09-14 18:46:51 -0600886 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
887 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return mf;
889}
890
891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
892/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800893 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530894 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 * @ioc: Pointer to MPT adapter structure
896 * @mf: Pointer to MPT request frame
897 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800898 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 * specific MPT adapter.
900 */
901void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530902mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 u32 mf_dma_addr;
905 int req_offset;
906 u16 req_idx; /* Request index */
907
908 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530909 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
911 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500912 req_idx = req_offset / ioc->req_sz;
913 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
915
Prakash, Sathya436ace72007-07-24 15:42:08 +0530916 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200918 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600919 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
920 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
921 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
923}
924
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530925/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800926 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530927 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530928 * @ioc: Pointer to MPT adapter structure
929 * @mf: Pointer to MPT request frame
930 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800931 * Send a protocol-specific MPT request frame to an IOC using
932 * hi-priority request queue.
933 *
934 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530935 * specific MPT adapter.
936 **/
937void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530938mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530939{
940 u32 mf_dma_addr;
941 int req_offset;
942 u16 req_idx; /* Request index */
943
944 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530945 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530946 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
947 req_idx = req_offset / ioc->req_sz;
948 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
949 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
950
951 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
952
953 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
954 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
955 ioc->name, mf_dma_addr, req_idx));
956 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
960/**
961 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 * @ioc: Pointer to MPT adapter structure
963 * @mf: Pointer to MPT request frame
964 *
965 * This routine places a MPT request frame back on the MPT adapter's
966 * FreeQ.
967 */
968void
969mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
970{
971 unsigned long flags;
972
973 /* Put Request back on FreeQ! */
974 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530975 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
976 goto out;
977 /* signature to know if this mf is freed */
978 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
980#ifdef MFCNT
981 ioc->mfcnt--;
982#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +0530983 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
985}
986
987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
988/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530989 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 * @pAddr: virtual address for SGE
991 * @flagslength: SGE flags and data transfer length
992 * @dma_addr: Physical address
993 *
994 * This routine places a MPT request frame back on the MPT adapter's
995 * FreeQ.
996 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530997static void
998mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301000 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1001 pSge->FlagsLength = cpu_to_le32(flagslength);
1002 pSge->Address = cpu_to_le32(dma_addr);
1003}
1004
1005/**
1006 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1007 * @pAddr: virtual address for SGE
1008 * @flagslength: SGE flags and data transfer length
1009 * @dma_addr: Physical address
1010 *
1011 * This routine places a MPT request frame back on the MPT adapter's
1012 * FreeQ.
1013 **/
1014static void
1015mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1016{
1017 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1018 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301019 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301020 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301021 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301022 pSge->FlagsLength = cpu_to_le32
1023 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1024}
1025
1026/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001027 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301028 * @pAddr: virtual address for SGE
1029 * @flagslength: SGE flags and data transfer length
1030 * @dma_addr: Physical address
1031 *
1032 * This routine places a MPT request frame back on the MPT adapter's
1033 * FreeQ.
1034 **/
1035static void
1036mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1037{
1038 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1039 u32 tmp;
1040
1041 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301042 (lower_32_bits(dma_addr));
1043 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301044
1045 /*
1046 * 1078 errata workaround for the 36GB limitation
1047 */
1048 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1049 flagslength |=
1050 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1051 tmp |= (1<<31);
1052 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1053 printk(KERN_DEBUG "1078 P0M2 addressing for "
1054 "addr = 0x%llx len = %d\n",
1055 (unsigned long long)dma_addr,
1056 MPI_SGE_LENGTH(flagslength));
1057 }
1058
1059 pSge->Address.High = cpu_to_le32(tmp);
1060 pSge->FlagsLength = cpu_to_le32(
1061 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1062}
1063
1064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1065/**
1066 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1067 * @pAddr: virtual address for SGE
1068 * @next: nextChainOffset value (u32's)
1069 * @length: length of next SGL segment
1070 * @dma_addr: Physical address
1071 *
1072 */
1073static void
1074mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1075{
1076 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1077 pChain->Length = cpu_to_le16(length);
1078 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1079 pChain->NextChainOffset = next;
1080 pChain->Address = cpu_to_le32(dma_addr);
1081}
1082
1083/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1084/**
1085 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1086 * @pAddr: virtual address for SGE
1087 * @next: nextChainOffset value (u32's)
1088 * @length: length of next SGL segment
1089 * @dma_addr: Physical address
1090 *
1091 */
1092static void
1093mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1094{
1095 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 u32 tmp = dma_addr & 0xFFFFFFFF;
1097
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301098 pChain->Length = cpu_to_le16(length);
1099 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1100 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301102 pChain->NextChainOffset = next;
1103
1104 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301105 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301106 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107}
1108
1109/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1110/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001111 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301112 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 * @ioc: Pointer to MPT adapter structure
1114 * @reqBytes: Size of the request in bytes
1115 * @req: Pointer to MPT request frame
1116 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1117 *
1118 * This routine is used exclusively to send MptScsiTaskMgmt
1119 * requests since they are required to be sent via doorbell handshake.
1120 *
1121 * NOTE: It is the callers responsibility to byte-swap fields in the
1122 * request which are greater than 1 byte in size.
1123 *
1124 * Returns 0 for success, non-zero for failure.
1125 */
1126int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301127mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
Eric Moorecd2c6192007-01-29 09:47:47 -07001129 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 u8 *req_as_bytes;
1131 int ii;
1132
1133 /* State is known to be good upon entering
1134 * this function so issue the bus reset
1135 * request.
1136 */
1137
1138 /*
1139 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1140 * setting cb_idx/req_idx. But ONLY if this request
1141 * is in proper (pre-alloc'd) request buffer range...
1142 */
1143 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1144 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1145 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1146 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301147 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149
1150 /* Make sure there are no doorbells */
1151 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1154 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1155 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1156
1157 /* Wait for IOC doorbell int */
1158 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1159 return ii;
1160 }
1161
1162 /* Read doorbell and check for active bit */
1163 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1164 return -5;
1165
Eric Moore29dd3602007-09-14 18:46:51 -06001166 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001167 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1170
1171 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1172 return -2;
1173 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 /* Send request via doorbell handshake */
1176 req_as_bytes = (u8 *) req;
1177 for (ii = 0; ii < reqBytes/4; ii++) {
1178 u32 word;
1179
1180 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1181 (req_as_bytes[(ii*4) + 1] << 8) |
1182 (req_as_bytes[(ii*4) + 2] << 16) |
1183 (req_as_bytes[(ii*4) + 3] << 24));
1184 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1185 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1186 r = -3;
1187 break;
1188 }
1189 }
1190
1191 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1192 r = 0;
1193 else
1194 r = -4;
1195
1196 /* Make sure there are no doorbells */
1197 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 return r;
1200}
1201
1202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1203/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001204 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001205 * @ioc: Pointer to MPT adapter structure
1206 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001207 * @sleepFlag: Specifies whether the process can sleep
1208 *
1209 * Provides mechanism for the host driver to control the IOC's
1210 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001211 *
1212 * Access Control Value - bits[15:12]
1213 * 0h Reserved
1214 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1215 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1216 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1217 *
1218 * Returns 0 for success, non-zero for failure.
1219 */
1220
1221static int
1222mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1223{
1224 int r = 0;
1225
1226 /* return if in use */
1227 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1228 & MPI_DOORBELL_ACTIVE)
1229 return -1;
1230
1231 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1232
1233 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1234 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1235 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1236 (access_control_value<<12)));
1237
1238 /* Wait for IOC to clear Doorbell Status bit */
1239 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1240 return -2;
1241 }else
1242 return 0;
1243}
1244
1245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1246/**
1247 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001248 * @ioc: Pointer to pointer to IOC adapter
1249 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001250 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001251 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001252 * Returns 0 for success, non-zero for failure.
1253 */
1254static int
1255mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1256{
1257 char *psge;
1258 int flags_length;
1259 u32 host_page_buffer_sz=0;
1260
1261 if(!ioc->HostPageBuffer) {
1262
1263 host_page_buffer_sz =
1264 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1265
1266 if(!host_page_buffer_sz)
1267 return 0; /* fw doesn't need any host buffers */
1268
1269 /* spin till we get enough memory */
1270 while(host_page_buffer_sz > 0) {
1271
1272 if((ioc->HostPageBuffer = pci_alloc_consistent(
1273 ioc->pcidev,
1274 host_page_buffer_sz,
1275 &ioc->HostPageBuffer_dma)) != NULL) {
1276
Prakash, Sathya436ace72007-07-24 15:42:08 +05301277 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001278 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001279 ioc->name, ioc->HostPageBuffer,
1280 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001281 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001282 ioc->alloc_total += host_page_buffer_sz;
1283 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1284 break;
1285 }
1286
1287 host_page_buffer_sz -= (4*1024);
1288 }
1289 }
1290
1291 if(!ioc->HostPageBuffer) {
1292 printk(MYIOC_s_ERR_FMT
1293 "Failed to alloc memory for host_page_buffer!\n",
1294 ioc->name);
1295 return -999;
1296 }
1297
1298 psge = (char *)&ioc_init->HostPageBufferSGE;
1299 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1300 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001301 MPI_SGE_FLAGS_HOST_TO_IOC |
1302 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001303 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1304 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301305 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001306 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1307
1308return 0;
1309}
1310
1311/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1312/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001313 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 * @iocid: IOC unique identifier (integer)
1315 * @iocpp: Pointer to pointer to IOC adapter
1316 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001317 * Given a unique IOC identifier, set pointer to the associated MPT
1318 * adapter structure.
1319 *
1320 * Returns iocid and sets iocpp if iocid is found.
1321 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 */
1323int
1324mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1325{
1326 MPT_ADAPTER *ioc;
1327
1328 list_for_each_entry(ioc,&ioc_list,list) {
1329 if (ioc->id == iocid) {
1330 *iocpp =ioc;
1331 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 *iocpp = NULL;
1336 return -1;
1337}
1338
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301339/**
1340 * mpt_get_product_name - returns product string
1341 * @vendor: pci vendor id
1342 * @device: pci device id
1343 * @revision: pci revision id
1344 * @prod_name: string returned
1345 *
1346 * Returns product string displayed when driver loads,
1347 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1348 *
1349 **/
1350static void
1351mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1352{
1353 char *product_str = NULL;
1354
1355 if (vendor == PCI_VENDOR_ID_BROCADE) {
1356 switch (device)
1357 {
1358 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1359 switch (revision)
1360 {
1361 case 0x00:
1362 product_str = "BRE040 A0";
1363 break;
1364 case 0x01:
1365 product_str = "BRE040 A1";
1366 break;
1367 default:
1368 product_str = "BRE040";
1369 break;
1370 }
1371 break;
1372 }
1373 goto out;
1374 }
1375
1376 switch (device)
1377 {
1378 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1379 product_str = "LSIFC909 B1";
1380 break;
1381 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1382 product_str = "LSIFC919 B0";
1383 break;
1384 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1385 product_str = "LSIFC929 B0";
1386 break;
1387 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1388 if (revision < 0x80)
1389 product_str = "LSIFC919X A0";
1390 else
1391 product_str = "LSIFC919XL A1";
1392 break;
1393 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1394 if (revision < 0x80)
1395 product_str = "LSIFC929X A0";
1396 else
1397 product_str = "LSIFC929XL A1";
1398 break;
1399 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1400 product_str = "LSIFC939X A1";
1401 break;
1402 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1403 product_str = "LSIFC949X A1";
1404 break;
1405 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1406 switch (revision)
1407 {
1408 case 0x00:
1409 product_str = "LSIFC949E A0";
1410 break;
1411 case 0x01:
1412 product_str = "LSIFC949E A1";
1413 break;
1414 default:
1415 product_str = "LSIFC949E";
1416 break;
1417 }
1418 break;
1419 case MPI_MANUFACTPAGE_DEVID_53C1030:
1420 switch (revision)
1421 {
1422 case 0x00:
1423 product_str = "LSI53C1030 A0";
1424 break;
1425 case 0x01:
1426 product_str = "LSI53C1030 B0";
1427 break;
1428 case 0x03:
1429 product_str = "LSI53C1030 B1";
1430 break;
1431 case 0x07:
1432 product_str = "LSI53C1030 B2";
1433 break;
1434 case 0x08:
1435 product_str = "LSI53C1030 C0";
1436 break;
1437 case 0x80:
1438 product_str = "LSI53C1030T A0";
1439 break;
1440 case 0x83:
1441 product_str = "LSI53C1030T A2";
1442 break;
1443 case 0x87:
1444 product_str = "LSI53C1030T A3";
1445 break;
1446 case 0xc1:
1447 product_str = "LSI53C1020A A1";
1448 break;
1449 default:
1450 product_str = "LSI53C1030";
1451 break;
1452 }
1453 break;
1454 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1455 switch (revision)
1456 {
1457 case 0x03:
1458 product_str = "LSI53C1035 A2";
1459 break;
1460 case 0x04:
1461 product_str = "LSI53C1035 B0";
1462 break;
1463 default:
1464 product_str = "LSI53C1035";
1465 break;
1466 }
1467 break;
1468 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1469 switch (revision)
1470 {
1471 case 0x00:
1472 product_str = "LSISAS1064 A1";
1473 break;
1474 case 0x01:
1475 product_str = "LSISAS1064 A2";
1476 break;
1477 case 0x02:
1478 product_str = "LSISAS1064 A3";
1479 break;
1480 case 0x03:
1481 product_str = "LSISAS1064 A4";
1482 break;
1483 default:
1484 product_str = "LSISAS1064";
1485 break;
1486 }
1487 break;
1488 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1489 switch (revision)
1490 {
1491 case 0x00:
1492 product_str = "LSISAS1064E A0";
1493 break;
1494 case 0x01:
1495 product_str = "LSISAS1064E B0";
1496 break;
1497 case 0x02:
1498 product_str = "LSISAS1064E B1";
1499 break;
1500 case 0x04:
1501 product_str = "LSISAS1064E B2";
1502 break;
1503 case 0x08:
1504 product_str = "LSISAS1064E B3";
1505 break;
1506 default:
1507 product_str = "LSISAS1064E";
1508 break;
1509 }
1510 break;
1511 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1512 switch (revision)
1513 {
1514 case 0x00:
1515 product_str = "LSISAS1068 A0";
1516 break;
1517 case 0x01:
1518 product_str = "LSISAS1068 B0";
1519 break;
1520 case 0x02:
1521 product_str = "LSISAS1068 B1";
1522 break;
1523 default:
1524 product_str = "LSISAS1068";
1525 break;
1526 }
1527 break;
1528 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1529 switch (revision)
1530 {
1531 case 0x00:
1532 product_str = "LSISAS1068E A0";
1533 break;
1534 case 0x01:
1535 product_str = "LSISAS1068E B0";
1536 break;
1537 case 0x02:
1538 product_str = "LSISAS1068E B1";
1539 break;
1540 case 0x04:
1541 product_str = "LSISAS1068E B2";
1542 break;
1543 case 0x08:
1544 product_str = "LSISAS1068E B3";
1545 break;
1546 default:
1547 product_str = "LSISAS1068E";
1548 break;
1549 }
1550 break;
1551 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1552 switch (revision)
1553 {
1554 case 0x00:
1555 product_str = "LSISAS1078 A0";
1556 break;
1557 case 0x01:
1558 product_str = "LSISAS1078 B0";
1559 break;
1560 case 0x02:
1561 product_str = "LSISAS1078 C0";
1562 break;
1563 case 0x03:
1564 product_str = "LSISAS1078 C1";
1565 break;
1566 case 0x04:
1567 product_str = "LSISAS1078 C2";
1568 break;
1569 default:
1570 product_str = "LSISAS1078";
1571 break;
1572 }
1573 break;
1574 }
1575
1576 out:
1577 if (product_str)
1578 sprintf(prod_name, "%s", product_str);
1579}
1580
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301581/**
1582 * mpt_mapresources - map in memory mapped io
1583 * @ioc: Pointer to pointer to IOC adapter
1584 *
1585 **/
1586static int
1587mpt_mapresources(MPT_ADAPTER *ioc)
1588{
1589 u8 __iomem *mem;
1590 int ii;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001591 resource_size_t mem_phys;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301592 unsigned long port;
1593 u32 msize;
1594 u32 psize;
1595 u8 revision;
1596 int r = -ENODEV;
1597 struct pci_dev *pdev;
1598
1599 pdev = ioc->pcidev;
1600 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1601 if (pci_enable_device_mem(pdev)) {
1602 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1603 "failed\n", ioc->name);
1604 return r;
1605 }
1606 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1607 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1608 "MEM failed\n", ioc->name);
1609 return r;
1610 }
1611
1612 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1613
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301614 if (sizeof(dma_addr_t) > 4) {
1615 const uint64_t required_mask = dma_get_required_mask
1616 (&pdev->dev);
1617 if (required_mask > DMA_BIT_MASK(32)
1618 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1619 && !pci_set_consistent_dma_mask(pdev,
1620 DMA_BIT_MASK(64))) {
1621 ioc->dma_mask = DMA_BIT_MASK(64);
1622 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1623 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1624 ioc->name));
1625 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1626 && !pci_set_consistent_dma_mask(pdev,
1627 DMA_BIT_MASK(32))) {
1628 ioc->dma_mask = DMA_BIT_MASK(32);
1629 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1630 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1631 ioc->name));
1632 } else {
1633 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1634 ioc->name, pci_name(pdev));
1635 return r;
1636 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301637 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301638 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1639 && !pci_set_consistent_dma_mask(pdev,
1640 DMA_BIT_MASK(32))) {
1641 ioc->dma_mask = DMA_BIT_MASK(32);
1642 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1643 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1644 ioc->name));
1645 } else {
1646 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1647 ioc->name, pci_name(pdev));
1648 return r;
1649 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301650 }
1651
1652 mem_phys = msize = 0;
1653 port = psize = 0;
1654 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1655 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1656 if (psize)
1657 continue;
1658 /* Get I/O space! */
1659 port = pci_resource_start(pdev, ii);
1660 psize = pci_resource_len(pdev, ii);
1661 } else {
1662 if (msize)
1663 continue;
1664 /* Get memmap */
1665 mem_phys = pci_resource_start(pdev, ii);
1666 msize = pci_resource_len(pdev, ii);
1667 }
1668 }
1669 ioc->mem_size = msize;
1670
1671 mem = NULL;
1672 /* Get logical ptr for PciMem0 space */
1673 /*mem = ioremap(mem_phys, msize);*/
1674 mem = ioremap(mem_phys, msize);
1675 if (mem == NULL) {
1676 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1677 " memory!\n", ioc->name);
1678 return -EINVAL;
1679 }
1680 ioc->memmap = mem;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001681 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
1682 ioc->name, mem, (unsigned long long)mem_phys));
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301683
1684 ioc->mem_phys = mem_phys;
1685 ioc->chip = (SYSIF_REGS __iomem *)mem;
1686
1687 /* Save Port IO values in case we need to do downloadboot */
1688 ioc->pio_mem_phys = port;
1689 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1690
1691 return 0;
1692}
1693
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001695/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001696 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001698 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 *
1700 * This routine performs all the steps necessary to bring the IOC of
1701 * a MPT adapter to a OPERATIONAL state. This includes registering
1702 * memory regions, registering the interrupt, and allocating request
1703 * and reply memory pools.
1704 *
1705 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1706 * MPT adapter.
1707 *
1708 * Returns 0 for success, non-zero for failure.
1709 *
1710 * TODO: Add support for polled controllers
1711 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001712int
1713mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714{
1715 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301716 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 u8 revision;
1719 u8 pcixcmd;
1720 static int mpt_ids = 0;
1721#ifdef CONFIG_PROC_FS
1722 struct proc_dir_entry *dent, *ent;
1723#endif
1724
Jesper Juhl56876192007-08-10 14:50:51 -07001725 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1726 if (ioc == NULL) {
1727 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1728 return -ENOMEM;
1729 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301730
Eric Moore29dd3602007-09-14 18:46:51 -06001731 ioc->id = mpt_ids++;
1732 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301733 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001734
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301735 /*
1736 * set initial debug level
1737 * (refer to mptdebug.h)
1738 *
1739 */
1740 ioc->debug_level = mpt_debug_level;
1741 if (mpt_debug_level)
1742 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301743
Eric Moore29dd3602007-09-14 18:46:51 -06001744 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001745
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301746 ioc->pcidev = pdev;
1747 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001748 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 return r;
1750 }
1751
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301752 /*
1753 * Setting up proper handlers for scatter gather handling
1754 */
1755 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1756 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1757 ioc->add_sge = &mpt_add_sge_64bit_1078;
1758 else
1759 ioc->add_sge = &mpt_add_sge_64bit;
1760 ioc->add_chain = &mpt_add_chain_64bit;
1761 ioc->sg_addr_size = 8;
1762 } else {
1763 ioc->add_sge = &mpt_add_sge;
1764 ioc->add_chain = &mpt_add_chain;
1765 ioc->sg_addr_size = 4;
1766 }
1767 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 ioc->alloc_total = sizeof(MPT_ADAPTER);
1770 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1771 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 ioc->pcidev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301775 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301776 mutex_init(&ioc->internal_cmds.mutex);
1777 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301778 mutex_init(&ioc->mptbase_cmds.mutex);
1779 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301780 mutex_init(&ioc->taskmgmt_cmds.mutex);
1781 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 /* Initialize the event logging.
1784 */
1785 ioc->eventTypes = 0; /* None */
1786 ioc->eventContext = 0;
1787 ioc->eventLogSize = 0;
1788 ioc->events = NULL;
1789
1790#ifdef MFCNT
1791 ioc->mfcnt = 0;
1792#endif
1793
Kashyap, Desai2f187862009-05-29 16:52:37 +05301794 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 ioc->cached_fw = NULL;
1796
1797 /* Initilize SCSI Config Data structure
1798 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001799 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Michael Reed05e8ec12006-01-13 14:31:54 -06001801 /* Initialize the fc rport list head.
1802 */
1803 INIT_LIST_HEAD(&ioc->fc_rports);
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 /* Find lookup slot. */
1806 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001807
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301808
1809 /* Initialize workqueue */
1810 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301811
Kashyap, Desai2f187862009-05-29 16:52:37 +05301812 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001813 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301814 ioc->reset_work_q =
1815 create_singlethread_workqueue(ioc->reset_work_q_name);
1816 if (!ioc->reset_work_q) {
1817 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1818 ioc->name);
1819 pci_release_selected_regions(pdev, ioc->bars);
1820 kfree(ioc);
1821 return -ENOMEM;
1822 }
1823
Eric Moore29dd3602007-09-14 18:46:51 -06001824 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1825 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301827 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1828 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1829
1830 switch (pdev->device)
1831 {
1832 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1833 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1834 ioc->errata_flag_1064 = 1;
1835 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1836 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1838 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301840 break;
1841
1842 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* 929X Chip Fix. Set Split transactions level
1845 * for PCIX. Set MOST bits to zero.
1846 */
1847 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1848 pcixcmd &= 0x8F;
1849 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1850 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 /* 929XL Chip Fix. Set MMRBC to 0x08.
1852 */
1853 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1854 pcixcmd |= 0x08;
1855 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301858 break;
1859
1860 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 /* 919X Chip Fix. Set Split transactions level
1862 * for PCIX. Set MOST bits to zero.
1863 */
1864 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1865 pcixcmd &= 0x8F;
1866 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001867 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301868 break;
1869
1870 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 /* 1030 Chip Fix. Disable Split transactions
1872 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1873 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (revision < C0_1030) {
1875 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1876 pcixcmd &= 0x8F;
1877 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1878 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301879
1880 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001881 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301882 break;
1883
1884 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1885 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001886 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301887 ioc->bus_type = SAS;
1888 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301889
1890 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1891 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1892 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001893 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301894 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301897
Kashyap, Desaie3829682009-01-08 14:27:16 +05301898 switch (ioc->bus_type) {
1899
1900 case SAS:
1901 ioc->msi_enable = mpt_msi_enable_sas;
1902 break;
1903
1904 case SPI:
1905 ioc->msi_enable = mpt_msi_enable_spi;
1906 break;
1907
1908 case FC:
1909 ioc->msi_enable = mpt_msi_enable_fc;
1910 break;
1911
1912 default:
1913 ioc->msi_enable = 0;
1914 break;
1915 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001916 if (ioc->errata_flag_1064)
1917 pci_disable_io_access(pdev);
1918
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 spin_lock_init(&ioc->FreeQlock);
1920
1921 /* Disable all! */
1922 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1923 ioc->active = 0;
1924 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1925
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301926 /* Set IOC ptr in the pcidev's driver data. */
1927 pci_set_drvdata(ioc->pcidev, ioc);
1928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 /* Set lookup ptr. */
1930 list_add_tail(&ioc->list, &ioc_list);
1931
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001932 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 */
1934 mpt_detect_bound_ports(ioc, pdev);
1935
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301936 INIT_LIST_HEAD(&ioc->fw_event_list);
1937 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301938 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301939 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1940
James Bottomleyc92f2222006-03-01 09:02:49 -06001941 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1942 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001943 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1944 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001945
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001947 if (ioc->alt_ioc)
1948 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301949 iounmap(ioc->memmap);
1950 if (r != -5)
1951 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301952
1953 destroy_workqueue(ioc->reset_work_q);
1954 ioc->reset_work_q = NULL;
1955
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 kfree(ioc);
1957 pci_set_drvdata(pdev, NULL);
1958 return r;
1959 }
1960
1961 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001962 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301963 if(MptDeviceDriverHandlers[cb_idx] &&
1964 MptDeviceDriverHandlers[cb_idx]->probe) {
1965 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 }
1967 }
1968
1969#ifdef CONFIG_PROC_FS
1970 /*
1971 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1972 */
1973 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1974 if (dent) {
1975 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1976 if (ent) {
1977 ent->read_proc = procmpt_iocinfo_read;
1978 ent->data = ioc;
1979 }
1980 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1981 if (ent) {
1982 ent->read_proc = procmpt_summary_read;
1983 ent->data = ioc;
1984 }
1985 }
1986#endif
1987
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301988 if (!ioc->alt_ioc)
1989 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1990 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1991
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 return 0;
1993}
1994
1995/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001996/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001997 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 */
2000
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002001void
2002mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003{
2004 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2005 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302006 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302007 unsigned long flags;
2008 struct workqueue_struct *wq;
2009
2010 /*
2011 * Stop polling ioc for fault condition
2012 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302013 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302014 wq = ioc->reset_work_q;
2015 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302016 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302017 cancel_delayed_work(&ioc->fault_reset_work);
2018 destroy_workqueue(wq);
2019
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302020 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2021 wq = ioc->fw_event_q;
2022 ioc->fw_event_q = NULL;
2023 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2024 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
2026 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2027 remove_proc_entry(pname, NULL);
2028 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2029 remove_proc_entry(pname, NULL);
2030 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2031 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002032
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002034 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302035 if(MptDeviceDriverHandlers[cb_idx] &&
2036 MptDeviceDriverHandlers[cb_idx]->remove) {
2037 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 }
2039 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002040
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 /* Disable interrupts! */
2042 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2043
2044 ioc->active = 0;
2045 synchronize_irq(pdev->irq);
2046
2047 /* Clear any lingering interrupt */
2048 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2049
2050 CHIPREG_READ32(&ioc->chip->IntStatus);
2051
2052 mpt_adapter_dispose(ioc);
2053
2054 pci_set_drvdata(pdev, NULL);
2055}
2056
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057/**************************************************************************
2058 * Power Management
2059 */
2060#ifdef CONFIG_PM
2061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002062/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002063 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002064 * @pdev: Pointer to pci_dev structure
2065 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002067int
2068mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069{
2070 u32 device_state;
2071 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302073 device_state = pci_choose_state(pdev, state);
2074 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2075 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2076 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
2078 /* put ioc into READY_STATE */
2079 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2080 printk(MYIOC_s_ERR_FMT
2081 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2082 }
2083
2084 /* disable interrupts */
2085 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2086 ioc->active = 0;
2087
2088 /* Clear any lingering interrupt */
2089 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2090
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302091 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002092 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302093 pci_disable_msi(ioc->pcidev);
2094 ioc->pci_irq = -1;
2095 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302097 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 return 0;
2100}
2101
2102/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002103/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002104 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002105 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002107int
2108mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109{
2110 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2111 u32 device_state = pdev->current_state;
2112 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302113 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002114
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302115 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2116 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2117 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302119 pci_set_power_state(pdev, PCI_D0);
2120 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302122 ioc->pcidev = pdev;
2123 err = mpt_mapresources(ioc);
2124 if (err)
2125 return err;
2126
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302127 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2128 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2129 ioc->add_sge = &mpt_add_sge_64bit_1078;
2130 else
2131 ioc->add_sge = &mpt_add_sge_64bit;
2132 ioc->add_chain = &mpt_add_chain_64bit;
2133 ioc->sg_addr_size = 8;
2134 } else {
2135
2136 ioc->add_sge = &mpt_add_sge;
2137 ioc->add_chain = &mpt_add_chain;
2138 ioc->sg_addr_size = 4;
2139 }
2140 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2141
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302142 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2143 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2144 CHIPREG_READ32(&ioc->chip->Doorbell));
2145
2146 /*
2147 * Errata workaround for SAS pci express:
2148 * Upon returning to the D0 state, the contents of the doorbell will be
2149 * stale data, and this will incorrectly signal to the host driver that
2150 * the firmware is ready to process mpt commands. The workaround is
2151 * to issue a diagnostic reset.
2152 */
2153 if (ioc->bus_type == SAS && (pdev->device ==
2154 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2155 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2156 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2157 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2158 ioc->name);
2159 goto out;
2160 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302161 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
2163 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302164 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2165 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2166 CAN_SLEEP);
2167 if (recovery_state != 0)
2168 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2169 "error:[%x]\n", ioc->name, recovery_state);
2170 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302172 "pci-resume: success\n", ioc->name);
2173 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302175
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176}
2177#endif
2178
James Bottomley4ff42a62006-05-17 18:06:52 -05002179static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302180mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002181{
2182 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2183 ioc->bus_type != SPI) ||
2184 (MptDriverClass[index] == MPTFC_DRIVER &&
2185 ioc->bus_type != FC) ||
2186 (MptDriverClass[index] == MPTSAS_DRIVER &&
2187 ioc->bus_type != SAS))
2188 /* make sure we only call the relevant reset handler
2189 * for the bus */
2190 return 0;
2191 return (MptResetHandlers[index])(ioc, reset_phase);
2192}
2193
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002195/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2197 * @ioc: Pointer to MPT adapter structure
2198 * @reason: Event word / reason
2199 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2200 *
2201 * This routine performs all the steps necessary to bring the IOC
2202 * to a OPERATIONAL state.
2203 *
2204 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2205 * MPT adapter.
2206 *
2207 * Returns:
2208 * 0 for success
2209 * -1 if failed to get board READY
2210 * -2 if READY but IOCFacts Failed
2211 * -3 if READY but PrimeIOCFifos Failed
2212 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302213 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302214 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 */
2216static int
2217mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2218{
2219 int hard_reset_done = 0;
2220 int alt_ioc_ready = 0;
2221 int hard;
2222 int rc=0;
2223 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 int ret = 0;
2225 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002226 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302227 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Eric Moore29dd3602007-09-14 18:46:51 -06002229 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2230 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
2232 /* Disable reply interrupts (also blocks FreeQ) */
2233 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2234 ioc->active = 0;
2235
2236 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302237 if (ioc->alt_ioc->active ||
2238 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302240 /* Disable alt-IOC's reply interrupts
2241 * (and FreeQ) for a bit
2242 **/
2243 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2244 0xFFFFFFFF);
2245 ioc->alt_ioc->active = 0;
2246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 }
2248
2249 hard = 1;
2250 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2251 hard = 0;
2252
2253 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2254 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002255 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2256 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
2258 if (reset_alt_ioc_active && ioc->alt_ioc) {
2259 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002260 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2261 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002262 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 ioc->alt_ioc->active = 1;
2264 }
2265
2266 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302267 printk(MYIOC_s_WARN_FMT
2268 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302270 ret = -1;
2271 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 }
2273
2274 /* hard_reset_done = 0 if a soft reset was performed
2275 * and 1 if a hard reset was performed.
2276 */
2277 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2278 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2279 alt_ioc_ready = 1;
2280 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302281 printk(MYIOC_s_WARN_FMT
2282 ": alt-ioc Not ready WARNING!\n",
2283 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 }
2285
2286 for (ii=0; ii<5; ii++) {
2287 /* Get IOC facts! Allow 5 retries */
2288 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2289 break;
2290 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002291
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
2293 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002294 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2295 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 ret = -2;
2297 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2298 MptDisplayIocCapabilities(ioc);
2299 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 if (alt_ioc_ready) {
2302 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302303 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302304 "Initial Alt IocFacts failed rc=%x\n",
2305 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 /* Retry - alt IOC was initialized once
2307 */
2308 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2309 }
2310 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302311 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002312 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 alt_ioc_ready = 0;
2314 reset_alt_ioc_active = 0;
2315 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2316 MptDisplayIocCapabilities(ioc->alt_ioc);
2317 }
2318 }
2319
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302320 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2321 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2322 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2323 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2324 IORESOURCE_IO);
2325 if (pci_enable_device(ioc->pcidev))
2326 return -5;
2327 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2328 "mpt"))
2329 return -5;
2330 }
2331
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002332 /*
2333 * Device is reset now. It must have de-asserted the interrupt line
2334 * (if it was asserted) and it should be safe to register for the
2335 * interrupt now.
2336 */
2337 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2338 ioc->pci_irq = -1;
2339 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302340 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002341 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002342 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302343 else
2344 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002345 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002346 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002347 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002348 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302349 "interrupt %d!\n",
2350 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302351 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002352 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302353 ret = -EBUSY;
2354 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002355 }
2356 irq_allocated = 1;
2357 ioc->pci_irq = ioc->pcidev->irq;
2358 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302359 pci_set_drvdata(ioc->pcidev, ioc);
2360 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2361 "installed at interrupt %d\n", ioc->name,
2362 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002363 }
2364 }
2365
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 /* Prime reply & request queues!
2367 * (mucho alloc's) Must be done prior to
2368 * init as upper addresses are needed for init.
2369 * If fails, continue with alt-ioc processing
2370 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302371 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2372 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2374 ret = -3;
2375
2376 /* May need to check/upload firmware & data here!
2377 * If fails, continue with alt-ioc processing
2378 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302379 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2380 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2382 ret = -4;
2383// NEW!
2384 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302385 printk(MYIOC_s_WARN_FMT
2386 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002387 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 alt_ioc_ready = 0;
2389 reset_alt_ioc_active = 0;
2390 }
2391
2392 if (alt_ioc_ready) {
2393 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2394 alt_ioc_ready = 0;
2395 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302396 printk(MYIOC_s_WARN_FMT
2397 ": alt-ioc: (%d) init failure WARNING!\n",
2398 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 }
2400 }
2401
2402 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2403 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302404 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002405 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
2407 /* Controller is not operational, cannot do upload
2408 */
2409 if (ret == 0) {
2410 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002411 if (rc == 0) {
2412 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2413 /*
2414 * Maintain only one pointer to FW memory
2415 * so there will not be two attempt to
2416 * downloadboot onboard dual function
2417 * chips (mpt_adapter_disable,
2418 * mpt_diag_reset)
2419 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302420 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002421 "mpt_upload: alt_%s has cached_fw=%p \n",
2422 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302423 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002424 }
2425 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002426 printk(MYIOC_s_WARN_FMT
2427 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302428 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 }
2431 }
2432 }
2433
Kashyap, Desaifd761752009-05-29 16:39:06 +05302434 /* Enable MPT base driver management of EventNotification
2435 * and EventAck handling.
2436 */
2437 if ((ret == 0) && (!ioc->facts.EventState)) {
2438 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2439 "SendEventNotification\n",
2440 ioc->name));
2441 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2442 }
2443
2444 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2445 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2446
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 if (ret == 0) {
2448 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002449 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 ioc->active = 1;
2451 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302452 if (rc == 0) { /* alt ioc */
2453 if (reset_alt_ioc_active && ioc->alt_ioc) {
2454 /* (re)Enable alt-IOC! (reply interrupt) */
2455 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2456 "reply irq re-enabled\n",
2457 ioc->alt_ioc->name));
2458 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2459 MPI_HIM_DIM);
2460 ioc->alt_ioc->active = 1;
2461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 }
2463
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002465 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2467 * recursive scenario; GetLanConfigPages times out, timer expired
2468 * routine calls HardResetHandler, which calls into here again,
2469 * and we try GetLanConfigPages again...
2470 */
2471 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002472
2473 /*
2474 * Initalize link list for inactive raid volumes.
2475 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002476 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002477 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2478
Kashyap, Desai2f187862009-05-29 16:52:37 +05302479 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002480
Kashyap, Desai2f187862009-05-29 16:52:37 +05302481 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002482 /* clear persistency table */
2483 if(ioc->facts.IOCExceptions &
2484 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2485 ret = mptbase_sas_persist_operation(ioc,
2486 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2487 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002488 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002489 }
2490
2491 /* Find IM volumes
2492 */
2493 mpt_findImVolumes(ioc);
2494
Kashyap, Desai2f187862009-05-29 16:52:37 +05302495 /* Check, and possibly reset, the coalescing value
2496 */
2497 mpt_read_ioc_pg_1(ioc);
2498
2499 break;
2500
2501 case FC:
2502 if ((ioc->pfacts[0].ProtocolFlags &
2503 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2505 /*
2506 * Pre-fetch the ports LAN MAC address!
2507 * (LANPage1_t stuff)
2508 */
2509 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302510 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2511 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302512 "LanAddr = %02X:%02X:%02X"
2513 ":%02X:%02X:%02X\n",
2514 ioc->name, a[5], a[4],
2515 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302517 break;
2518
2519 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 /* Get NVRAM and adapter maximums from SPP 0 and 2
2521 */
2522 mpt_GetScsiPortSettings(ioc, 0);
2523
2524 /* Get version and length of SDP 1
2525 */
2526 mpt_readScsiDevicePageHeaders(ioc, 0);
2527
2528 /* Find IM volumes
2529 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002530 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 mpt_findImVolumes(ioc);
2532
2533 /* Check, and possibly reset, the coalescing value
2534 */
2535 mpt_read_ioc_pg_1(ioc);
2536
2537 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302538
2539 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 }
2541
2542 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302543 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 }
2545
Eric Moore0ccdb002006-07-11 17:33:13 -06002546 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002547 if ((ret != 0) && irq_allocated) {
2548 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302549 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002550 pci_disable_msi(ioc->pcidev);
2551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 return ret;
2553}
2554
2555/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002556/**
2557 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 * @ioc: Pointer to MPT adapter structure
2559 * @pdev: Pointer to (struct pci_dev) structure
2560 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002561 * Search for PCI bus/dev_function which matches
2562 * PCI bus/dev_function (+/-1) for newly discovered 929,
2563 * 929X, 1030 or 1035.
2564 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2566 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2567 */
2568static void
2569mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2570{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002571 struct pci_dev *peer=NULL;
2572 unsigned int slot = PCI_SLOT(pdev->devfn);
2573 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 MPT_ADAPTER *ioc_srch;
2575
Prakash, Sathya436ace72007-07-24 15:42:08 +05302576 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002577 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002578 ioc->name, pci_name(pdev), pdev->bus->number,
2579 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002580
2581 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2582 if (!peer) {
2583 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2584 if (!peer)
2585 return;
2586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
2588 list_for_each_entry(ioc_srch, &ioc_list, list) {
2589 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002590 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 /* Paranoia checks */
2592 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302593 printk(MYIOC_s_WARN_FMT
2594 "Oops, already bound (%s <==> %s)!\n",
2595 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 break;
2597 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302598 printk(MYIOC_s_WARN_FMT
2599 "Oops, already bound (%s <==> %s)!\n",
2600 ioc_srch->name, ioc_srch->name,
2601 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 break;
2603 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302604 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2605 "FOUND! binding %s <==> %s\n",
2606 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 ioc_srch->alt_ioc = ioc;
2608 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 }
2610 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002611 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612}
2613
2614/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002615/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002617 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 */
2619static void
2620mpt_adapter_disable(MPT_ADAPTER *ioc)
2621{
2622 int sz;
2623 int ret;
2624
2625 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302626 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2627 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302628 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2629 ioc->cached_fw, CAN_SLEEP)) < 0) {
2630 printk(MYIOC_s_WARN_FMT
2631 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002632 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 }
2634 }
2635
Kashyap, Desai71278192009-05-29 16:53:14 +05302636 /*
2637 * Put the controller into ready state (if its not already)
2638 */
2639 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2640 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2641 CAN_SLEEP)) {
2642 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2643 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2644 "reset failed to put ioc in ready state!\n",
2645 ioc->name, __func__);
2646 } else
2647 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2648 "failed!\n", ioc->name, __func__);
2649 }
2650
2651
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302653 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2655 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302656
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 /* Clear any lingering interrupt */
2658 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302659 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
2661 if (ioc->alloc != NULL) {
2662 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002663 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2664 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 pci_free_consistent(ioc->pcidev, sz,
2666 ioc->alloc, ioc->alloc_dma);
2667 ioc->reply_frames = NULL;
2668 ioc->req_frames = NULL;
2669 ioc->alloc = NULL;
2670 ioc->alloc_total -= sz;
2671 }
2672
2673 if (ioc->sense_buf_pool != NULL) {
2674 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2675 pci_free_consistent(ioc->pcidev, sz,
2676 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2677 ioc->sense_buf_pool = NULL;
2678 ioc->alloc_total -= sz;
2679 }
2680
2681 if (ioc->events != NULL){
2682 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2683 kfree(ioc->events);
2684 ioc->events = NULL;
2685 ioc->alloc_total -= sz;
2686 }
2687
Prakash, Sathya984621b2008-01-11 14:42:17 +05302688 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002690 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002691 mpt_inactive_raid_list_free(ioc);
2692 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002693 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002694 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002695 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
2697 if (ioc->spi_data.pIocPg4 != NULL) {
2698 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302699 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 ioc->spi_data.pIocPg4,
2701 ioc->spi_data.IocPg4_dma);
2702 ioc->spi_data.pIocPg4 = NULL;
2703 ioc->alloc_total -= sz;
2704 }
2705
2706 if (ioc->ReqToChain != NULL) {
2707 kfree(ioc->ReqToChain);
2708 kfree(ioc->RequestNB);
2709 ioc->ReqToChain = NULL;
2710 }
2711
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002712 kfree(ioc->ChainToChain);
2713 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002714
2715 if (ioc->HostPageBuffer != NULL) {
2716 if((ret = mpt_host_page_access_control(ioc,
2717 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002718 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302719 ": %s: host page buffers free failed (%d)!\n",
2720 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002721 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302722 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2723 "HostPageBuffer free @ %p, sz=%d bytes\n",
2724 ioc->name, ioc->HostPageBuffer,
2725 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002726 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002727 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002728 ioc->HostPageBuffer = NULL;
2729 ioc->HostPageBuffer_sz = 0;
2730 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732
Kashyap, Desai2f187862009-05-29 16:52:37 +05302733 pci_set_drvdata(ioc->pcidev, NULL);
2734}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002736/**
2737 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 * @ioc: Pointer to MPT adapter structure
2739 *
2740 * This routine unregisters h/w resources and frees all alloc'd memory
2741 * associated with a MPT adapter structure.
2742 */
2743static void
2744mpt_adapter_dispose(MPT_ADAPTER *ioc)
2745{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002746 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002748 if (ioc == NULL)
2749 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002751 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002753 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002755 if (ioc->pci_irq != -1) {
2756 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302757 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002758 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002759 ioc->pci_irq = -1;
2760 }
2761
2762 if (ioc->memmap != NULL) {
2763 iounmap(ioc->memmap);
2764 ioc->memmap = NULL;
2765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302767 pci_disable_device(ioc->pcidev);
2768 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2769
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002771 if (ioc->mtrr_reg > 0) {
2772 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002773 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775#endif
2776
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002777 /* Zap the adapter lookup ptr! */
2778 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002780 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002781 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2782 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002783
2784 if (ioc->alt_ioc)
2785 ioc->alt_ioc->alt_ioc = NULL;
2786
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002787 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788}
2789
2790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002791/**
2792 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 * @ioc: Pointer to MPT adapter structure
2794 */
2795static void
2796MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2797{
2798 int i = 0;
2799
2800 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302801 if (ioc->prod_name)
2802 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 printk("Capabilities={");
2804
2805 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2806 printk("Initiator");
2807 i++;
2808 }
2809
2810 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2811 printk("%sTarget", i ? "," : "");
2812 i++;
2813 }
2814
2815 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2816 printk("%sLAN", i ? "," : "");
2817 i++;
2818 }
2819
2820#if 0
2821 /*
2822 * This would probably evoke more questions than it's worth
2823 */
2824 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2825 printk("%sLogBusAddr", i ? "," : "");
2826 i++;
2827 }
2828#endif
2829
2830 printk("}\n");
2831}
2832
2833/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002834/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2836 * @ioc: Pointer to MPT_ADAPTER structure
2837 * @force: Force hard KickStart of IOC
2838 * @sleepFlag: Specifies whether the process can sleep
2839 *
2840 * Returns:
2841 * 1 - DIAG reset and READY
2842 * 0 - READY initially OR soft reset and READY
2843 * -1 - Any failure on KickStart
2844 * -2 - Msg Unit Reset Failed
2845 * -3 - IO Unit Reset Failed
2846 * -4 - IOC owned by a PEER
2847 */
2848static int
2849MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2850{
2851 u32 ioc_state;
2852 int statefault = 0;
2853 int cntdn;
2854 int hard_reset_done = 0;
2855 int r;
2856 int ii;
2857 int whoinit;
2858
2859 /* Get current [raw] IOC state */
2860 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002861 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
2863 /*
2864 * Check to see if IOC got left/stuck in doorbell handshake
2865 * grip of death. If so, hard reset the IOC.
2866 */
2867 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2868 statefault = 1;
2869 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2870 ioc->name);
2871 }
2872
2873 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302874 if (!statefault &&
2875 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2876 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2877 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
2881 /*
2882 * Check to see if IOC is in FAULT state.
2883 */
2884 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2885 statefault = 2;
2886 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002887 ioc->name);
2888 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2889 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 }
2891
2892 /*
2893 * Hmmm... Did it get left operational?
2894 */
2895 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302896 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 ioc->name));
2898
2899 /* Check WhoInit.
2900 * If PCI Peer, exit.
2901 * Else, if no fault conditions are present, issue a MessageUnitReset
2902 * Else, fall through to KickStart case
2903 */
2904 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002905 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2906 "whoinit 0x%x statefault %d force %d\n",
2907 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 if (whoinit == MPI_WHOINIT_PCI_PEER)
2909 return -4;
2910 else {
2911 if ((statefault == 0 ) && (force == 0)) {
2912 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2913 return 0;
2914 }
2915 statefault = 3;
2916 }
2917 }
2918
2919 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2920 if (hard_reset_done < 0)
2921 return -1;
2922
2923 /*
2924 * Loop here waiting for IOC to come READY.
2925 */
2926 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002927 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928
2929 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2930 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2931 /*
2932 * BIOS or previous driver load left IOC in OP state.
2933 * Reset messaging FIFOs.
2934 */
2935 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2936 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2937 return -2;
2938 }
2939 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2940 /*
2941 * Something is wrong. Try to get IOC back
2942 * to a known state.
2943 */
2944 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2945 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2946 return -3;
2947 }
2948 }
2949
2950 ii++; cntdn--;
2951 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302952 printk(MYIOC_s_ERR_FMT
2953 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2954 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 return -ETIME;
2956 }
2957
2958 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002959 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 } else {
2961 mdelay (1); /* 1 msec delay */
2962 }
2963
2964 }
2965
2966 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302967 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2968 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 }
2970
2971 return hard_reset_done;
2972}
2973
2974/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002975/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 * mpt_GetIocState - Get the current state of a MPT adapter.
2977 * @ioc: Pointer to MPT_ADAPTER structure
2978 * @cooked: Request raw or cooked IOC state
2979 *
2980 * Returns all IOC Doorbell register bits if cooked==0, else just the
2981 * Doorbell bits in MPI_IOC_STATE_MASK.
2982 */
2983u32
2984mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2985{
2986 u32 s, sc;
2987
2988 /* Get! */
2989 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 sc = s & MPI_IOC_STATE_MASK;
2991
2992 /* Save! */
2993 ioc->last_state = sc;
2994
2995 return cooked ? sc : s;
2996}
2997
2998/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002999/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 * GetIocFacts - Send IOCFacts request to MPT adapter.
3001 * @ioc: Pointer to MPT_ADAPTER structure
3002 * @sleepFlag: Specifies whether the process can sleep
3003 * @reason: If recovery, only update facts.
3004 *
3005 * Returns 0 for success, non-zero for failure.
3006 */
3007static int
3008GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3009{
3010 IOCFacts_t get_facts;
3011 IOCFactsReply_t *facts;
3012 int r;
3013 int req_sz;
3014 int reply_sz;
3015 int sz;
3016 u32 status, vv;
3017 u8 shiftFactor=1;
3018
3019 /* IOC *must* NOT be in RESET state! */
3020 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303021 printk(KERN_ERR MYNAM
3022 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3023 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 return -44;
3025 }
3026
3027 facts = &ioc->facts;
3028
3029 /* Destination (reply area)... */
3030 reply_sz = sizeof(*facts);
3031 memset(facts, 0, reply_sz);
3032
3033 /* Request area (get_facts on the stack right now!) */
3034 req_sz = sizeof(get_facts);
3035 memset(&get_facts, 0, req_sz);
3036
3037 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3038 /* Assert: All other get_facts fields are zero! */
3039
Prakash, Sathya436ace72007-07-24 15:42:08 +05303040 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003041 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 ioc->name, req_sz, reply_sz));
3043
3044 /* No non-zero fields in the get_facts request are greater than
3045 * 1 byte in size, so we can just fire it off as is.
3046 */
3047 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3048 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3049 if (r != 0)
3050 return r;
3051
3052 /*
3053 * Now byte swap (GRRR) the necessary fields before any further
3054 * inspection of reply contents.
3055 *
3056 * But need to do some sanity checks on MsgLength (byte) field
3057 * to make sure we don't zero IOC's req_sz!
3058 */
3059 /* Did we get a valid reply? */
3060 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3061 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3062 /*
3063 * If not been here, done that, save off first WhoInit value
3064 */
3065 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3066 ioc->FirstWhoInit = facts->WhoInit;
3067 }
3068
3069 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3070 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3071 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3072 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3073 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003074 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 /* CHECKME! IOCStatus, IOCLogInfo */
3076
3077 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3078 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3079
3080 /*
3081 * FC f/w version changed between 1.1 and 1.2
3082 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3083 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3084 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303085 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 /*
3087 * Handle old FC f/w style, convert to new...
3088 */
3089 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3090 facts->FWVersion.Word =
3091 ((oldv<<12) & 0xFF000000) |
3092 ((oldv<<8) & 0x000FFF00);
3093 } else
3094 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3095
3096 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303097
Eric Mooreb506ade2007-01-29 09:45:37 -07003098 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3099 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3100 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303101
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 facts->CurrentHostMfaHighAddr =
3103 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3104 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3105 facts->CurrentSenseBufferHighAddr =
3106 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3107 facts->CurReplyFrameSize =
3108 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003109 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110
3111 /*
3112 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3113 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3114 * to 14 in MPI-1.01.0x.
3115 */
3116 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303117 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3119 }
3120
3121 sz = facts->FWImageSize;
3122 if ( sz & 0x01 )
3123 sz += 1;
3124 if ( sz & 0x02 )
3125 sz += 2;
3126 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003127
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 if (!facts->RequestFrameSize) {
3129 /* Something is wrong! */
3130 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3131 ioc->name);
3132 return -55;
3133 }
3134
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003135 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 vv = ((63 / (sz * 4)) + 1) & 0x03;
3137 ioc->NB_for_64_byte_frame = vv;
3138 while ( sz )
3139 {
3140 shiftFactor++;
3141 sz = sz >> 1;
3142 }
3143 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303144 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003145 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3146 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003147
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3149 /*
3150 * Set values for this IOC's request & reply frame sizes,
3151 * and request & reply queue depths...
3152 */
3153 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3154 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3155 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3156 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3157
Prakash, Sathya436ace72007-07-24 15:42:08 +05303158 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303160 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 ioc->name, ioc->req_sz, ioc->req_depth));
3162
3163 /* Get port facts! */
3164 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3165 return r;
3166 }
3167 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003168 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3170 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3171 RequestFrameSize)/sizeof(u32)));
3172 return -66;
3173 }
3174
3175 return 0;
3176}
3177
3178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003179/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 * GetPortFacts - Send PortFacts request to MPT adapter.
3181 * @ioc: Pointer to MPT_ADAPTER structure
3182 * @portnum: Port number
3183 * @sleepFlag: Specifies whether the process can sleep
3184 *
3185 * Returns 0 for success, non-zero for failure.
3186 */
3187static int
3188GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3189{
3190 PortFacts_t get_pfacts;
3191 PortFactsReply_t *pfacts;
3192 int ii;
3193 int req_sz;
3194 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003195 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
3197 /* IOC *must* NOT be in RESET state! */
3198 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003199 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3200 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 return -4;
3202 }
3203
3204 pfacts = &ioc->pfacts[portnum];
3205
3206 /* Destination (reply area)... */
3207 reply_sz = sizeof(*pfacts);
3208 memset(pfacts, 0, reply_sz);
3209
3210 /* Request area (get_pfacts on the stack right now!) */
3211 req_sz = sizeof(get_pfacts);
3212 memset(&get_pfacts, 0, req_sz);
3213
3214 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3215 get_pfacts.PortNumber = portnum;
3216 /* Assert: All other get_pfacts fields are zero! */
3217
Prakash, Sathya436ace72007-07-24 15:42:08 +05303218 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 ioc->name, portnum));
3220
3221 /* No non-zero fields in the get_pfacts request are greater than
3222 * 1 byte in size, so we can just fire it off as is.
3223 */
3224 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3225 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3226 if (ii != 0)
3227 return ii;
3228
3229 /* Did we get a valid reply? */
3230
3231 /* Now byte swap the necessary fields in the response. */
3232 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3233 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3234 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3235 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3236 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3237 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3238 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3239 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3240 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3241
Eric Moore793955f2007-01-29 09:42:20 -07003242 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3243 pfacts->MaxDevices;
3244 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3245 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3246
3247 /*
3248 * Place all the devices on channels
3249 *
3250 * (for debuging)
3251 */
3252 if (mpt_channel_mapping) {
3253 ioc->devices_per_bus = 1;
3254 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3255 }
3256
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 return 0;
3258}
3259
3260/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003261/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 * SendIocInit - Send IOCInit request to MPT adapter.
3263 * @ioc: Pointer to MPT_ADAPTER structure
3264 * @sleepFlag: Specifies whether the process can sleep
3265 *
3266 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3267 *
3268 * Returns 0 for success, non-zero for failure.
3269 */
3270static int
3271SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3272{
3273 IOCInit_t ioc_init;
3274 MPIDefaultReply_t init_reply;
3275 u32 state;
3276 int r;
3277 int count;
3278 int cntdn;
3279
3280 memset(&ioc_init, 0, sizeof(ioc_init));
3281 memset(&init_reply, 0, sizeof(init_reply));
3282
3283 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3284 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3285
3286 /* If we are in a recovery mode and we uploaded the FW image,
3287 * then this pointer is not NULL. Skip the upload a second time.
3288 * Set this flag if cached_fw set for either IOC.
3289 */
3290 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3291 ioc->upload_fw = 1;
3292 else
3293 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303294 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3296
Eric Moore793955f2007-01-29 09:42:20 -07003297 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3298 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303299
Prakash, Sathya436ace72007-07-24 15:42:08 +05303300 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003301 ioc->name, ioc->facts.MsgVersion));
3302 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3303 // set MsgVersion and HeaderVersion host driver was built with
3304 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3305 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003307 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3308 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3309 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3310 return -99;
3311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3313
Kashyap, Desai2f187862009-05-29 16:52:37 +05303314 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 /* Save the upper 32-bits of the request
3316 * (reply) and sense buffers.
3317 */
3318 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3319 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3320 } else {
3321 /* Force 32-bit addressing */
3322 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3323 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3324 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003325
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3327 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003328 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3329 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330
Prakash, Sathya436ace72007-07-24 15:42:08 +05303331 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 ioc->name, &ioc_init));
3333
3334 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3335 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003336 if (r != 0) {
3337 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340
3341 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003342 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 */
3344
Prakash, Sathya436ace72007-07-24 15:42:08 +05303345 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003347
3348 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3349 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352
3353 /* YIKES! SUPER IMPORTANT!!!
3354 * Poll IocState until _OPERATIONAL while IOC is doing
3355 * LoopInit and TargetDiscovery!
3356 */
3357 count = 0;
3358 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3359 state = mpt_GetIocState(ioc, 1);
3360 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3361 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003362 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 } else {
3364 mdelay(1);
3365 }
3366
3367 if (!cntdn) {
3368 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3369 ioc->name, (int)((count+5)/HZ));
3370 return -9;
3371 }
3372
3373 state = mpt_GetIocState(ioc, 1);
3374 count++;
3375 }
Eric Moore29dd3602007-09-14 18:46:51 -06003376 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 ioc->name, count));
3378
Eric Mooreba856d32006-07-11 17:34:01 -06003379 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 return r;
3381}
3382
3383/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003384/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 * SendPortEnable - Send PortEnable request to MPT adapter port.
3386 * @ioc: Pointer to MPT_ADAPTER structure
3387 * @portnum: Port number to enable
3388 * @sleepFlag: Specifies whether the process can sleep
3389 *
3390 * Send PortEnable to bring IOC to OPERATIONAL state.
3391 *
3392 * Returns 0 for success, non-zero for failure.
3393 */
3394static int
3395SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3396{
3397 PortEnable_t port_enable;
3398 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003399 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 int req_sz;
3401 int reply_sz;
3402
3403 /* Destination... */
3404 reply_sz = sizeof(MPIDefaultReply_t);
3405 memset(&reply_buf, 0, reply_sz);
3406
3407 req_sz = sizeof(PortEnable_t);
3408 memset(&port_enable, 0, req_sz);
3409
3410 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3411 port_enable.PortNumber = portnum;
3412/* port_enable.ChainOffset = 0; */
3413/* port_enable.MsgFlags = 0; */
3414/* port_enable.MsgContext = 0; */
3415
Prakash, Sathya436ace72007-07-24 15:42:08 +05303416 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 ioc->name, portnum, &port_enable));
3418
3419 /* RAID FW may take a long time to enable
3420 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003421 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003422 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3423 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3424 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003425 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003426 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3427 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3428 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003430 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431}
3432
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003433/**
3434 * mpt_alloc_fw_memory - allocate firmware memory
3435 * @ioc: Pointer to MPT_ADAPTER structure
3436 * @size: total FW bytes
3437 *
3438 * If memory has already been allocated, the same (cached) value
3439 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303440 *
3441 * Return 0 if successfull, or non-zero for failure
3442 **/
3443int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3445{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303446 int rc;
3447
3448 if (ioc->cached_fw) {
3449 rc = 0; /* use already allocated memory */
3450 goto out;
3451 }
3452 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3454 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303455 rc = 0;
3456 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303458 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3459 if (!ioc->cached_fw) {
3460 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3461 ioc->name);
3462 rc = -1;
3463 } else {
3464 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3465 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3466 ioc->alloc_total += size;
3467 rc = 0;
3468 }
3469 out:
3470 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303472
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003473/**
3474 * mpt_free_fw_memory - free firmware memory
3475 * @ioc: Pointer to MPT_ADAPTER structure
3476 *
3477 * If alt_img is NULL, delete from ioc structure.
3478 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303479 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480void
3481mpt_free_fw_memory(MPT_ADAPTER *ioc)
3482{
3483 int sz;
3484
Prakash, Sathya984621b2008-01-11 14:42:17 +05303485 if (!ioc->cached_fw)
3486 return;
3487
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303489 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3490 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003491 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303492 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494}
3495
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003497/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3499 * @ioc: Pointer to MPT_ADAPTER structure
3500 * @sleepFlag: Specifies whether the process can sleep
3501 *
3502 * Returns 0 for success, >0 for handshake failure
3503 * <0 for fw upload failure.
3504 *
3505 * Remark: If bound IOC and a successful FWUpload was performed
3506 * on the bound IOC, the second image is discarded
3507 * and memory is free'd. Both channels must upload to prevent
3508 * IOC from running in degraded mode.
3509 */
3510static int
3511mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3512{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 u8 reply[sizeof(FWUploadReply_t)];
3514 FWUpload_t *prequest;
3515 FWUploadReply_t *preply;
3516 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 u32 flagsLength;
3518 int ii, sz, reply_sz;
3519 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303520 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 /* If the image size is 0, we are done.
3522 */
3523 if ((sz = ioc->facts.FWImageSize) == 0)
3524 return 0;
3525
Prakash, Sathya984621b2008-01-11 14:42:17 +05303526 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3527 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528
Eric Moore29dd3602007-09-14 18:46:51 -06003529 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3530 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003531
Eric Moorebc6e0892007-09-29 10:16:28 -06003532 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3533 kzalloc(ioc->req_sz, GFP_KERNEL);
3534 if (!prequest) {
3535 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3536 "while allocating memory \n", ioc->name));
3537 mpt_free_fw_memory(ioc);
3538 return -ENOMEM;
3539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540
Eric Moorebc6e0892007-09-29 10:16:28 -06003541 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
3543 reply_sz = sizeof(reply);
3544 memset(preply, 0, reply_sz);
3545
3546 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3547 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3548
3549 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3550 ptcsge->DetailsLength = 12;
3551 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3552 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003553 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303556 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3557 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3558 ioc->SGE_size;
3559 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3560 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3561 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003562 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303564 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3565 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
Kashyap, Desai2f187862009-05-29 16:52:37 +05303567 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3568 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
3570 cmdStatus = -EFAULT;
3571 if (ii == 0) {
3572 /* Handshake transfer was complete and successful.
3573 * Check the Reply Frame.
3574 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303575 int status;
3576 status = le16_to_cpu(preply->IOCStatus) &
3577 MPI_IOCSTATUS_MASK;
3578 if (status == MPI_IOCSTATUS_SUCCESS &&
3579 ioc->facts.FWImageSize ==
3580 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303583 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 ioc->name, cmdStatus));
3585
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003586
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303588 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3589 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 mpt_free_fw_memory(ioc);
3591 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003592 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593
3594 return cmdStatus;
3595}
3596
3597/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003598/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 * mpt_downloadboot - DownloadBoot code
3600 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003601 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 * @sleepFlag: Specifies whether the process can sleep
3603 *
3604 * FwDownloadBoot requires Programmed IO access.
3605 *
3606 * Returns 0 for success
3607 * -1 FW Image size is 0
3608 * -2 No valid cached_fw Pointer
3609 * <0 for fw upload failure.
3610 */
3611static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003612mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 MpiExtImageHeader_t *pExtImage;
3615 u32 fwSize;
3616 u32 diag0val;
3617 int count;
3618 u32 *ptrFw;
3619 u32 diagRwData;
3620 u32 nextImage;
3621 u32 load_addr;
3622 u32 ioc_state=0;
3623
Prakash, Sathya436ace72007-07-24 15:42:08 +05303624 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003625 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003626
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3628 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3629 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3630 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3631 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3632 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3633
3634 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3635
3636 /* wait 1 msec */
3637 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003638 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 } else {
3640 mdelay (1);
3641 }
3642
3643 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3644 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3645
3646 for (count = 0; count < 30; count ++) {
3647 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3648 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303649 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 ioc->name, count));
3651 break;
3652 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003653 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003655 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003657 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 }
3659 }
3660
3661 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303662 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003663 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 ioc->name, diag0val));
3665 return -3;
3666 }
3667
3668 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3669 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3670 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3671 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3672 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3673 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3674
3675 /* Set the DiagRwEn and Disable ARM bits */
3676 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 fwSize = (pFwHeader->ImageSize + 3)/4;
3679 ptrFw = (u32 *) pFwHeader;
3680
3681 /* Write the LoadStartAddress to the DiagRw Address Register
3682 * using Programmed IO
3683 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003684 if (ioc->errata_flag_1064)
3685 pci_enable_io_access(ioc->pcidev);
3686
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303688 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 ioc->name, pFwHeader->LoadStartAddress));
3690
Prakash, Sathya436ace72007-07-24 15:42:08 +05303691 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 ioc->name, fwSize*4, ptrFw));
3693 while (fwSize--) {
3694 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3695 }
3696
3697 nextImage = pFwHeader->NextImageHeaderOffset;
3698 while (nextImage) {
3699 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3700
3701 load_addr = pExtImage->LoadStartAddress;
3702
3703 fwSize = (pExtImage->ImageSize + 3) >> 2;
3704 ptrFw = (u32 *)pExtImage;
3705
Prakash, Sathya436ace72007-07-24 15:42:08 +05303706 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 +02003707 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3709
3710 while (fwSize--) {
3711 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3712 }
3713 nextImage = pExtImage->NextImageHeaderOffset;
3714 }
3715
3716 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303717 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3719
3720 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303721 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3723
3724 /* Clear the internal flash bad bit - autoincrementing register,
3725 * so must do two writes.
3726 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003727 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003728 /*
3729 * 1030 and 1035 H/W errata, workaround to access
3730 * the ClearFlashBadSignatureBit
3731 */
3732 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3733 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3734 diagRwData |= 0x40000000;
3735 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3736 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3737
3738 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3739 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3740 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3741 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3742
3743 /* wait 1 msec */
3744 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003745 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003746 } else {
3747 mdelay (1);
3748 }
3749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003751 if (ioc->errata_flag_1064)
3752 pci_disable_io_access(ioc->pcidev);
3753
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303755 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003756 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003758 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303759 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 ioc->name, diag0val));
3761 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3762
3763 /* Write 0xFF to reset the sequencer */
3764 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3765
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003766 if (ioc->bus_type == SAS) {
3767 ioc_state = mpt_GetIocState(ioc, 0);
3768 if ( (GetIocFacts(ioc, sleepFlag,
3769 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303770 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003771 ioc->name, ioc_state));
3772 return -EFAULT;
3773 }
3774 }
3775
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 for (count=0; count<HZ*20; count++) {
3777 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303778 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3779 "downloadboot successful! (count=%d) IocState=%x\n",
3780 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003781 if (ioc->bus_type == SAS) {
3782 return 0;
3783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303785 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3786 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 ioc->name));
3788 return -EFAULT;
3789 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303790 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3791 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 ioc->name));
3793 return 0;
3794 }
3795 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003796 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 } else {
3798 mdelay (10);
3799 }
3800 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303801 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3802 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 return -EFAULT;
3804}
3805
3806/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003807/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 * KickStart - Perform hard reset of MPT adapter.
3809 * @ioc: Pointer to MPT_ADAPTER structure
3810 * @force: Force hard reset
3811 * @sleepFlag: Specifies whether the process can sleep
3812 *
3813 * This routine places MPT adapter in diagnostic mode via the
3814 * WriteSequence register, and then performs a hard reset of adapter
3815 * via the Diagnostic register.
3816 *
3817 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3818 * or NO_SLEEP (interrupt thread, use mdelay)
3819 * force - 1 if doorbell active, board fault state
3820 * board operational, IOC_RECOVERY or
3821 * IOC_BRINGUP and there is an alt_ioc.
3822 * 0 else
3823 *
3824 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003825 * 1 - hard reset, READY
3826 * 0 - no reset due to History bit, READY
3827 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 * OR reset but failed to come READY
3829 * -2 - no reset, could not enter DIAG mode
3830 * -3 - reset but bad FW bit
3831 */
3832static int
3833KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3834{
3835 int hard_reset_done = 0;
3836 u32 ioc_state=0;
3837 int cnt,cntdn;
3838
Eric Moore29dd3602007-09-14 18:46:51 -06003839 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003840 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 /* Always issue a Msg Unit Reset first. This will clear some
3842 * SCSI bus hang conditions.
3843 */
3844 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3845
3846 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003847 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 } else {
3849 mdelay (1000);
3850 }
3851 }
3852
3853 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3854 if (hard_reset_done < 0)
3855 return hard_reset_done;
3856
Prakash, Sathya436ace72007-07-24 15:42:08 +05303857 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003858 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859
3860 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3861 for (cnt=0; cnt<cntdn; cnt++) {
3862 ioc_state = mpt_GetIocState(ioc, 1);
3863 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303864 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 ioc->name, cnt));
3866 return hard_reset_done;
3867 }
3868 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003869 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 } else {
3871 mdelay (10);
3872 }
3873 }
3874
Eric Moore29dd3602007-09-14 18:46:51 -06003875 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3876 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 return -1;
3878}
3879
3880/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003881/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 * mpt_diag_reset - Perform hard reset of the adapter.
3883 * @ioc: Pointer to MPT_ADAPTER structure
3884 * @ignore: Set if to honor and clear to ignore
3885 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003886 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 * else set to NO_SLEEP (use mdelay instead)
3888 *
3889 * This routine places the adapter in diagnostic mode via the
3890 * WriteSequence register and then performs a hard reset of adapter
3891 * via the Diagnostic register. Adapter should be in ready state
3892 * upon successful completion.
3893 *
3894 * Returns: 1 hard reset successful
3895 * 0 no reset performed because reset history bit set
3896 * -2 enabling diagnostic mode failed
3897 * -3 diagnostic reset failed
3898 */
3899static int
3900mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3901{
3902 u32 diag0val;
3903 u32 doorbell;
3904 int hard_reset_done = 0;
3905 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303907 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303908 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909
Eric Moorecd2c6192007-01-29 09:47:47 -07003910 /* Clear any existing interrupts */
3911 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3912
Eric Moore87cf8982006-06-27 16:09:26 -06003913 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303914
3915 if (!ignore)
3916 return 0;
3917
Prakash, Sathya436ace72007-07-24 15:42:08 +05303918 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003919 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003920 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3921 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3922 if (sleepFlag == CAN_SLEEP)
3923 msleep(1);
3924 else
3925 mdelay(1);
3926
Kashyap, Desaid1306912009-08-05 12:53:51 +05303927 /*
3928 * Call each currently registered protocol IOC reset handler
3929 * with pre-reset indication.
3930 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3931 * MptResetHandlers[] registered yet.
3932 */
3933 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3934 if (MptResetHandlers[cb_idx])
3935 (*(MptResetHandlers[cb_idx]))(ioc,
3936 MPT_IOC_PRE_RESET);
3937 }
3938
Eric Moore87cf8982006-06-27 16:09:26 -06003939 for (count = 0; count < 60; count ++) {
3940 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3941 doorbell &= MPI_IOC_STATE_MASK;
3942
Prakash, Sathya436ace72007-07-24 15:42:08 +05303943 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003944 "looking for READY STATE: doorbell=%x"
3945 " count=%d\n",
3946 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303947
Eric Moore87cf8982006-06-27 16:09:26 -06003948 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003949 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003950 }
3951
3952 /* wait 1 sec */
3953 if (sleepFlag == CAN_SLEEP)
3954 msleep(1000);
3955 else
3956 mdelay(1000);
3957 }
3958 return -1;
3959 }
3960
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 /* Use "Diagnostic reset" method! (only thing available!) */
3962 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3963
Prakash, Sathya436ace72007-07-24 15:42:08 +05303964 if (ioc->debug_level & MPT_DEBUG) {
3965 if (ioc->alt_ioc)
3966 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3967 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970
3971 /* Do the reset if we are told to ignore the reset history
3972 * or if the reset history is 0
3973 */
3974 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3975 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3976 /* Write magic sequence to WriteSequence register
3977 * Loop until in diagnostic mode
3978 */
3979 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3980 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3981 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3982 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3983 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3984 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3985
3986 /* wait 100 msec */
3987 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003988 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 } else {
3990 mdelay (100);
3991 }
3992
3993 count++;
3994 if (count > 20) {
3995 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3996 ioc->name, diag0val);
3997 return -2;
3998
3999 }
4000
4001 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4002
Prakash, Sathya436ace72007-07-24 15:42:08 +05304003 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 ioc->name, diag0val));
4005 }
4006
Prakash, Sathya436ace72007-07-24 15:42:08 +05304007 if (ioc->debug_level & MPT_DEBUG) {
4008 if (ioc->alt_ioc)
4009 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4010 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304012 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 /*
4014 * Disable the ARM (Bug fix)
4015 *
4016 */
4017 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004018 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019
4020 /*
4021 * Now hit the reset bit in the Diagnostic register
4022 * (THE BIG HAMMER!) (Clears DRWE bit).
4023 */
4024 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4025 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304026 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 ioc->name));
4028
4029 /*
4030 * Call each currently registered protocol IOC reset handler
4031 * with pre-reset indication.
4032 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4033 * MptResetHandlers[] registered yet.
4034 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304035 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4036 if (MptResetHandlers[cb_idx]) {
4037 mpt_signal_reset(cb_idx,
4038 ioc, MPT_IOC_PRE_RESET);
4039 if (ioc->alt_ioc) {
4040 mpt_signal_reset(cb_idx,
4041 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 }
4043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 }
4045
Eric Moore0ccdb002006-07-11 17:33:13 -06004046 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304047 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004048 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304049 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4050 else
4051 cached_fw = NULL;
4052 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 /* If the DownloadBoot operation fails, the
4054 * IOC will be left unusable. This is a fatal error
4055 * case. _diag_reset will return < 0
4056 */
4057 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304058 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4060 break;
4061 }
4062
Prakash, Sathya436ace72007-07-24 15:42:08 +05304063 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304064 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 /* wait 1 sec */
4066 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004067 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 } else {
4069 mdelay (1000);
4070 }
4071 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304072 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004073 printk(MYIOC_s_WARN_FMT
4074 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 }
4076
4077 } else {
4078 /* Wait for FW to reload and for board
4079 * to go to the READY state.
4080 * Maximum wait is 60 seconds.
4081 * If fail, no error will check again
4082 * with calling program.
4083 */
4084 for (count = 0; count < 60; count ++) {
4085 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4086 doorbell &= MPI_IOC_STATE_MASK;
4087
Kashyap, Desai2f187862009-05-29 16:52:37 +05304088 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4089 "looking for READY STATE: doorbell=%x"
4090 " count=%d\n", ioc->name, doorbell, count));
4091
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 if (doorbell == MPI_IOC_STATE_READY) {
4093 break;
4094 }
4095
4096 /* wait 1 sec */
4097 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004098 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 } else {
4100 mdelay (1000);
4101 }
4102 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304103
4104 if (doorbell != MPI_IOC_STATE_READY)
4105 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4106 "after reset! IocState=%x", ioc->name,
4107 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 }
4109 }
4110
4111 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304112 if (ioc->debug_level & MPT_DEBUG) {
4113 if (ioc->alt_ioc)
4114 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4115 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4116 ioc->name, diag0val, diag1val));
4117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118
4119 /* Clear RESET_HISTORY bit! Place board in the
4120 * diagnostic mode to update the diag register.
4121 */
4122 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4123 count = 0;
4124 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4125 /* Write magic sequence to WriteSequence register
4126 * Loop until in diagnostic mode
4127 */
4128 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4129 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4130 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4131 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4132 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4133 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4134
4135 /* wait 100 msec */
4136 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004137 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 } else {
4139 mdelay (100);
4140 }
4141
4142 count++;
4143 if (count > 20) {
4144 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4145 ioc->name, diag0val);
4146 break;
4147 }
4148 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4149 }
4150 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4151 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4152 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4153 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4154 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4155 ioc->name);
4156 }
4157
4158 /* Disable Diagnostic Mode
4159 */
4160 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4161
4162 /* Check FW reload status flags.
4163 */
4164 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4165 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4166 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4167 ioc->name, diag0val);
4168 return -3;
4169 }
4170
Prakash, Sathya436ace72007-07-24 15:42:08 +05304171 if (ioc->debug_level & MPT_DEBUG) {
4172 if (ioc->alt_ioc)
4173 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4174 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177
4178 /*
4179 * Reset flag that says we've enabled event notification
4180 */
4181 ioc->facts.EventState = 0;
4182
4183 if (ioc->alt_ioc)
4184 ioc->alt_ioc->facts.EventState = 0;
4185
4186 return hard_reset_done;
4187}
4188
4189/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004190/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 * SendIocReset - Send IOCReset request to MPT adapter.
4192 * @ioc: Pointer to MPT_ADAPTER structure
4193 * @reset_type: reset type, expected values are
4194 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004195 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 *
4197 * Send IOCReset request to the MPT adapter.
4198 *
4199 * Returns 0 for success, non-zero for failure.
4200 */
4201static int
4202SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4203{
4204 int r;
4205 u32 state;
4206 int cntdn, count;
4207
Prakash, Sathya436ace72007-07-24 15:42:08 +05304208 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 ioc->name, reset_type));
4210 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4211 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4212 return r;
4213
4214 /* FW ACK'd request, wait for READY state
4215 */
4216 count = 0;
4217 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4218
4219 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4220 cntdn--;
4221 count++;
4222 if (!cntdn) {
4223 if (sleepFlag != CAN_SLEEP)
4224 count *= 10;
4225
Kashyap, Desai2f187862009-05-29 16:52:37 +05304226 printk(MYIOC_s_ERR_FMT
4227 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4228 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 return -ETIME;
4230 }
4231
4232 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004233 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 } else {
4235 mdelay (1); /* 1 msec delay */
4236 }
4237 }
4238
4239 /* TODO!
4240 * Cleanup all event stuff for this IOC; re-issue EventNotification
4241 * request if needed.
4242 */
4243 if (ioc->facts.Function)
4244 ioc->facts.EventState = 0;
4245
4246 return 0;
4247}
4248
4249/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004250/**
4251 * initChainBuffers - Allocate memory for and initialize chain buffers
4252 * @ioc: Pointer to MPT_ADAPTER structure
4253 *
4254 * Allocates memory for and initializes chain buffers,
4255 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 */
4257static int
4258initChainBuffers(MPT_ADAPTER *ioc)
4259{
4260 u8 *mem;
4261 int sz, ii, num_chain;
4262 int scale, num_sge, numSGE;
4263
4264 /* ReqToChain size must equal the req_depth
4265 * index = req_idx
4266 */
4267 if (ioc->ReqToChain == NULL) {
4268 sz = ioc->req_depth * sizeof(int);
4269 mem = kmalloc(sz, GFP_ATOMIC);
4270 if (mem == NULL)
4271 return -1;
4272
4273 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304274 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 ioc->name, mem, sz));
4276 mem = kmalloc(sz, GFP_ATOMIC);
4277 if (mem == NULL)
4278 return -1;
4279
4280 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304281 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 ioc->name, mem, sz));
4283 }
4284 for (ii = 0; ii < ioc->req_depth; ii++) {
4285 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4286 }
4287
4288 /* ChainToChain size must equal the total number
4289 * of chain buffers to be allocated.
4290 * index = chain_idx
4291 *
4292 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004293 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 *
4295 * num_sge = num sge in request frame + last chain buffer
4296 * scale = num sge per chain buffer if no chain element
4297 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304298 scale = ioc->req_sz / ioc->SGE_size;
4299 if (ioc->sg_addr_size == sizeof(u64))
4300 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304302 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304304 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304306 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304308 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4309 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304311 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 ioc->name, num_sge, numSGE));
4313
Kashyap, Desai2f187862009-05-29 16:52:37 +05304314 if (ioc->bus_type == FC) {
4315 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4316 numSGE = MPT_SCSI_FC_SG_DEPTH;
4317 } else {
4318 if (numSGE > MPT_SCSI_SG_DEPTH)
4319 numSGE = MPT_SCSI_SG_DEPTH;
4320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321
4322 num_chain = 1;
4323 while (numSGE - num_sge > 0) {
4324 num_chain++;
4325 num_sge += (scale - 1);
4326 }
4327 num_chain++;
4328
Prakash, Sathya436ace72007-07-24 15:42:08 +05304329 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 ioc->name, numSGE, num_sge, num_chain));
4331
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004332 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004334 else if (ioc->bus_type == SAS)
4335 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 else
4337 num_chain *= MPT_FC_CAN_QUEUE;
4338
4339 ioc->num_chain = num_chain;
4340
4341 sz = num_chain * sizeof(int);
4342 if (ioc->ChainToChain == NULL) {
4343 mem = kmalloc(sz, GFP_ATOMIC);
4344 if (mem == NULL)
4345 return -1;
4346
4347 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304348 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 ioc->name, mem, sz));
4350 } else {
4351 mem = (u8 *) ioc->ChainToChain;
4352 }
4353 memset(mem, 0xFF, sz);
4354 return num_chain;
4355}
4356
4357/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004358/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4360 * @ioc: Pointer to MPT_ADAPTER structure
4361 *
4362 * This routine allocates memory for the MPT reply and request frame
4363 * pools (if necessary), and primes the IOC reply FIFO with
4364 * reply frames.
4365 *
4366 * Returns 0 for success, non-zero for failure.
4367 */
4368static int
4369PrimeIocFifos(MPT_ADAPTER *ioc)
4370{
4371 MPT_FRAME_HDR *mf;
4372 unsigned long flags;
4373 dma_addr_t alloc_dma;
4374 u8 *mem;
4375 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304376 u64 dma_mask;
4377
4378 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
4380 /* Prime reply FIFO... */
4381
4382 if (ioc->reply_frames == NULL) {
4383 if ( (num_chain = initChainBuffers(ioc)) < 0)
4384 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304385 /*
4386 * 1078 errata workaround for the 36GB limitation
4387 */
4388 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004389 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304390 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4391 && !pci_set_consistent_dma_mask(ioc->pcidev,
4392 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004393 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304394 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4395 "setting 35 bit addressing for "
4396 "Request/Reply/Chain and Sense Buffers\n",
4397 ioc->name));
4398 } else {
4399 /*Reseting DMA mask to 64 bit*/
4400 pci_set_dma_mask(ioc->pcidev,
4401 DMA_BIT_MASK(64));
4402 pci_set_consistent_dma_mask(ioc->pcidev,
4403 DMA_BIT_MASK(64));
4404
4405 printk(MYIOC_s_ERR_FMT
4406 "failed setting 35 bit addressing for "
4407 "Request/Reply/Chain and Sense Buffers\n",
4408 ioc->name);
4409 return -1;
4410 }
4411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412
4413 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304414 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304416 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 ioc->name, reply_sz, reply_sz));
4418
4419 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304420 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304422 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 ioc->name, sz, sz));
4424 total_size += sz;
4425
4426 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304427 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304429 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 ioc->name, sz, sz, num_chain));
4431
4432 total_size += sz;
4433 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4434 if (mem == NULL) {
4435 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4436 ioc->name);
4437 goto out_fail;
4438 }
4439
Prakash, Sathya436ace72007-07-24 15:42:08 +05304440 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4442
4443 memset(mem, 0, total_size);
4444 ioc->alloc_total += total_size;
4445 ioc->alloc = mem;
4446 ioc->alloc_dma = alloc_dma;
4447 ioc->alloc_sz = total_size;
4448 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4449 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4450
Prakash, Sathya436ace72007-07-24 15:42:08 +05304451 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004452 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4453
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 alloc_dma += reply_sz;
4455 mem += reply_sz;
4456
4457 /* Request FIFO - WE manage this! */
4458
4459 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4460 ioc->req_frames_dma = alloc_dma;
4461
Prakash, Sathya436ace72007-07-24 15:42:08 +05304462 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 ioc->name, mem, (void *)(ulong)alloc_dma));
4464
4465 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4466
4467#if defined(CONFIG_MTRR) && 0
4468 /*
4469 * Enable Write Combining MTRR for IOC's memory region.
4470 * (at least as much as we can; "size and base must be
4471 * multiples of 4 kiB"
4472 */
4473 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4474 sz,
4475 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304476 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 ioc->name, ioc->req_frames_dma, sz));
4478#endif
4479
4480 for (i = 0; i < ioc->req_depth; i++) {
4481 alloc_dma += ioc->req_sz;
4482 mem += ioc->req_sz;
4483 }
4484
4485 ioc->ChainBuffer = mem;
4486 ioc->ChainBufferDMA = alloc_dma;
4487
Prakash, Sathya436ace72007-07-24 15:42:08 +05304488 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4490
4491 /* Initialize the free chain Q.
4492 */
4493
4494 INIT_LIST_HEAD(&ioc->FreeChainQ);
4495
4496 /* Post the chain buffers to the FreeChainQ.
4497 */
4498 mem = (u8 *)ioc->ChainBuffer;
4499 for (i=0; i < num_chain; i++) {
4500 mf = (MPT_FRAME_HDR *) mem;
4501 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4502 mem += ioc->req_sz;
4503 }
4504
4505 /* Initialize Request frames linked list
4506 */
4507 alloc_dma = ioc->req_frames_dma;
4508 mem = (u8 *) ioc->req_frames;
4509
4510 spin_lock_irqsave(&ioc->FreeQlock, flags);
4511 INIT_LIST_HEAD(&ioc->FreeQ);
4512 for (i = 0; i < ioc->req_depth; i++) {
4513 mf = (MPT_FRAME_HDR *) mem;
4514
4515 /* Queue REQUESTs *internally*! */
4516 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4517
4518 mem += ioc->req_sz;
4519 }
4520 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4521
4522 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4523 ioc->sense_buf_pool =
4524 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4525 if (ioc->sense_buf_pool == NULL) {
4526 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4527 ioc->name);
4528 goto out_fail;
4529 }
4530
4531 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4532 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304533 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4535
4536 }
4537
4538 /* Post Reply frames to FIFO
4539 */
4540 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304541 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4543
4544 for (i = 0; i < ioc->reply_depth; i++) {
4545 /* Write each address to the IOC! */
4546 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4547 alloc_dma += ioc->reply_sz;
4548 }
4549
Andrew Morton8e20ce92009-06-18 16:49:17 -07004550 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304551 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4552 ioc->dma_mask))
4553 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4554 "restoring 64 bit addressing\n", ioc->name));
4555
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 return 0;
4557
4558out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304559
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 if (ioc->alloc != NULL) {
4561 sz = ioc->alloc_sz;
4562 pci_free_consistent(ioc->pcidev,
4563 sz,
4564 ioc->alloc, ioc->alloc_dma);
4565 ioc->reply_frames = NULL;
4566 ioc->req_frames = NULL;
4567 ioc->alloc_total -= sz;
4568 }
4569 if (ioc->sense_buf_pool != NULL) {
4570 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4571 pci_free_consistent(ioc->pcidev,
4572 sz,
4573 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4574 ioc->sense_buf_pool = NULL;
4575 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304576
Andrew Morton8e20ce92009-06-18 16:49:17 -07004577 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304578 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4579 DMA_BIT_MASK(64)))
4580 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4581 "restoring 64 bit addressing\n", ioc->name));
4582
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 return -1;
4584}
4585
4586/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4587/**
4588 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4589 * from IOC via doorbell handshake method.
4590 * @ioc: Pointer to MPT_ADAPTER structure
4591 * @reqBytes: Size of the request in bytes
4592 * @req: Pointer to MPT request frame
4593 * @replyBytes: Expected size of the reply in bytes
4594 * @u16reply: Pointer to area where reply should be written
4595 * @maxwait: Max wait time for a reply (in seconds)
4596 * @sleepFlag: Specifies whether the process can sleep
4597 *
4598 * NOTES: It is the callers responsibility to byte-swap fields in the
4599 * request which are greater than 1 byte in size. It is also the
4600 * callers responsibility to byte-swap response fields which are
4601 * greater than 1 byte in size.
4602 *
4603 * Returns 0 for success, non-zero for failure.
4604 */
4605static int
4606mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004607 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608{
4609 MPIDefaultReply_t *mptReply;
4610 int failcnt = 0;
4611 int t;
4612
4613 /*
4614 * Get ready to cache a handshake reply
4615 */
4616 ioc->hs_reply_idx = 0;
4617 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4618 mptReply->MsgLength = 0;
4619
4620 /*
4621 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4622 * then tell IOC that we want to handshake a request of N words.
4623 * (WRITE u32val to Doorbell reg).
4624 */
4625 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4626 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4627 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4628 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4629
4630 /*
4631 * Wait for IOC's doorbell handshake int
4632 */
4633 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4634 failcnt++;
4635
Prakash, Sathya436ace72007-07-24 15:42:08 +05304636 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4638
4639 /* Read doorbell and check for active bit */
4640 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4641 return -1;
4642
4643 /*
4644 * Clear doorbell int (WRITE 0 to IntStatus reg),
4645 * then wait for IOC to ACKnowledge that it's ready for
4646 * our handshake request.
4647 */
4648 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4649 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4650 failcnt++;
4651
4652 if (!failcnt) {
4653 int ii;
4654 u8 *req_as_bytes = (u8 *) req;
4655
4656 /*
4657 * Stuff request words via doorbell handshake,
4658 * with ACK from IOC for each.
4659 */
4660 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4661 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4662 (req_as_bytes[(ii*4) + 1] << 8) |
4663 (req_as_bytes[(ii*4) + 2] << 16) |
4664 (req_as_bytes[(ii*4) + 3] << 24));
4665
4666 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4667 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4668 failcnt++;
4669 }
4670
Prakash, Sathya436ace72007-07-24 15:42:08 +05304671 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004672 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673
Prakash, Sathya436ace72007-07-24 15:42:08 +05304674 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4676
4677 /*
4678 * Wait for completion of doorbell handshake reply from the IOC
4679 */
4680 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4681 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004682
Prakash, Sathya436ace72007-07-24 15:42:08 +05304683 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4685
4686 /*
4687 * Copy out the cached reply...
4688 */
4689 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4690 u16reply[ii] = ioc->hs_reply[ii];
4691 } else {
4692 return -99;
4693 }
4694
4695 return -failcnt;
4696}
4697
4698/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004699/**
4700 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 * @ioc: Pointer to MPT_ADAPTER structure
4702 * @howlong: How long to wait (in seconds)
4703 * @sleepFlag: Specifies whether the process can sleep
4704 *
4705 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004706 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4707 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 *
4709 * Returns a negative value on failure, else wait loop count.
4710 */
4711static int
4712WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4713{
4714 int cntdn;
4715 int count = 0;
4716 u32 intstat=0;
4717
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004718 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719
4720 if (sleepFlag == CAN_SLEEP) {
4721 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004722 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4724 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4725 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 count++;
4727 }
4728 } else {
4729 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004730 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4732 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4733 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 count++;
4735 }
4736 }
4737
4738 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304739 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 ioc->name, count));
4741 return count;
4742 }
4743
4744 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4745 ioc->name, count, intstat);
4746 return -1;
4747}
4748
4749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004750/**
4751 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 * @ioc: Pointer to MPT_ADAPTER structure
4753 * @howlong: How long to wait (in seconds)
4754 * @sleepFlag: Specifies whether the process can sleep
4755 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004756 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4757 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 *
4759 * Returns a negative value on failure, else wait loop count.
4760 */
4761static int
4762WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4763{
4764 int cntdn;
4765 int count = 0;
4766 u32 intstat=0;
4767
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004768 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 if (sleepFlag == CAN_SLEEP) {
4770 while (--cntdn) {
4771 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4772 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4773 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004774 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 count++;
4776 }
4777 } else {
4778 while (--cntdn) {
4779 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4780 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4781 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004782 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 count++;
4784 }
4785 }
4786
4787 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304788 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 ioc->name, count, howlong));
4790 return count;
4791 }
4792
4793 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4794 ioc->name, count, intstat);
4795 return -1;
4796}
4797
4798/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004799/**
4800 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 * @ioc: Pointer to MPT_ADAPTER structure
4802 * @howlong: How long to wait (in seconds)
4803 * @sleepFlag: Specifies whether the process can sleep
4804 *
4805 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4806 * Reply is cached to IOC private area large enough to hold a maximum
4807 * of 128 bytes of reply data.
4808 *
4809 * Returns a negative value on failure, else size of reply in WORDS.
4810 */
4811static int
4812WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4813{
4814 int u16cnt = 0;
4815 int failcnt = 0;
4816 int t;
4817 u16 *hs_reply = ioc->hs_reply;
4818 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4819 u16 hword;
4820
4821 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4822
4823 /*
4824 * Get first two u16's so we can look at IOC's intended reply MsgLength
4825 */
4826 u16cnt=0;
4827 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4828 failcnt++;
4829 } else {
4830 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4831 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4832 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4833 failcnt++;
4834 else {
4835 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4836 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4837 }
4838 }
4839
Prakash, Sathya436ace72007-07-24 15:42:08 +05304840 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004841 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4843
4844 /*
4845 * If no error (and IOC said MsgLength is > 0), piece together
4846 * reply 16 bits at a time.
4847 */
4848 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4849 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4850 failcnt++;
4851 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4852 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004853 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 hs_reply[u16cnt] = hword;
4855 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4856 }
4857
4858 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4859 failcnt++;
4860 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4861
4862 if (failcnt) {
4863 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4864 ioc->name);
4865 return -failcnt;
4866 }
4867#if 0
4868 else if (u16cnt != (2 * mptReply->MsgLength)) {
4869 return -101;
4870 }
4871 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4872 return -102;
4873 }
4874#endif
4875
Prakash, Sathya436ace72007-07-24 15:42:08 +05304876 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004877 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878
Prakash, Sathya436ace72007-07-24 15:42:08 +05304879 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 ioc->name, t, u16cnt/2));
4881 return u16cnt/2;
4882}
4883
4884/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004885/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 * GetLanConfigPages - Fetch LANConfig pages.
4887 * @ioc: Pointer to MPT_ADAPTER structure
4888 *
4889 * Return: 0 for success
4890 * -ENOMEM if no memory available
4891 * -EPERM if not allowed due to ISR context
4892 * -EAGAIN if no msg frames currently available
4893 * -EFAULT for non-successful reply or no reply (timeout)
4894 */
4895static int
4896GetLanConfigPages(MPT_ADAPTER *ioc)
4897{
4898 ConfigPageHeader_t hdr;
4899 CONFIGPARMS cfg;
4900 LANPage0_t *ppage0_alloc;
4901 dma_addr_t page0_dma;
4902 LANPage1_t *ppage1_alloc;
4903 dma_addr_t page1_dma;
4904 int rc = 0;
4905 int data_sz;
4906 int copy_sz;
4907
4908 /* Get LAN Page 0 header */
4909 hdr.PageVersion = 0;
4910 hdr.PageLength = 0;
4911 hdr.PageNumber = 0;
4912 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004913 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914 cfg.physAddr = -1;
4915 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4916 cfg.dir = 0;
4917 cfg.pageAddr = 0;
4918 cfg.timeout = 0;
4919
4920 if ((rc = mpt_config(ioc, &cfg)) != 0)
4921 return rc;
4922
4923 if (hdr.PageLength > 0) {
4924 data_sz = hdr.PageLength * 4;
4925 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4926 rc = -ENOMEM;
4927 if (ppage0_alloc) {
4928 memset((u8 *)ppage0_alloc, 0, data_sz);
4929 cfg.physAddr = page0_dma;
4930 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4931
4932 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4933 /* save the data */
4934 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4935 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4936
4937 }
4938
4939 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4940
4941 /* FIXME!
4942 * Normalize endianness of structure data,
4943 * by byte-swapping all > 1 byte fields!
4944 */
4945
4946 }
4947
4948 if (rc)
4949 return rc;
4950 }
4951
4952 /* Get LAN Page 1 header */
4953 hdr.PageVersion = 0;
4954 hdr.PageLength = 0;
4955 hdr.PageNumber = 1;
4956 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004957 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958 cfg.physAddr = -1;
4959 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4960 cfg.dir = 0;
4961 cfg.pageAddr = 0;
4962
4963 if ((rc = mpt_config(ioc, &cfg)) != 0)
4964 return rc;
4965
4966 if (hdr.PageLength == 0)
4967 return 0;
4968
4969 data_sz = hdr.PageLength * 4;
4970 rc = -ENOMEM;
4971 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4972 if (ppage1_alloc) {
4973 memset((u8 *)ppage1_alloc, 0, data_sz);
4974 cfg.physAddr = page1_dma;
4975 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4976
4977 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4978 /* save the data */
4979 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4980 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4981 }
4982
4983 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4984
4985 /* FIXME!
4986 * Normalize endianness of structure data,
4987 * by byte-swapping all > 1 byte fields!
4988 */
4989
4990 }
4991
4992 return rc;
4993}
4994
4995/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004996/**
4997 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004998 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004999 * @persist_opcode: see below
5000 *
5001 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5002 * devices not currently present.
5003 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5004 *
5005 * NOTE: Don't use not this function during interrupt time.
5006 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005007 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005008 */
5009
5010/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5011int
5012mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5013{
5014 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5015 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5016 MPT_FRAME_HDR *mf = NULL;
5017 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305018 int ret = 0;
5019 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005020
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305021 mutex_lock(&ioc->mptbase_cmds.mutex);
5022
5023 /* init the internal cmd struct */
5024 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5025 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005026
5027 /* insure garbage is not sent to fw */
5028 switch(persist_opcode) {
5029
5030 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5031 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5032 break;
5033
5034 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305035 ret = -1;
5036 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005037 }
5038
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305039 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5040 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005041
5042 /* Get a MF for this command.
5043 */
5044 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305045 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5046 ret = -1;
5047 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005048 }
5049
5050 mpi_hdr = (MPIHeader_t *) mf;
5051 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5052 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5053 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5054 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5055 sasIoUnitCntrReq->Operation = persist_opcode;
5056
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005057 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305058 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5059 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5060 ret = -ETIME;
5061 printk(KERN_DEBUG "%s: failed\n", __func__);
5062 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5063 goto out;
5064 if (!timeleft) {
5065 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
5066 ioc->name, __func__);
5067 mpt_HardResetHandler(ioc, CAN_SLEEP);
5068 mpt_free_msg_frame(ioc, mf);
5069 }
5070 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005071 }
5072
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305073 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5074 ret = -1;
5075 goto out;
5076 }
5077
5078 sasIoUnitCntrReply =
5079 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5080 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5081 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5082 __func__, sasIoUnitCntrReply->IOCStatus,
5083 sasIoUnitCntrReply->IOCLogInfo);
5084 printk(KERN_DEBUG "%s: failed\n", __func__);
5085 ret = -1;
5086 } else
5087 printk(KERN_DEBUG "%s: success\n", __func__);
5088 out:
5089
5090 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5091 mutex_unlock(&ioc->mptbase_cmds.mutex);
5092 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005093}
5094
5095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005096
5097static void
5098mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5099 MpiEventDataRaid_t * pRaidEventData)
5100{
5101 int volume;
5102 int reason;
5103 int disk;
5104 int status;
5105 int flags;
5106 int state;
5107
5108 volume = pRaidEventData->VolumeID;
5109 reason = pRaidEventData->ReasonCode;
5110 disk = pRaidEventData->PhysDiskNum;
5111 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5112 flags = (status >> 0) & 0xff;
5113 state = (status >> 8) & 0xff;
5114
5115 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5116 return;
5117 }
5118
5119 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5120 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5121 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005122 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5123 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005124 } else {
5125 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5126 ioc->name, volume);
5127 }
5128
5129 switch(reason) {
5130 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5131 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5132 ioc->name);
5133 break;
5134
5135 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5136
5137 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5138 ioc->name);
5139 break;
5140
5141 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5142 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5143 ioc->name);
5144 break;
5145
5146 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5147 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5148 ioc->name,
5149 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5150 ? "optimal"
5151 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5152 ? "degraded"
5153 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5154 ? "failed"
5155 : "state unknown",
5156 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5157 ? ", enabled" : "",
5158 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5159 ? ", quiesced" : "",
5160 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5161 ? ", resync in progress" : "" );
5162 break;
5163
5164 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5165 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5166 ioc->name, disk);
5167 break;
5168
5169 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5170 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5171 ioc->name);
5172 break;
5173
5174 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5175 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5176 ioc->name);
5177 break;
5178
5179 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5180 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5181 ioc->name);
5182 break;
5183
5184 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5185 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5186 ioc->name,
5187 state == MPI_PHYSDISK0_STATUS_ONLINE
5188 ? "online"
5189 : state == MPI_PHYSDISK0_STATUS_MISSING
5190 ? "missing"
5191 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5192 ? "not compatible"
5193 : state == MPI_PHYSDISK0_STATUS_FAILED
5194 ? "failed"
5195 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5196 ? "initializing"
5197 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5198 ? "offline requested"
5199 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5200 ? "failed requested"
5201 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5202 ? "offline"
5203 : "state unknown",
5204 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5205 ? ", out of sync" : "",
5206 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5207 ? ", quiesced" : "" );
5208 break;
5209
5210 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5211 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5212 ioc->name, disk);
5213 break;
5214
5215 case MPI_EVENT_RAID_RC_SMART_DATA:
5216 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5217 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5218 break;
5219
5220 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5221 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5222 ioc->name, disk);
5223 break;
5224 }
5225}
5226
5227/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005228/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5230 * @ioc: Pointer to MPT_ADAPTER structure
5231 *
5232 * Returns: 0 for success
5233 * -ENOMEM if no memory available
5234 * -EPERM if not allowed due to ISR context
5235 * -EAGAIN if no msg frames currently available
5236 * -EFAULT for non-successful reply or no reply (timeout)
5237 */
5238static int
5239GetIoUnitPage2(MPT_ADAPTER *ioc)
5240{
5241 ConfigPageHeader_t hdr;
5242 CONFIGPARMS cfg;
5243 IOUnitPage2_t *ppage_alloc;
5244 dma_addr_t page_dma;
5245 int data_sz;
5246 int rc;
5247
5248 /* Get the page header */
5249 hdr.PageVersion = 0;
5250 hdr.PageLength = 0;
5251 hdr.PageNumber = 2;
5252 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005253 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 cfg.physAddr = -1;
5255 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5256 cfg.dir = 0;
5257 cfg.pageAddr = 0;
5258 cfg.timeout = 0;
5259
5260 if ((rc = mpt_config(ioc, &cfg)) != 0)
5261 return rc;
5262
5263 if (hdr.PageLength == 0)
5264 return 0;
5265
5266 /* Read the config page */
5267 data_sz = hdr.PageLength * 4;
5268 rc = -ENOMEM;
5269 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5270 if (ppage_alloc) {
5271 memset((u8 *)ppage_alloc, 0, data_sz);
5272 cfg.physAddr = page_dma;
5273 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5274
5275 /* If Good, save data */
5276 if ((rc = mpt_config(ioc, &cfg)) == 0)
5277 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5278
5279 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5280 }
5281
5282 return rc;
5283}
5284
5285/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005286/**
5287 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 * @ioc: Pointer to a Adapter Strucutre
5289 * @portnum: IOC port number
5290 *
5291 * Return: -EFAULT if read of config page header fails
5292 * or if no nvram
5293 * If read of SCSI Port Page 0 fails,
5294 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5295 * Adapter settings: async, narrow
5296 * Return 1
5297 * If read of SCSI Port Page 2 fails,
5298 * Adapter settings valid
5299 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5300 * Return 1
5301 * Else
5302 * Both valid
5303 * Return 0
5304 * CHECK - what type of locking mechanisms should be used????
5305 */
5306static int
5307mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5308{
5309 u8 *pbuf;
5310 dma_addr_t buf_dma;
5311 CONFIGPARMS cfg;
5312 ConfigPageHeader_t header;
5313 int ii;
5314 int data, rc = 0;
5315
5316 /* Allocate memory
5317 */
5318 if (!ioc->spi_data.nvram) {
5319 int sz;
5320 u8 *mem;
5321 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5322 mem = kmalloc(sz, GFP_ATOMIC);
5323 if (mem == NULL)
5324 return -EFAULT;
5325
5326 ioc->spi_data.nvram = (int *) mem;
5327
Prakash, Sathya436ace72007-07-24 15:42:08 +05305328 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 ioc->name, ioc->spi_data.nvram, sz));
5330 }
5331
5332 /* Invalidate NVRAM information
5333 */
5334 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5335 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5336 }
5337
5338 /* Read SPP0 header, allocate memory, then read page.
5339 */
5340 header.PageVersion = 0;
5341 header.PageLength = 0;
5342 header.PageNumber = 0;
5343 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005344 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 cfg.physAddr = -1;
5346 cfg.pageAddr = portnum;
5347 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5348 cfg.dir = 0;
5349 cfg.timeout = 0; /* use default */
5350 if (mpt_config(ioc, &cfg) != 0)
5351 return -EFAULT;
5352
5353 if (header.PageLength > 0) {
5354 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5355 if (pbuf) {
5356 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5357 cfg.physAddr = buf_dma;
5358 if (mpt_config(ioc, &cfg) != 0) {
5359 ioc->spi_data.maxBusWidth = MPT_NARROW;
5360 ioc->spi_data.maxSyncOffset = 0;
5361 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5362 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5363 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305364 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5365 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005366 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 } else {
5368 /* Save the Port Page 0 data
5369 */
5370 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5371 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5372 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5373
5374 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5375 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005376 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5377 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 ioc->name, pPP0->Capabilities));
5379 }
5380 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5381 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5382 if (data) {
5383 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5384 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5385 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305386 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5387 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005388 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 } else {
5390 ioc->spi_data.maxSyncOffset = 0;
5391 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5392 }
5393
5394 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5395
5396 /* Update the minSyncFactor based on bus type.
5397 */
5398 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5399 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5400
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005401 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305403 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5404 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005405 ioc->name, ioc->spi_data.minSyncFactor));
5406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 }
5408 }
5409 if (pbuf) {
5410 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5411 }
5412 }
5413 }
5414
5415 /* SCSI Port Page 2 - Read the header then the page.
5416 */
5417 header.PageVersion = 0;
5418 header.PageLength = 0;
5419 header.PageNumber = 2;
5420 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005421 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 cfg.physAddr = -1;
5423 cfg.pageAddr = portnum;
5424 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5425 cfg.dir = 0;
5426 if (mpt_config(ioc, &cfg) != 0)
5427 return -EFAULT;
5428
5429 if (header.PageLength > 0) {
5430 /* Allocate memory and read SCSI Port Page 2
5431 */
5432 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5433 if (pbuf) {
5434 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5435 cfg.physAddr = buf_dma;
5436 if (mpt_config(ioc, &cfg) != 0) {
5437 /* Nvram data is left with INVALID mark
5438 */
5439 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005440 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5441
5442 /* This is an ATTO adapter, read Page2 accordingly
5443 */
5444 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5445 ATTODeviceInfo_t *pdevice = NULL;
5446 u16 ATTOFlags;
5447
5448 /* Save the Port Page 2 data
5449 * (reformat into a 32bit quantity)
5450 */
5451 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5452 pdevice = &pPP2->DeviceSettings[ii];
5453 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5454 data = 0;
5455
5456 /* Translate ATTO device flags to LSI format
5457 */
5458 if (ATTOFlags & ATTOFLAG_DISC)
5459 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5460 if (ATTOFlags & ATTOFLAG_ID_ENB)
5461 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5462 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5463 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5464 if (ATTOFlags & ATTOFLAG_TAGGED)
5465 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5466 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5467 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5468
5469 data = (data << 16) | (pdevice->Period << 8) | 10;
5470 ioc->spi_data.nvram[ii] = data;
5471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 } else {
5473 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5474 MpiDeviceInfo_t *pdevice = NULL;
5475
Moore, Ericd8e925d2006-01-16 18:53:06 -07005476 /*
5477 * Save "Set to Avoid SCSI Bus Resets" flag
5478 */
5479 ioc->spi_data.bus_reset =
5480 (le32_to_cpu(pPP2->PortFlags) &
5481 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5482 0 : 1 ;
5483
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 /* Save the Port Page 2 data
5485 * (reformat into a 32bit quantity)
5486 */
5487 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5488 ioc->spi_data.PortFlags = data;
5489 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5490 pdevice = &pPP2->DeviceSettings[ii];
5491 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5492 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5493 ioc->spi_data.nvram[ii] = data;
5494 }
5495 }
5496
5497 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5498 }
5499 }
5500
5501 /* Update Adapter limits with those from NVRAM
5502 * Comment: Don't need to do this. Target performance
5503 * parameters will never exceed the adapters limits.
5504 */
5505
5506 return rc;
5507}
5508
5509/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005510/**
5511 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 * @ioc: Pointer to a Adapter Strucutre
5513 * @portnum: IOC port number
5514 *
5515 * Return: -EFAULT if read of config page header fails
5516 * or 0 if success.
5517 */
5518static int
5519mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5520{
5521 CONFIGPARMS cfg;
5522 ConfigPageHeader_t header;
5523
5524 /* Read the SCSI Device Page 1 header
5525 */
5526 header.PageVersion = 0;
5527 header.PageLength = 0;
5528 header.PageNumber = 1;
5529 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005530 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 cfg.physAddr = -1;
5532 cfg.pageAddr = portnum;
5533 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5534 cfg.dir = 0;
5535 cfg.timeout = 0;
5536 if (mpt_config(ioc, &cfg) != 0)
5537 return -EFAULT;
5538
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005539 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5540 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541
5542 header.PageVersion = 0;
5543 header.PageLength = 0;
5544 header.PageNumber = 0;
5545 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5546 if (mpt_config(ioc, &cfg) != 0)
5547 return -EFAULT;
5548
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005549 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5550 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551
Prakash, Sathya436ace72007-07-24 15:42:08 +05305552 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5554
Prakash, Sathya436ace72007-07-24 15:42:08 +05305555 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5557 return 0;
5558}
5559
Eric Mooreb506ade2007-01-29 09:45:37 -07005560/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005561 * mpt_inactive_raid_list_free - This clears this link list.
5562 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005563 **/
5564static void
5565mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5566{
5567 struct inactive_raid_component_info *component_info, *pNext;
5568
5569 if (list_empty(&ioc->raid_data.inactive_list))
5570 return;
5571
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005572 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005573 list_for_each_entry_safe(component_info, pNext,
5574 &ioc->raid_data.inactive_list, list) {
5575 list_del(&component_info->list);
5576 kfree(component_info);
5577 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005578 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005579}
5580
5581/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005582 * 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 -07005583 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005584 * @ioc : pointer to per adapter structure
5585 * @channel : volume channel
5586 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005587 **/
5588static void
5589mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5590{
5591 CONFIGPARMS cfg;
5592 ConfigPageHeader_t hdr;
5593 dma_addr_t dma_handle;
5594 pRaidVolumePage0_t buffer = NULL;
5595 int i;
5596 RaidPhysDiskPage0_t phys_disk;
5597 struct inactive_raid_component_info *component_info;
5598 int handle_inactive_volumes;
5599
5600 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5601 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5602 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5603 cfg.pageAddr = (channel << 8) + id;
5604 cfg.cfghdr.hdr = &hdr;
5605 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5606
5607 if (mpt_config(ioc, &cfg) != 0)
5608 goto out;
5609
5610 if (!hdr.PageLength)
5611 goto out;
5612
5613 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5614 &dma_handle);
5615
5616 if (!buffer)
5617 goto out;
5618
5619 cfg.physAddr = dma_handle;
5620 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5621
5622 if (mpt_config(ioc, &cfg) != 0)
5623 goto out;
5624
5625 if (!buffer->NumPhysDisks)
5626 goto out;
5627
5628 handle_inactive_volumes =
5629 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5630 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5631 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5632 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5633
5634 if (!handle_inactive_volumes)
5635 goto out;
5636
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005637 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005638 for (i = 0; i < buffer->NumPhysDisks; i++) {
5639 if(mpt_raid_phys_disk_pg0(ioc,
5640 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5641 continue;
5642
5643 if ((component_info = kmalloc(sizeof (*component_info),
5644 GFP_KERNEL)) == NULL)
5645 continue;
5646
5647 component_info->volumeID = id;
5648 component_info->volumeBus = channel;
5649 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5650 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5651 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5652 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5653
5654 list_add_tail(&component_info->list,
5655 &ioc->raid_data.inactive_list);
5656 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005657 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005658
5659 out:
5660 if (buffer)
5661 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5662 dma_handle);
5663}
5664
5665/**
5666 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5667 * @ioc: Pointer to a Adapter Structure
5668 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5669 * @phys_disk: requested payload data returned
5670 *
5671 * Return:
5672 * 0 on success
5673 * -EFAULT if read of config page header fails or data pointer not NULL
5674 * -ENOMEM if pci_alloc failed
5675 **/
5676int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305677mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5678 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005679{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305680 CONFIGPARMS cfg;
5681 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005682 dma_addr_t dma_handle;
5683 pRaidPhysDiskPage0_t buffer = NULL;
5684 int rc;
5685
5686 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5687 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305688 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005689
Kashyap, Desai2f187862009-05-29 16:52:37 +05305690 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005691 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5692 cfg.cfghdr.hdr = &hdr;
5693 cfg.physAddr = -1;
5694 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5695
5696 if (mpt_config(ioc, &cfg) != 0) {
5697 rc = -EFAULT;
5698 goto out;
5699 }
5700
5701 if (!hdr.PageLength) {
5702 rc = -EFAULT;
5703 goto out;
5704 }
5705
5706 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5707 &dma_handle);
5708
5709 if (!buffer) {
5710 rc = -ENOMEM;
5711 goto out;
5712 }
5713
5714 cfg.physAddr = dma_handle;
5715 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5716 cfg.pageAddr = phys_disk_num;
5717
5718 if (mpt_config(ioc, &cfg) != 0) {
5719 rc = -EFAULT;
5720 goto out;
5721 }
5722
5723 rc = 0;
5724 memcpy(phys_disk, buffer, sizeof(*buffer));
5725 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5726
5727 out:
5728
5729 if (buffer)
5730 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5731 dma_handle);
5732
5733 return rc;
5734}
5735
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305737 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5738 * @ioc: Pointer to a Adapter Structure
5739 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5740 *
5741 * Return:
5742 * returns number paths
5743 **/
5744int
5745mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5746{
5747 CONFIGPARMS cfg;
5748 ConfigPageHeader_t hdr;
5749 dma_addr_t dma_handle;
5750 pRaidPhysDiskPage1_t buffer = NULL;
5751 int rc;
5752
5753 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5754 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5755
5756 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5757 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5758 hdr.PageNumber = 1;
5759 cfg.cfghdr.hdr = &hdr;
5760 cfg.physAddr = -1;
5761 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5762
5763 if (mpt_config(ioc, &cfg) != 0) {
5764 rc = 0;
5765 goto out;
5766 }
5767
5768 if (!hdr.PageLength) {
5769 rc = 0;
5770 goto out;
5771 }
5772
5773 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5774 &dma_handle);
5775
5776 if (!buffer) {
5777 rc = 0;
5778 goto out;
5779 }
5780
5781 cfg.physAddr = dma_handle;
5782 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5783 cfg.pageAddr = phys_disk_num;
5784
5785 if (mpt_config(ioc, &cfg) != 0) {
5786 rc = 0;
5787 goto out;
5788 }
5789
5790 rc = buffer->NumPhysDiskPaths;
5791 out:
5792
5793 if (buffer)
5794 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5795 dma_handle);
5796
5797 return rc;
5798}
5799EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5800
5801/**
5802 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5803 * @ioc: Pointer to a Adapter Structure
5804 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5805 * @phys_disk: requested payload data returned
5806 *
5807 * Return:
5808 * 0 on success
5809 * -EFAULT if read of config page header fails or data pointer not NULL
5810 * -ENOMEM if pci_alloc failed
5811 **/
5812int
5813mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5814 RaidPhysDiskPage1_t *phys_disk)
5815{
5816 CONFIGPARMS cfg;
5817 ConfigPageHeader_t hdr;
5818 dma_addr_t dma_handle;
5819 pRaidPhysDiskPage1_t buffer = NULL;
5820 int rc;
5821 int i;
5822 __le64 sas_address;
5823
5824 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5825 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5826 rc = 0;
5827
5828 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5829 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5830 hdr.PageNumber = 1;
5831 cfg.cfghdr.hdr = &hdr;
5832 cfg.physAddr = -1;
5833 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5834
5835 if (mpt_config(ioc, &cfg) != 0) {
5836 rc = -EFAULT;
5837 goto out;
5838 }
5839
5840 if (!hdr.PageLength) {
5841 rc = -EFAULT;
5842 goto out;
5843 }
5844
5845 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5846 &dma_handle);
5847
5848 if (!buffer) {
5849 rc = -ENOMEM;
5850 goto out;
5851 }
5852
5853 cfg.physAddr = dma_handle;
5854 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5855 cfg.pageAddr = phys_disk_num;
5856
5857 if (mpt_config(ioc, &cfg) != 0) {
5858 rc = -EFAULT;
5859 goto out;
5860 }
5861
5862 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5863 phys_disk->PhysDiskNum = phys_disk_num;
5864 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5865 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5866 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5867 phys_disk->Path[i].OwnerIdentifier =
5868 buffer->Path[i].OwnerIdentifier;
5869 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5870 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5871 sas_address = le64_to_cpu(sas_address);
5872 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5873 memcpy(&sas_address,
5874 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5875 sas_address = le64_to_cpu(sas_address);
5876 memcpy(&phys_disk->Path[i].OwnerWWID,
5877 &sas_address, sizeof(__le64));
5878 }
5879
5880 out:
5881
5882 if (buffer)
5883 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5884 dma_handle);
5885
5886 return rc;
5887}
5888EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5889
5890
5891/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5893 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 *
5895 * Return:
5896 * 0 on success
5897 * -EFAULT if read of config page header fails or data pointer not NULL
5898 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005899 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900int
5901mpt_findImVolumes(MPT_ADAPTER *ioc)
5902{
5903 IOCPage2_t *pIoc2;
5904 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 dma_addr_t ioc2_dma;
5906 CONFIGPARMS cfg;
5907 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 int rc = 0;
5909 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005910 int i;
5911
5912 if (!ioc->ir_firmware)
5913 return 0;
5914
5915 /* Free the old page
5916 */
5917 kfree(ioc->raid_data.pIocPg2);
5918 ioc->raid_data.pIocPg2 = NULL;
5919 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920
5921 /* Read IOCP2 header then the page.
5922 */
5923 header.PageVersion = 0;
5924 header.PageLength = 0;
5925 header.PageNumber = 2;
5926 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005927 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928 cfg.physAddr = -1;
5929 cfg.pageAddr = 0;
5930 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5931 cfg.dir = 0;
5932 cfg.timeout = 0;
5933 if (mpt_config(ioc, &cfg) != 0)
5934 return -EFAULT;
5935
5936 if (header.PageLength == 0)
5937 return -EFAULT;
5938
5939 iocpage2sz = header.PageLength * 4;
5940 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5941 if (!pIoc2)
5942 return -ENOMEM;
5943
5944 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5945 cfg.physAddr = ioc2_dma;
5946 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005947 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948
Eric Mooreb506ade2007-01-29 09:45:37 -07005949 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5950 if (!mem)
5951 goto out;
5952
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005954 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955
Eric Mooreb506ade2007-01-29 09:45:37 -07005956 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957
Eric Mooreb506ade2007-01-29 09:45:37 -07005958 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5959 mpt_inactive_raid_volumes(ioc,
5960 pIoc2->RaidVolume[i].VolumeBus,
5961 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962
Eric Mooreb506ade2007-01-29 09:45:37 -07005963 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5965
5966 return rc;
5967}
5968
Moore, Ericc972c702006-03-14 09:14:06 -07005969static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5971{
5972 IOCPage3_t *pIoc3;
5973 u8 *mem;
5974 CONFIGPARMS cfg;
5975 ConfigPageHeader_t header;
5976 dma_addr_t ioc3_dma;
5977 int iocpage3sz = 0;
5978
5979 /* Free the old page
5980 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005981 kfree(ioc->raid_data.pIocPg3);
5982 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983
5984 /* There is at least one physical disk.
5985 * Read and save IOC Page 3
5986 */
5987 header.PageVersion = 0;
5988 header.PageLength = 0;
5989 header.PageNumber = 3;
5990 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005991 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 cfg.physAddr = -1;
5993 cfg.pageAddr = 0;
5994 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5995 cfg.dir = 0;
5996 cfg.timeout = 0;
5997 if (mpt_config(ioc, &cfg) != 0)
5998 return 0;
5999
6000 if (header.PageLength == 0)
6001 return 0;
6002
6003 /* Read Header good, alloc memory
6004 */
6005 iocpage3sz = header.PageLength * 4;
6006 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6007 if (!pIoc3)
6008 return 0;
6009
6010 /* Read the Page and save the data
6011 * into malloc'd memory.
6012 */
6013 cfg.physAddr = ioc3_dma;
6014 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6015 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006016 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017 if (mem) {
6018 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006019 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020 }
6021 }
6022
6023 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6024
6025 return 0;
6026}
6027
6028static void
6029mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6030{
6031 IOCPage4_t *pIoc4;
6032 CONFIGPARMS cfg;
6033 ConfigPageHeader_t header;
6034 dma_addr_t ioc4_dma;
6035 int iocpage4sz;
6036
6037 /* Read and save IOC Page 4
6038 */
6039 header.PageVersion = 0;
6040 header.PageLength = 0;
6041 header.PageNumber = 4;
6042 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006043 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 cfg.physAddr = -1;
6045 cfg.pageAddr = 0;
6046 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6047 cfg.dir = 0;
6048 cfg.timeout = 0;
6049 if (mpt_config(ioc, &cfg) != 0)
6050 return;
6051
6052 if (header.PageLength == 0)
6053 return;
6054
6055 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6056 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6057 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6058 if (!pIoc4)
6059 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006060 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061 } else {
6062 ioc4_dma = ioc->spi_data.IocPg4_dma;
6063 iocpage4sz = ioc->spi_data.IocPg4Sz;
6064 }
6065
6066 /* Read the Page into dma memory.
6067 */
6068 cfg.physAddr = ioc4_dma;
6069 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6070 if (mpt_config(ioc, &cfg) == 0) {
6071 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6072 ioc->spi_data.IocPg4_dma = ioc4_dma;
6073 ioc->spi_data.IocPg4Sz = iocpage4sz;
6074 } else {
6075 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6076 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006077 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078 }
6079}
6080
6081static void
6082mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6083{
6084 IOCPage1_t *pIoc1;
6085 CONFIGPARMS cfg;
6086 ConfigPageHeader_t header;
6087 dma_addr_t ioc1_dma;
6088 int iocpage1sz = 0;
6089 u32 tmp;
6090
6091 /* Check the Coalescing Timeout in IOC Page 1
6092 */
6093 header.PageVersion = 0;
6094 header.PageLength = 0;
6095 header.PageNumber = 1;
6096 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006097 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098 cfg.physAddr = -1;
6099 cfg.pageAddr = 0;
6100 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6101 cfg.dir = 0;
6102 cfg.timeout = 0;
6103 if (mpt_config(ioc, &cfg) != 0)
6104 return;
6105
6106 if (header.PageLength == 0)
6107 return;
6108
6109 /* Read Header good, alloc memory
6110 */
6111 iocpage1sz = header.PageLength * 4;
6112 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6113 if (!pIoc1)
6114 return;
6115
6116 /* Read the Page and check coalescing timeout
6117 */
6118 cfg.physAddr = ioc1_dma;
6119 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6120 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306121
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6123 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6124 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6125
Prakash, Sathya436ace72007-07-24 15:42:08 +05306126 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 ioc->name, tmp));
6128
6129 if (tmp > MPT_COALESCING_TIMEOUT) {
6130 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6131
6132 /* Write NVRAM and current
6133 */
6134 cfg.dir = 1;
6135 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6136 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306137 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006138 ioc->name, MPT_COALESCING_TIMEOUT));
6139
6140 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6141 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306142 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6143 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144 ioc->name, MPT_COALESCING_TIMEOUT));
6145 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306146 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6147 "Reset NVRAM Coalescing Timeout Failed\n",
6148 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149 }
6150
6151 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306152 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6153 "Reset of Current Coalescing Timeout Failed!\n",
6154 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155 }
6156 }
6157
6158 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306159 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160 }
6161 }
6162
6163 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6164
6165 return;
6166}
6167
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306168static void
6169mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6170{
6171 CONFIGPARMS cfg;
6172 ConfigPageHeader_t hdr;
6173 dma_addr_t buf_dma;
6174 ManufacturingPage0_t *pbuf = NULL;
6175
6176 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6177 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6178
6179 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6180 cfg.cfghdr.hdr = &hdr;
6181 cfg.physAddr = -1;
6182 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6183 cfg.timeout = 10;
6184
6185 if (mpt_config(ioc, &cfg) != 0)
6186 goto out;
6187
6188 if (!cfg.cfghdr.hdr->PageLength)
6189 goto out;
6190
6191 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6192 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6193 if (!pbuf)
6194 goto out;
6195
6196 cfg.physAddr = buf_dma;
6197
6198 if (mpt_config(ioc, &cfg) != 0)
6199 goto out;
6200
6201 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6202 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6203 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6204
6205 out:
6206
6207 if (pbuf)
6208 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6209}
6210
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006212/**
6213 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 * @ioc: Pointer to MPT_ADAPTER structure
6215 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306216 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 */
6218static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306219SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306221 EventNotification_t evn;
6222 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Kashyap, Desaifd761752009-05-29 16:39:06 +05306224 memset(&evn, 0, sizeof(EventNotification_t));
6225 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226
Kashyap, Desaifd761752009-05-29 16:39:06 +05306227 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6228 evn.Switch = EvSwitch;
6229 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230
Kashyap, Desaifd761752009-05-29 16:39:06 +05306231 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6232 "Sending EventNotification (%d) request %p\n",
6233 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234
Kashyap, Desaifd761752009-05-29 16:39:06 +05306235 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6236 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6237 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238}
6239
6240/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6241/**
6242 * SendEventAck - Send EventAck request to MPT adapter.
6243 * @ioc: Pointer to MPT_ADAPTER structure
6244 * @evnp: Pointer to original EventNotification request
6245 */
6246static int
6247SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6248{
6249 EventAck_t *pAck;
6250
6251 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306252 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306253 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 return -1;
6255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256
Prakash, Sathya436ace72007-07-24 15:42:08 +05306257 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258
6259 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6260 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006261 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006263 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 pAck->Event = evnp->Event;
6265 pAck->EventContext = evnp->EventContext;
6266
6267 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6268
6269 return 0;
6270}
6271
6272/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6273/**
6274 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006275 * @ioc: Pointer to an adapter structure
6276 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277 * action, page address, direction, physical address
6278 * and pointer to a configuration page header
6279 * Page header is updated.
6280 *
6281 * Returns 0 for success
6282 * -EPERM if not allowed due to ISR context
6283 * -EAGAIN if no msg frames currently available
6284 * -EFAULT for non-successful reply or no reply (timeout)
6285 */
6286int
6287mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6288{
6289 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306290 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006291 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306293 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006294 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306295 long timeout;
6296 int ret;
6297 u8 page_type = 0, extend_page;
6298 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306299 unsigned long flags;
6300 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306301 u8 issue_hard_reset = 0;
6302 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006304 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305 * to be in ISR context, because that is fatal!
6306 */
6307 in_isr = in_interrupt();
6308 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306309 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310 ioc->name));
6311 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306312 }
6313
6314 /* don't send a config page during diag reset */
6315 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6316 if (ioc->ioc_reset_in_progress) {
6317 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6318 "%s: busy with host reset\n", ioc->name, __func__));
6319 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6320 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306322 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306324 /* don't send if no chance of success */
6325 if (!ioc->active ||
6326 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6327 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6328 "%s: ioc not operational, %d, %xh\n",
6329 ioc->name, __func__, ioc->active,
6330 mpt_GetIocState(ioc, 0)));
6331 return -EFAULT;
6332 }
6333
6334 retry_config:
6335 mutex_lock(&ioc->mptbase_cmds.mutex);
6336 /* init the internal cmd struct */
6337 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6338 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6339
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340 /* Get and Populate a free Frame
6341 */
6342 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306343 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6344 "mpt_config: no msg frames!\n", ioc->name));
6345 ret = -EAGAIN;
6346 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306348
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 pReq = (Config_t *)mf;
6350 pReq->Action = pCfg->action;
6351 pReq->Reserved = 0;
6352 pReq->ChainOffset = 0;
6353 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006354
6355 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006356 pReq->ExtPageLength = 0;
6357 pReq->ExtPageType = 0;
6358 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006359
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360 for (ii=0; ii < 8; ii++)
6361 pReq->Reserved2[ii] = 0;
6362
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006363 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6364 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6365 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6366 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6367
6368 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6369 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6370 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6371 pReq->ExtPageType = pExtHdr->ExtPageType;
6372 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6373
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306374 /* Page Length must be treated as a reserved field for the
6375 * extended header.
6376 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006377 pReq->Header.PageLength = 0;
6378 }
6379
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6381
6382 /* Add a SGE to the config request.
6383 */
6384 if (pCfg->dir)
6385 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6386 else
6387 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6388
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306389 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6390 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006391 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306392 page_type = pReq->ExtPageType;
6393 extend_page = 1;
6394 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006395 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306396 page_type = pReq->Header.PageType;
6397 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306400 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6401 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6402 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6403
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306404 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306405 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306407 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6408 timeout);
6409 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6410 ret = -ETIME;
6411 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6412 "Failed Sending Config request type 0x%x, page 0x%x,"
6413 " action %d, status %xh, time left %ld\n\n",
6414 ioc->name, page_type, pReq->Header.PageNumber,
6415 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6416 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6417 goto out;
6418 if (!timeleft)
6419 issue_hard_reset = 1;
6420 goto out;
6421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306423 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6424 ret = -1;
6425 goto out;
6426 }
6427 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6428 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6429 if (ret == MPI_IOCSTATUS_SUCCESS) {
6430 if (extend_page) {
6431 pCfg->cfghdr.ehdr->ExtPageLength =
6432 le16_to_cpu(pReply->ExtPageLength);
6433 pCfg->cfghdr.ehdr->ExtPageType =
6434 pReply->ExtPageType;
6435 }
6436 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6437 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6438 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6439 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306443 if (retry_count)
6444 printk(MYIOC_s_INFO_FMT "Retry completed "
6445 "ret=0x%x timeleft=%ld\n",
6446 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306448 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6449 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306451out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306453 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6454 mutex_unlock(&ioc->mptbase_cmds.mutex);
6455 if (issue_hard_reset) {
6456 issue_hard_reset = 0;
6457 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6458 ioc->name, __func__);
6459 mpt_HardResetHandler(ioc, CAN_SLEEP);
6460 mpt_free_msg_frame(ioc, mf);
6461 /* attempt one retry for a timed out command */
6462 if (!retry_count) {
6463 printk(MYIOC_s_INFO_FMT
6464 "Attempting Retry Config request"
6465 " type 0x%x, page 0x%x,"
6466 " action %d\n", ioc->name, page_type,
6467 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6468 retry_count++;
6469 goto retry_config;
6470 }
6471 }
6472 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474}
6475
6476/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006477/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006478 * mpt_ioc_reset - Base cleanup for hard reset
6479 * @ioc: Pointer to the adapter structure
6480 * @reset_phase: Indicates pre- or post-reset functionality
6481 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006482 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483 */
6484static int
6485mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6486{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306487 switch (reset_phase) {
6488 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306489 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306490 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6491 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6492 break;
6493 case MPT_IOC_PRE_RESET:
6494 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6495 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6496 break;
6497 case MPT_IOC_POST_RESET:
6498 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6499 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6500/* wake up mptbase_cmds */
6501 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6502 ioc->mptbase_cmds.status |=
6503 MPT_MGMT_STATUS_DID_IOCRESET;
6504 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006505 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306506/* wake up taskmgmt_cmds */
6507 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6508 ioc->taskmgmt_cmds.status |=
6509 MPT_MGMT_STATUS_DID_IOCRESET;
6510 complete(&ioc->taskmgmt_cmds.done);
6511 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306512 break;
6513 default:
6514 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006515 }
6516
6517 return 1; /* currently means nothing really */
6518}
6519
6520
6521#ifdef CONFIG_PROC_FS /* { */
6522/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6523/*
6524 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6525 */
6526/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006527/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006528 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6529 *
6530 * Returns 0 for success, non-zero for failure.
6531 */
6532static int
6533procmpt_create(void)
6534{
6535 struct proc_dir_entry *ent;
6536
6537 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6538 if (mpt_proc_root_dir == NULL)
6539 return -ENOTDIR;
6540
6541 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6542 if (ent)
6543 ent->read_proc = procmpt_summary_read;
6544
6545 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6546 if (ent)
6547 ent->read_proc = procmpt_version_read;
6548
6549 return 0;
6550}
6551
6552/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006553/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6555 *
6556 * Returns 0 for success, non-zero for failure.
6557 */
6558static void
6559procmpt_destroy(void)
6560{
6561 remove_proc_entry("version", mpt_proc_root_dir);
6562 remove_proc_entry("summary", mpt_proc_root_dir);
6563 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6564}
6565
6566/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006567/**
6568 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569 * @buf: Pointer to area to write information
6570 * @start: Pointer to start pointer
6571 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006572 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006573 * @eof: Pointer to EOF integer
6574 * @data: Pointer
6575 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006576 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577 * Returns number of characters written to process performing the read.
6578 */
6579static int
6580procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6581{
6582 MPT_ADAPTER *ioc;
6583 char *out = buf;
6584 int len;
6585
6586 if (data) {
6587 int more = 0;
6588
6589 ioc = data;
6590 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6591
6592 out += more;
6593 } else {
6594 list_for_each_entry(ioc, &ioc_list, list) {
6595 int more = 0;
6596
6597 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6598
6599 out += more;
6600 if ((out-buf) >= request)
6601 break;
6602 }
6603 }
6604
6605 len = out - buf;
6606
6607 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6608}
6609
6610/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006611/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006612 * procmpt_version_read - Handle read request from /proc/mpt/version.
6613 * @buf: Pointer to area to write information
6614 * @start: Pointer to start pointer
6615 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006616 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006617 * @eof: Pointer to EOF integer
6618 * @data: Pointer
6619 *
6620 * Returns number of characters written to process performing the read.
6621 */
6622static int
6623procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6624{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306625 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006626 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006627 char *drvname;
6628 int len;
6629
6630 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6631 len += sprintf(buf+len, " Fusion MPT base driver\n");
6632
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006633 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006634 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006635 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306636 if (MptCallbacks[cb_idx]) {
6637 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006638 case MPTSPI_DRIVER:
6639 if (!scsi++) drvname = "SPI host";
6640 break;
6641 case MPTFC_DRIVER:
6642 if (!fc++) drvname = "FC host";
6643 break;
6644 case MPTSAS_DRIVER:
6645 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006646 break;
6647 case MPTLAN_DRIVER:
6648 if (!lan++) drvname = "LAN";
6649 break;
6650 case MPTSTM_DRIVER:
6651 if (!targ++) drvname = "SCSI target";
6652 break;
6653 case MPTCTL_DRIVER:
6654 if (!ctl++) drvname = "ioctl";
6655 break;
6656 }
6657
6658 if (drvname)
6659 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6660 }
6661 }
6662
6663 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6664}
6665
6666/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006667/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6669 * @buf: Pointer to area to write information
6670 * @start: Pointer to start pointer
6671 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006672 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006673 * @eof: Pointer to EOF integer
6674 * @data: Pointer
6675 *
6676 * Returns number of characters written to process performing the read.
6677 */
6678static int
6679procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6680{
6681 MPT_ADAPTER *ioc = data;
6682 int len;
6683 char expVer[32];
6684 int sz;
6685 int p;
6686
6687 mpt_get_fw_exp_ver(expVer, ioc);
6688
6689 len = sprintf(buf, "%s:", ioc->name);
6690 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6691 len += sprintf(buf+len, " (f/w download boot flag set)");
6692// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6693// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6694
6695 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6696 ioc->facts.ProductID,
6697 ioc->prod_name);
6698 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6699 if (ioc->facts.FWImageSize)
6700 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6701 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6702 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6703 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6704
6705 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6706 ioc->facts.CurrentHostMfaHighAddr);
6707 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6708 ioc->facts.CurrentSenseBufferHighAddr);
6709
6710 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6711 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6712
6713 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6714 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6715 /*
6716 * Rounding UP to nearest 4-kB boundary here...
6717 */
6718 sz = (ioc->req_sz * ioc->req_depth) + 128;
6719 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6720 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6721 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6722 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6723 4*ioc->facts.RequestFrameSize,
6724 ioc->facts.GlobalCredits);
6725
6726 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6727 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6728 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6729 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6730 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6731 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6732 ioc->facts.CurReplyFrameSize,
6733 ioc->facts.ReplyQueueDepth);
6734
6735 len += sprintf(buf+len, " MaxDevices = %d\n",
6736 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6737 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6738
6739 /* per-port info */
6740 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6741 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6742 p+1,
6743 ioc->facts.NumberOfPorts);
6744 if (ioc->bus_type == FC) {
6745 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6746 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6747 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6748 a[5], a[4], a[3], a[2], a[1], a[0]);
6749 }
6750 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6751 ioc->fc_port_page0[p].WWNN.High,
6752 ioc->fc_port_page0[p].WWNN.Low,
6753 ioc->fc_port_page0[p].WWPN.High,
6754 ioc->fc_port_page0[p].WWPN.Low);
6755 }
6756 }
6757
6758 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6759}
6760
6761#endif /* CONFIG_PROC_FS } */
6762
6763/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6764static void
6765mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6766{
6767 buf[0] ='\0';
6768 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6769 sprintf(buf, " (Exp %02d%02d)",
6770 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6771 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6772
6773 /* insider hack! */
6774 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6775 strcat(buf, " [MDBG]");
6776 }
6777}
6778
6779/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6780/**
6781 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6782 * @ioc: Pointer to MPT_ADAPTER structure
6783 * @buffer: Pointer to buffer where IOC summary info should be written
6784 * @size: Pointer to number of bytes we wrote (set by this routine)
6785 * @len: Offset at which to start writing in buffer
6786 * @showlan: Display LAN stuff?
6787 *
6788 * This routine writes (english readable) ASCII text, which represents
6789 * a summary of IOC information, to a buffer.
6790 */
6791void
6792mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6793{
6794 char expVer[32];
6795 int y;
6796
6797 mpt_get_fw_exp_ver(expVer, ioc);
6798
6799 /*
6800 * Shorter summary of attached ioc's...
6801 */
6802 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6803 ioc->name,
6804 ioc->prod_name,
6805 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6806 ioc->facts.FWVersion.Word,
6807 expVer,
6808 ioc->facts.NumberOfPorts,
6809 ioc->req_depth);
6810
6811 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6812 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6813 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6814 a[5], a[4], a[3], a[2], a[1], a[0]);
6815 }
6816
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006818
6819 if (!ioc->active)
6820 y += sprintf(buffer+len+y, " (disabled)");
6821
6822 y += sprintf(buffer+len+y, "\n");
6823
6824 *size = y;
6825}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306826/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006827 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306828 * @ioc: Pointer to MPT_ADAPTER structure
6829 *
6830 * Returns 0 for SUCCESS or -1 if FAILED.
6831 *
6832 * If -1 is return, then it was not possible to set the flags
6833 **/
6834int
6835mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6836{
6837 unsigned long flags;
6838 int retval;
6839
6840 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6841 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6842 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6843 retval = -1;
6844 goto out;
6845 }
6846 retval = 0;
6847 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306848 ioc->taskmgmt_quiesce_io = 1;
6849 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306850 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306851 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6852 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306853 out:
6854 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6855 return retval;
6856}
6857EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6858
6859/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006860 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306861 * @ioc: Pointer to MPT_ADAPTER structure
6862 *
6863 **/
6864void
6865mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6866{
6867 unsigned long flags;
6868
6869 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6870 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306871 ioc->taskmgmt_quiesce_io = 0;
6872 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306873 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306874 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6875 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306876 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6877}
6878EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006879
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306880
6881/**
6882 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6883 * the kernel
6884 * @ioc: Pointer to MPT_ADAPTER structure
6885 *
6886 **/
6887void
6888mpt_halt_firmware(MPT_ADAPTER *ioc)
6889{
6890 u32 ioc_raw_state;
6891
6892 ioc_raw_state = mpt_GetIocState(ioc, 0);
6893
6894 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6895 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6896 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6897 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6898 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6899 } else {
6900 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6901 panic("%s: Firmware is halted due to command timeout\n",
6902 ioc->name);
6903 }
6904}
6905EXPORT_SYMBOL(mpt_halt_firmware);
6906
Linus Torvalds1da177e2005-04-16 15:20:36 -07006907/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6908/*
6909 * Reset Handling
6910 */
6911/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6912/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006913 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006914 * @ioc: Pointer to MPT_ADAPTER structure
6915 * @sleepFlag: Indicates if sleep or schedule must be called.
6916 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006917 * Issues SCSI Task Management call based on input arg values.
6918 * If TaskMgmt fails, returns associated SCSI request.
6919 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006920 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6921 * or a non-interrupt thread. In the former, must not call schedule().
6922 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006923 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006924 * FW reload/initialization failed.
6925 *
6926 * Returns 0 for SUCCESS or -1 if FAILED.
6927 */
6928int
6929mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6930{
Kashyap, Desaid1306912009-08-05 12:53:51 +05306931 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306932 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006933 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306934 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935
Prakash, Sathya436ace72007-07-24 15:42:08 +05306936 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006937#ifdef MFCNT
6938 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6939 printk("MF count 0x%x !\n", ioc->mfcnt);
6940#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306941 if (mpt_fwfault_debug)
6942 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943
6944 /* Reset the adapter. Prevent more than 1 call to
6945 * mpt_do_ioc_recovery at any instant in time.
6946 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306947 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6948 if (ioc->ioc_reset_in_progress) {
6949 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006950 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006951 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306952 ioc->ioc_reset_in_progress = 1;
6953 if (ioc->alt_ioc)
6954 ioc->alt_ioc->ioc_reset_in_progress = 1;
6955 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006956
Linus Torvalds1da177e2005-04-16 15:20:36 -07006957
6958 /* The SCSI driver needs to adjust timeouts on all current
6959 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006960 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006961 * For all other protocol drivers, this is a no-op.
6962 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05306963 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6964 if (MptResetHandlers[cb_idx]) {
6965 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6966 if (ioc->alt_ioc)
6967 mpt_signal_reset(cb_idx, ioc->alt_ioc,
6968 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006969 }
6970 }
6971
Kashyap, Desai2f187862009-05-29 16:52:37 +05306972 time_count = jiffies;
6973 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
6974 if (rc != 0) {
6975 printk(KERN_WARNING MYNAM
6976 ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
6977 } else {
6978 if (ioc->hard_resets < -1)
6979 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006981
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306982 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6983 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306984 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306985 ioc->taskmgmt_in_progress = 0;
6986 if (ioc->alt_ioc) {
6987 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306988 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306989 ioc->alt_ioc->taskmgmt_in_progress = 0;
6990 }
6991 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992
Kashyap, Desaid1306912009-08-05 12:53:51 +05306993 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6994 if (MptResetHandlers[cb_idx]) {
6995 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
6996 if (ioc->alt_ioc)
6997 mpt_signal_reset(cb_idx,
6998 ioc->alt_ioc, MPT_IOC_POST_RESET);
6999 }
7000 }
7001
Kashyap, Desai2f187862009-05-29 16:52:37 +05307002 dtmprintk(ioc,
7003 printk(MYIOC_s_DEBUG_FMT
7004 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7005 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7006 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007
7008 return rc;
7009}
7010
Kashyap, Desai2f187862009-05-29 16:52:37 +05307011#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007012static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307013mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007014{
Eric Moore509e5e52006-04-26 13:22:37 -06007015 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307016 u32 evData0;
7017 int ii;
7018 u8 event;
7019 char *evStr = ioc->evStr;
7020
7021 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7022 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007023
7024 switch(event) {
7025 case MPI_EVENT_NONE:
7026 ds = "None";
7027 break;
7028 case MPI_EVENT_LOG_DATA:
7029 ds = "Log Data";
7030 break;
7031 case MPI_EVENT_STATE_CHANGE:
7032 ds = "State Change";
7033 break;
7034 case MPI_EVENT_UNIT_ATTENTION:
7035 ds = "Unit Attention";
7036 break;
7037 case MPI_EVENT_IOC_BUS_RESET:
7038 ds = "IOC Bus Reset";
7039 break;
7040 case MPI_EVENT_EXT_BUS_RESET:
7041 ds = "External Bus Reset";
7042 break;
7043 case MPI_EVENT_RESCAN:
7044 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007045 break;
7046 case MPI_EVENT_LINK_STATUS_CHANGE:
7047 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7048 ds = "Link Status(FAILURE) Change";
7049 else
7050 ds = "Link Status(ACTIVE) Change";
7051 break;
7052 case MPI_EVENT_LOOP_STATE_CHANGE:
7053 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7054 ds = "Loop State(LIP) Change";
7055 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307056 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007057 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307058 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007059 break;
7060 case MPI_EVENT_LOGOUT:
7061 ds = "Logout";
7062 break;
7063 case MPI_EVENT_EVENT_CHANGE:
7064 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007065 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007066 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007067 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007068 break;
7069 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007070 {
7071 u8 ReasonCode = (u8)(evData0 >> 16);
7072 switch (ReasonCode) {
7073 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7074 ds = "Integrated Raid: Volume Created";
7075 break;
7076 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7077 ds = "Integrated Raid: Volume Deleted";
7078 break;
7079 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7080 ds = "Integrated Raid: Volume Settings Changed";
7081 break;
7082 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7083 ds = "Integrated Raid: Volume Status Changed";
7084 break;
7085 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7086 ds = "Integrated Raid: Volume Physdisk Changed";
7087 break;
7088 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7089 ds = "Integrated Raid: Physdisk Created";
7090 break;
7091 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7092 ds = "Integrated Raid: Physdisk Deleted";
7093 break;
7094 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7095 ds = "Integrated Raid: Physdisk Settings Changed";
7096 break;
7097 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7098 ds = "Integrated Raid: Physdisk Status Changed";
7099 break;
7100 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7101 ds = "Integrated Raid: Domain Validation Needed";
7102 break;
7103 case MPI_EVENT_RAID_RC_SMART_DATA :
7104 ds = "Integrated Raid; Smart Data";
7105 break;
7106 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7107 ds = "Integrated Raid: Replace Action Started";
7108 break;
7109 default:
7110 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007111 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007112 }
7113 break;
7114 }
7115 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7116 ds = "SCSI Device Status Change";
7117 break;
7118 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7119 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007120 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007121 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007122 u8 ReasonCode = (u8)(evData0 >> 16);
7123 switch (ReasonCode) {
7124 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007125 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007126 "SAS Device Status Change: Added: "
7127 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007128 break;
7129 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007130 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007131 "SAS Device Status Change: Deleted: "
7132 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007133 break;
7134 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007135 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007136 "SAS Device Status Change: SMART Data: "
7137 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007138 break;
7139 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007140 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007141 "SAS Device Status Change: No Persistancy: "
7142 "id=%d channel=%d", id, channel);
7143 break;
7144 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7145 snprintf(evStr, EVENT_DESCR_STR_SZ,
7146 "SAS Device Status Change: Unsupported Device "
7147 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007148 break;
7149 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7150 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007151 "SAS Device Status Change: Internal Device "
7152 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007153 break;
7154 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7155 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007156 "SAS Device Status Change: Internal Task "
7157 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007158 break;
7159 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7160 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007161 "SAS Device Status Change: Internal Abort "
7162 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007163 break;
7164 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7165 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007166 "SAS Device Status Change: Internal Clear "
7167 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007168 break;
7169 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7170 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007171 "SAS Device Status Change: Internal Query "
7172 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007173 break;
7174 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007175 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007176 "SAS Device Status Change: Unknown: "
7177 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007178 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007179 }
7180 break;
7181 }
7182 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7183 ds = "Bus Timer Expired";
7184 break;
7185 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007186 {
7187 u16 curr_depth = (u16)(evData0 >> 16);
7188 u8 channel = (u8)(evData0 >> 8);
7189 u8 id = (u8)(evData0);
7190
7191 snprintf(evStr, EVENT_DESCR_STR_SZ,
7192 "Queue Full: channel=%d id=%d depth=%d",
7193 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007194 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007195 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007196 case MPI_EVENT_SAS_SES:
7197 ds = "SAS SES Event";
7198 break;
7199 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7200 ds = "Persistent Table Full";
7201 break;
7202 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007203 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007204 u8 LinkRates = (u8)(evData0 >> 8);
7205 u8 PhyNumber = (u8)(evData0);
7206 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7207 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7208 switch (LinkRates) {
7209 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007210 snprintf(evStr, EVENT_DESCR_STR_SZ,
7211 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007212 " Rate Unknown",PhyNumber);
7213 break;
7214 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007215 snprintf(evStr, EVENT_DESCR_STR_SZ,
7216 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007217 " Phy Disabled",PhyNumber);
7218 break;
7219 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007220 snprintf(evStr, EVENT_DESCR_STR_SZ,
7221 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007222 " Failed Speed Nego",PhyNumber);
7223 break;
7224 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007225 snprintf(evStr, EVENT_DESCR_STR_SZ,
7226 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007227 " Sata OOB Completed",PhyNumber);
7228 break;
7229 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007230 snprintf(evStr, EVENT_DESCR_STR_SZ,
7231 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007232 " Rate 1.5 Gbps",PhyNumber);
7233 break;
7234 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007235 snprintf(evStr, EVENT_DESCR_STR_SZ,
7236 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007237 " Rate 3.0 Gpbs",PhyNumber);
7238 break;
7239 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007240 snprintf(evStr, EVENT_DESCR_STR_SZ,
7241 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007242 break;
7243 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007244 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007245 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007246 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7247 ds = "SAS Discovery Error";
7248 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007249 case MPI_EVENT_IR_RESYNC_UPDATE:
7250 {
7251 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007252 snprintf(evStr, EVENT_DESCR_STR_SZ,
7253 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007254 break;
7255 }
7256 case MPI_EVENT_IR2:
7257 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307258 u8 id = (u8)(evData0);
7259 u8 channel = (u8)(evData0 >> 8);
7260 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007261 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307262
Moore, Eric3a892be2006-03-14 09:14:03 -07007263 switch (ReasonCode) {
7264 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307265 snprintf(evStr, EVENT_DESCR_STR_SZ,
7266 "IR2: LD State Changed: "
7267 "id=%d channel=%d phys_num=%d",
7268 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007269 break;
7270 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307271 snprintf(evStr, EVENT_DESCR_STR_SZ,
7272 "IR2: PD State Changed "
7273 "id=%d channel=%d phys_num=%d",
7274 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007275 break;
7276 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307277 snprintf(evStr, EVENT_DESCR_STR_SZ,
7278 "IR2: Bad Block Table Full: "
7279 "id=%d channel=%d phys_num=%d",
7280 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007281 break;
7282 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307283 snprintf(evStr, EVENT_DESCR_STR_SZ,
7284 "IR2: PD Inserted: "
7285 "id=%d channel=%d phys_num=%d",
7286 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007287 break;
7288 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307289 snprintf(evStr, EVENT_DESCR_STR_SZ,
7290 "IR2: PD Removed: "
7291 "id=%d channel=%d phys_num=%d",
7292 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007293 break;
7294 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307295 snprintf(evStr, EVENT_DESCR_STR_SZ,
7296 "IR2: Foreign CFG Detected: "
7297 "id=%d channel=%d phys_num=%d",
7298 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007299 break;
7300 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307301 snprintf(evStr, EVENT_DESCR_STR_SZ,
7302 "IR2: Rebuild Medium Error: "
7303 "id=%d channel=%d phys_num=%d",
7304 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007305 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307306 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7307 snprintf(evStr, EVENT_DESCR_STR_SZ,
7308 "IR2: Dual Port Added: "
7309 "id=%d channel=%d phys_num=%d",
7310 id, channel, phys_num);
7311 break;
7312 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7313 snprintf(evStr, EVENT_DESCR_STR_SZ,
7314 "IR2: Dual Port Removed: "
7315 "id=%d channel=%d phys_num=%d",
7316 id, channel, phys_num);
7317 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007318 default:
7319 ds = "IR2";
7320 break;
7321 }
7322 break;
7323 }
7324 case MPI_EVENT_SAS_DISCOVERY:
7325 {
7326 if (evData0)
7327 ds = "SAS Discovery: Start";
7328 else
7329 ds = "SAS Discovery: Stop";
7330 break;
7331 }
7332 case MPI_EVENT_LOG_ENTRY_ADDED:
7333 ds = "SAS Log Entry Added";
7334 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007335
Eric Moorec6c727a2007-01-29 09:44:54 -07007336 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7337 {
7338 u8 phy_num = (u8)(evData0);
7339 u8 port_num = (u8)(evData0 >> 8);
7340 u8 port_width = (u8)(evData0 >> 16);
7341 u8 primative = (u8)(evData0 >> 24);
7342 snprintf(evStr, EVENT_DESCR_STR_SZ,
7343 "SAS Broadcase Primative: phy=%d port=%d "
7344 "width=%d primative=0x%02x",
7345 phy_num, port_num, port_width, primative);
7346 break;
7347 }
7348
7349 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7350 {
7351 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007352
Kashyap, Desai2f187862009-05-29 16:52:37 +05307353 switch (reason) {
7354 case MPI_EVENT_SAS_INIT_RC_ADDED:
7355 ds = "SAS Initiator Status Change: Added";
7356 break;
7357 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7358 ds = "SAS Initiator Status Change: Deleted";
7359 break;
7360 default:
7361 ds = "SAS Initiator Status Change";
7362 break;
7363 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007364 break;
7365 }
7366
7367 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7368 {
7369 u8 max_init = (u8)(evData0);
7370 u8 current_init = (u8)(evData0 >> 8);
7371
7372 snprintf(evStr, EVENT_DESCR_STR_SZ,
7373 "SAS Initiator Device Table Overflow: max initiators=%02d "
7374 "current initators=%02d",
7375 max_init, current_init);
7376 break;
7377 }
7378 case MPI_EVENT_SAS_SMP_ERROR:
7379 {
7380 u8 status = (u8)(evData0);
7381 u8 port_num = (u8)(evData0 >> 8);
7382 u8 result = (u8)(evData0 >> 16);
7383
7384 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7385 snprintf(evStr, EVENT_DESCR_STR_SZ,
7386 "SAS SMP Error: port=%d result=0x%02x",
7387 port_num, result);
7388 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7389 snprintf(evStr, EVENT_DESCR_STR_SZ,
7390 "SAS SMP Error: port=%d : CRC Error",
7391 port_num);
7392 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7393 snprintf(evStr, EVENT_DESCR_STR_SZ,
7394 "SAS SMP Error: port=%d : Timeout",
7395 port_num);
7396 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7397 snprintf(evStr, EVENT_DESCR_STR_SZ,
7398 "SAS SMP Error: port=%d : No Destination",
7399 port_num);
7400 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7401 snprintf(evStr, EVENT_DESCR_STR_SZ,
7402 "SAS SMP Error: port=%d : Bad Destination",
7403 port_num);
7404 else
7405 snprintf(evStr, EVENT_DESCR_STR_SZ,
7406 "SAS SMP Error: port=%d : status=0x%02x",
7407 port_num, status);
7408 break;
7409 }
7410
Kashyap, Desai2f187862009-05-29 16:52:37 +05307411 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7412 {
7413 u8 reason = (u8)(evData0);
7414
7415 switch (reason) {
7416 case MPI_EVENT_SAS_EXP_RC_ADDED:
7417 ds = "Expander Status Change: Added";
7418 break;
7419 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7420 ds = "Expander Status Change: Deleted";
7421 break;
7422 default:
7423 ds = "Expander Status Change";
7424 break;
7425 }
7426 break;
7427 }
7428
Linus Torvalds1da177e2005-04-16 15:20:36 -07007429 /*
7430 * MPT base "custom" events may be added here...
7431 */
7432 default:
7433 ds = "Unknown";
7434 break;
7435 }
Eric Moore509e5e52006-04-26 13:22:37 -06007436 if (ds)
7437 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007438
Kashyap, Desai2f187862009-05-29 16:52:37 +05307439
7440 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7441 "MPT event:(%02Xh) : %s\n",
7442 ioc->name, event, evStr));
7443
7444 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7445 ": Event data:\n"));
7446 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7447 devtverboseprintk(ioc, printk(" %08x",
7448 le32_to_cpu(pEventReply->Data[ii])));
7449 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7450}
7451#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007452/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007453/**
7454 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007455 * @ioc: Pointer to MPT_ADAPTER structure
7456 * @pEventReply: Pointer to EventNotification reply frame
7457 * @evHandlers: Pointer to integer, number of event handlers
7458 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007459 * Routes a received EventNotificationReply to all currently registered
7460 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007461 * Returns sum of event handlers return values.
7462 */
7463static int
7464ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7465{
7466 u16 evDataLen;
7467 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007468 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307469 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007470 int r = 0;
7471 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007472 u8 event;
7473
7474 /*
7475 * Do platform normalization of values
7476 */
7477 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007478 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7479 if (evDataLen) {
7480 evData0 = le32_to_cpu(pEventReply->Data[0]);
7481 }
7482
Prakash, Sathya436ace72007-07-24 15:42:08 +05307483#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307484 if (evDataLen)
7485 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007486#endif
7487
7488 /*
7489 * Do general / base driver event processing
7490 */
7491 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007492 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7493 if (evDataLen) {
7494 u8 evState = evData0 & 0xFF;
7495
7496 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7497
7498 /* Update EventState field in cached IocFacts */
7499 if (ioc->facts.Function) {
7500 ioc->facts.EventState = evState;
7501 }
7502 }
7503 break;
Moore, Ericece50912006-01-16 18:53:19 -07007504 case MPI_EVENT_INTEGRATED_RAID:
7505 mptbase_raid_process_event_data(ioc,
7506 (MpiEventDataRaid_t *)pEventReply->Data);
7507 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007508 default:
7509 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007510 }
7511
7512 /*
7513 * Should this event be logged? Events are written sequentially.
7514 * When buffer is full, start again at the top.
7515 */
7516 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7517 int idx;
7518
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007519 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007520
7521 ioc->events[idx].event = event;
7522 ioc->events[idx].eventContext = ioc->eventContext;
7523
7524 for (ii = 0; ii < 2; ii++) {
7525 if (ii < evDataLen)
7526 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7527 else
7528 ioc->events[idx].data[ii] = 0;
7529 }
7530
7531 ioc->eventContext++;
7532 }
7533
7534
7535 /*
7536 * Call each currently registered protocol event handler.
7537 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007538 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307539 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307540 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7541 "Routing Event to event handler #%d\n",
7542 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307543 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007544 handlers++;
7545 }
7546 }
7547 /* FIXME? Examine results here? */
7548
7549 /*
7550 * If needed, send (a single) EventAck.
7551 */
7552 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307553 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007554 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007555 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307556 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007557 ioc->name, ii));
7558 }
7559 }
7560
7561 *evHandlers = handlers;
7562 return r;
7563}
7564
7565/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007566/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007567 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7568 * @ioc: Pointer to MPT_ADAPTER structure
7569 * @log_info: U32 LogInfo reply word from the IOC
7570 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007571 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007572 */
7573static void
7574mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7575{
Eric Moore7c431e52007-06-13 16:34:36 -06007576 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007577
Eric Moore7c431e52007-06-13 16:34:36 -06007578 switch (log_info & 0xFF000000) {
7579 case MPI_IOCLOGINFO_FC_INIT_BASE:
7580 desc = "FCP Initiator";
7581 break;
7582 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7583 desc = "FCP Target";
7584 break;
7585 case MPI_IOCLOGINFO_FC_LAN_BASE:
7586 desc = "LAN";
7587 break;
7588 case MPI_IOCLOGINFO_FC_MSG_BASE:
7589 desc = "MPI Message Layer";
7590 break;
7591 case MPI_IOCLOGINFO_FC_LINK_BASE:
7592 desc = "FC Link";
7593 break;
7594 case MPI_IOCLOGINFO_FC_CTX_BASE:
7595 desc = "Context Manager";
7596 break;
7597 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7598 desc = "Invalid Field Offset";
7599 break;
7600 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7601 desc = "State Change Info";
7602 break;
7603 }
7604
7605 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7606 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007607}
7608
7609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007610/**
Moore, Eric335a9412006-01-17 17:06:23 -07007611 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007612 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007613 * @log_info: U32 LogInfo word from the IOC
7614 *
7615 * Refer to lsi/sp_log.h.
7616 */
7617static void
Moore, Eric335a9412006-01-17 17:06:23 -07007618mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007619{
7620 u32 info = log_info & 0x00FF0000;
7621 char *desc = "unknown";
7622
7623 switch (info) {
7624 case 0x00010000:
7625 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007626 break;
7627
7628 case 0x00020000:
7629 desc = "Parity Error";
7630 break;
7631
7632 case 0x00030000:
7633 desc = "ASYNC Outbound Overrun";
7634 break;
7635
7636 case 0x00040000:
7637 desc = "SYNC Offset Error";
7638 break;
7639
7640 case 0x00050000:
7641 desc = "BM Change";
7642 break;
7643
7644 case 0x00060000:
7645 desc = "Msg In Overflow";
7646 break;
7647
7648 case 0x00070000:
7649 desc = "DMA Error";
7650 break;
7651
7652 case 0x00080000:
7653 desc = "Outbound DMA Overrun";
7654 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007655
Linus Torvalds1da177e2005-04-16 15:20:36 -07007656 case 0x00090000:
7657 desc = "Task Management";
7658 break;
7659
7660 case 0x000A0000:
7661 desc = "Device Problem";
7662 break;
7663
7664 case 0x000B0000:
7665 desc = "Invalid Phase Change";
7666 break;
7667
7668 case 0x000C0000:
7669 desc = "Untagged Table Size";
7670 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007671
Linus Torvalds1da177e2005-04-16 15:20:36 -07007672 }
7673
7674 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7675}
7676
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007677/* strings for sas loginfo */
7678 static char *originator_str[] = {
7679 "IOP", /* 00h */
7680 "PL", /* 01h */
7681 "IR" /* 02h */
7682 };
7683 static char *iop_code_str[] = {
7684 NULL, /* 00h */
7685 "Invalid SAS Address", /* 01h */
7686 NULL, /* 02h */
7687 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007688 "Diag Message Error", /* 04h */
7689 "Task Terminated", /* 05h */
7690 "Enclosure Management", /* 06h */
7691 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007692 };
7693 static char *pl_code_str[] = {
7694 NULL, /* 00h */
7695 "Open Failure", /* 01h */
7696 "Invalid Scatter Gather List", /* 02h */
7697 "Wrong Relative Offset or Frame Length", /* 03h */
7698 "Frame Transfer Error", /* 04h */
7699 "Transmit Frame Connected Low", /* 05h */
7700 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7701 "SATA Read Log Receive Data Error", /* 07h */
7702 "SATA NCQ Fail All Commands After Error", /* 08h */
7703 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7704 "Receive Frame Invalid Message", /* 0Ah */
7705 "Receive Context Message Valid Error", /* 0Bh */
7706 "Receive Frame Current Frame Error", /* 0Ch */
7707 "SATA Link Down", /* 0Dh */
7708 "Discovery SATA Init W IOS", /* 0Eh */
7709 "Config Invalid Page", /* 0Fh */
7710 "Discovery SATA Init Timeout", /* 10h */
7711 "Reset", /* 11h */
7712 "Abort", /* 12h */
7713 "IO Not Yet Executed", /* 13h */
7714 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007715 "Persistent Reservation Out Not Affiliation "
7716 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007717 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007718 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007719 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007720 NULL, /* 19h */
7721 NULL, /* 1Ah */
7722 NULL, /* 1Bh */
7723 NULL, /* 1Ch */
7724 NULL, /* 1Dh */
7725 NULL, /* 1Eh */
7726 NULL, /* 1Fh */
7727 "Enclosure Management" /* 20h */
7728 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007729 static char *ir_code_str[] = {
7730 "Raid Action Error", /* 00h */
7731 NULL, /* 00h */
7732 NULL, /* 01h */
7733 NULL, /* 02h */
7734 NULL, /* 03h */
7735 NULL, /* 04h */
7736 NULL, /* 05h */
7737 NULL, /* 06h */
7738 NULL /* 07h */
7739 };
7740 static char *raid_sub_code_str[] = {
7741 NULL, /* 00h */
7742 "Volume Creation Failed: Data Passed too "
7743 "Large", /* 01h */
7744 "Volume Creation Failed: Duplicate Volumes "
7745 "Attempted", /* 02h */
7746 "Volume Creation Failed: Max Number "
7747 "Supported Volumes Exceeded", /* 03h */
7748 "Volume Creation Failed: DMA Error", /* 04h */
7749 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7750 "Volume Creation Failed: Error Reading "
7751 "MFG Page 4", /* 06h */
7752 "Volume Creation Failed: Creating Internal "
7753 "Structures", /* 07h */
7754 NULL, /* 08h */
7755 NULL, /* 09h */
7756 NULL, /* 0Ah */
7757 NULL, /* 0Bh */
7758 NULL, /* 0Ch */
7759 NULL, /* 0Dh */
7760 NULL, /* 0Eh */
7761 NULL, /* 0Fh */
7762 "Activation failed: Already Active Volume", /* 10h */
7763 "Activation failed: Unsupported Volume Type", /* 11h */
7764 "Activation failed: Too Many Active Volumes", /* 12h */
7765 "Activation failed: Volume ID in Use", /* 13h */
7766 "Activation failed: Reported Failure", /* 14h */
7767 "Activation failed: Importing a Volume", /* 15h */
7768 NULL, /* 16h */
7769 NULL, /* 17h */
7770 NULL, /* 18h */
7771 NULL, /* 19h */
7772 NULL, /* 1Ah */
7773 NULL, /* 1Bh */
7774 NULL, /* 1Ch */
7775 NULL, /* 1Dh */
7776 NULL, /* 1Eh */
7777 NULL, /* 1Fh */
7778 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7779 "Phys Disk failed: Data Passed too Large", /* 21h */
7780 "Phys Disk failed: DMA Error", /* 22h */
7781 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7782 "Phys Disk failed: Creating Phys Disk Config "
7783 "Page", /* 24h */
7784 NULL, /* 25h */
7785 NULL, /* 26h */
7786 NULL, /* 27h */
7787 NULL, /* 28h */
7788 NULL, /* 29h */
7789 NULL, /* 2Ah */
7790 NULL, /* 2Bh */
7791 NULL, /* 2Ch */
7792 NULL, /* 2Dh */
7793 NULL, /* 2Eh */
7794 NULL, /* 2Fh */
7795 "Compatibility Error: IR Disabled", /* 30h */
7796 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7797 "Compatibility Error: Device not Direct Access "
7798 "Device ", /* 32h */
7799 "Compatibility Error: Removable Device Found", /* 33h */
7800 "Compatibility Error: Device SCSI Version not "
7801 "2 or Higher", /* 34h */
7802 "Compatibility Error: SATA Device, 48 BIT LBA "
7803 "not Supported", /* 35h */
7804 "Compatibility Error: Device doesn't have "
7805 "512 Byte Block Sizes", /* 36h */
7806 "Compatibility Error: Volume Type Check Failed", /* 37h */
7807 "Compatibility Error: Volume Type is "
7808 "Unsupported by FW", /* 38h */
7809 "Compatibility Error: Disk Drive too Small for "
7810 "use in Volume", /* 39h */
7811 "Compatibility Error: Phys Disk for Create "
7812 "Volume not Found", /* 3Ah */
7813 "Compatibility Error: Too Many or too Few "
7814 "Disks for Volume Type", /* 3Bh */
7815 "Compatibility Error: Disk stripe Sizes "
7816 "Must be 64KB", /* 3Ch */
7817 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7818 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007819
7820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007821/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007822 * mpt_sas_log_info - Log information returned from SAS IOC.
7823 * @ioc: Pointer to MPT_ADAPTER structure
7824 * @log_info: U32 LogInfo reply word from the IOC
7825 *
7826 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007827 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007828static void
7829mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7830{
7831union loginfo_type {
7832 u32 loginfo;
7833 struct {
7834 u32 subcode:16;
7835 u32 code:8;
7836 u32 originator:4;
7837 u32 bus_type:4;
7838 }dw;
7839};
7840 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007841 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007842 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007843 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007844
7845 sas_loginfo.loginfo = log_info;
7846 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007847 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007848 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007849
7850 originator_desc = originator_str[sas_loginfo.dw.originator];
7851
7852 switch (sas_loginfo.dw.originator) {
7853
7854 case 0: /* IOP */
7855 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007856 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007857 code_desc = iop_code_str[sas_loginfo.dw.code];
7858 break;
7859 case 1: /* PL */
7860 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007861 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007862 code_desc = pl_code_str[sas_loginfo.dw.code];
7863 break;
7864 case 2: /* IR */
7865 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007866 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007867 break;
7868 code_desc = ir_code_str[sas_loginfo.dw.code];
7869 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007870 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007871 break;
7872 if (sas_loginfo.dw.code == 0)
7873 sub_code_desc =
7874 raid_sub_code_str[sas_loginfo.dw.subcode];
7875 break;
7876 default:
7877 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007878 }
7879
Eric Moorec6c727a2007-01-29 09:44:54 -07007880 if (sub_code_desc != NULL)
7881 printk(MYIOC_s_INFO_FMT
7882 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7883 " SubCode={%s}\n",
7884 ioc->name, log_info, originator_desc, code_desc,
7885 sub_code_desc);
7886 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007887 printk(MYIOC_s_INFO_FMT
7888 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7889 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007890 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007891 sas_loginfo.dw.subcode);
7892 else
7893 printk(MYIOC_s_INFO_FMT
7894 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7895 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007896 ioc->name, log_info, originator_desc,
7897 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007898}
7899
Linus Torvalds1da177e2005-04-16 15:20:36 -07007900/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007901/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007902 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7903 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007904 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007905 * @mf: Pointer to MPT request frame
7906 *
7907 * Refer to lsi/mpi.h.
7908 **/
7909static void
7910mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7911{
7912 Config_t *pReq = (Config_t *)mf;
7913 char extend_desc[EVENT_DESCR_STR_SZ];
7914 char *desc = NULL;
7915 u32 form;
7916 u8 page_type;
7917
7918 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7919 page_type = pReq->ExtPageType;
7920 else
7921 page_type = pReq->Header.PageType;
7922
7923 /*
7924 * ignore invalid page messages for GET_NEXT_HANDLE
7925 */
7926 form = le32_to_cpu(pReq->PageAddress);
7927 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7928 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7929 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7930 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7931 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7932 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7933 return;
7934 }
7935 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7936 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7937 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7938 return;
7939 }
7940
7941 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7942 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7943 page_type, pReq->Header.PageNumber, pReq->Action, form);
7944
7945 switch (ioc_status) {
7946
7947 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7948 desc = "Config Page Invalid Action";
7949 break;
7950
7951 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7952 desc = "Config Page Invalid Type";
7953 break;
7954
7955 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7956 desc = "Config Page Invalid Page";
7957 break;
7958
7959 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7960 desc = "Config Page Invalid Data";
7961 break;
7962
7963 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7964 desc = "Config Page No Defaults";
7965 break;
7966
7967 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7968 desc = "Config Page Can't Commit";
7969 break;
7970 }
7971
7972 if (!desc)
7973 return;
7974
Eric Moore29dd3602007-09-14 18:46:51 -06007975 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7976 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007977}
7978
7979/**
7980 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007981 * @ioc: Pointer to MPT_ADAPTER structure
7982 * @ioc_status: U32 IOCStatus word from IOC
7983 * @mf: Pointer to MPT request frame
7984 *
7985 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007986 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007987static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007988mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007989{
7990 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007991 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007992
7993 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007994
7995/****************************************************************************/
7996/* Common IOCStatus values for all replies */
7997/****************************************************************************/
7998
Linus Torvalds1da177e2005-04-16 15:20:36 -07007999 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8000 desc = "Invalid Function";
8001 break;
8002
8003 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8004 desc = "Busy";
8005 break;
8006
8007 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8008 desc = "Invalid SGL";
8009 break;
8010
8011 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8012 desc = "Internal Error";
8013 break;
8014
8015 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8016 desc = "Reserved";
8017 break;
8018
8019 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8020 desc = "Insufficient Resources";
8021 break;
8022
8023 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8024 desc = "Invalid Field";
8025 break;
8026
8027 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8028 desc = "Invalid State";
8029 break;
8030
Eric Moorec6c727a2007-01-29 09:44:54 -07008031/****************************************************************************/
8032/* Config IOCStatus values */
8033/****************************************************************************/
8034
Linus Torvalds1da177e2005-04-16 15:20:36 -07008035 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8036 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8037 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8038 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8039 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8040 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008041 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008042 break;
8043
Eric Moorec6c727a2007-01-29 09:44:54 -07008044/****************************************************************************/
8045/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8046/* */
8047/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8048/* */
8049/****************************************************************************/
8050
Linus Torvalds1da177e2005-04-16 15:20:36 -07008051 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008052 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008053 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8054 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8055 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8056 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008057 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008058 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008059 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008060 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008061 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008062 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008063 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008064 break;
8065
Eric Moorec6c727a2007-01-29 09:44:54 -07008066/****************************************************************************/
8067/* SCSI Target values */
8068/****************************************************************************/
8069
8070 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8071 desc = "Target: Priority IO";
8072 break;
8073
8074 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8075 desc = "Target: Invalid Port";
8076 break;
8077
8078 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8079 desc = "Target Invalid IO Index:";
8080 break;
8081
8082 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8083 desc = "Target: Aborted";
8084 break;
8085
8086 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8087 desc = "Target: No Conn Retryable";
8088 break;
8089
8090 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8091 desc = "Target: No Connection";
8092 break;
8093
8094 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8095 desc = "Target: Transfer Count Mismatch";
8096 break;
8097
8098 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8099 desc = "Target: STS Data not Sent";
8100 break;
8101
8102 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8103 desc = "Target: Data Offset Error";
8104 break;
8105
8106 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8107 desc = "Target: Too Much Write Data";
8108 break;
8109
8110 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8111 desc = "Target: IU Too Short";
8112 break;
8113
8114 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8115 desc = "Target: ACK NAK Timeout";
8116 break;
8117
8118 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8119 desc = "Target: Nak Received";
8120 break;
8121
8122/****************************************************************************/
8123/* Fibre Channel Direct Access values */
8124/****************************************************************************/
8125
8126 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8127 desc = "FC: Aborted";
8128 break;
8129
8130 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8131 desc = "FC: RX ID Invalid";
8132 break;
8133
8134 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8135 desc = "FC: DID Invalid";
8136 break;
8137
8138 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8139 desc = "FC: Node Logged Out";
8140 break;
8141
8142 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8143 desc = "FC: Exchange Canceled";
8144 break;
8145
8146/****************************************************************************/
8147/* LAN values */
8148/****************************************************************************/
8149
8150 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8151 desc = "LAN: Device not Found";
8152 break;
8153
8154 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8155 desc = "LAN: Device Failure";
8156 break;
8157
8158 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8159 desc = "LAN: Transmit Error";
8160 break;
8161
8162 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8163 desc = "LAN: Transmit Aborted";
8164 break;
8165
8166 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8167 desc = "LAN: Receive Error";
8168 break;
8169
8170 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8171 desc = "LAN: Receive Aborted";
8172 break;
8173
8174 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8175 desc = "LAN: Partial Packet";
8176 break;
8177
8178 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8179 desc = "LAN: Canceled";
8180 break;
8181
8182/****************************************************************************/
8183/* Serial Attached SCSI values */
8184/****************************************************************************/
8185
8186 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8187 desc = "SAS: SMP Request Failed";
8188 break;
8189
8190 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8191 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008192 break;
8193
8194 default:
8195 desc = "Others";
8196 break;
8197 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008198
8199 if (!desc)
8200 return;
8201
Eric Moore29dd3602007-09-14 18:46:51 -06008202 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8203 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008204}
8205
8206/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008207EXPORT_SYMBOL(mpt_attach);
8208EXPORT_SYMBOL(mpt_detach);
8209#ifdef CONFIG_PM
8210EXPORT_SYMBOL(mpt_resume);
8211EXPORT_SYMBOL(mpt_suspend);
8212#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008213EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008214EXPORT_SYMBOL(mpt_register);
8215EXPORT_SYMBOL(mpt_deregister);
8216EXPORT_SYMBOL(mpt_event_register);
8217EXPORT_SYMBOL(mpt_event_deregister);
8218EXPORT_SYMBOL(mpt_reset_register);
8219EXPORT_SYMBOL(mpt_reset_deregister);
8220EXPORT_SYMBOL(mpt_device_driver_register);
8221EXPORT_SYMBOL(mpt_device_driver_deregister);
8222EXPORT_SYMBOL(mpt_get_msg_frame);
8223EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308224EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008225EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008226EXPORT_SYMBOL(mpt_send_handshake_request);
8227EXPORT_SYMBOL(mpt_verify_adapter);
8228EXPORT_SYMBOL(mpt_GetIocState);
8229EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008230EXPORT_SYMBOL(mpt_HardResetHandler);
8231EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008232EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008233EXPORT_SYMBOL(mpt_alloc_fw_memory);
8234EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008235EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008236EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008237
Linus Torvalds1da177e2005-04-16 15:20:36 -07008238/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008239/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008240 * fusion_init - Fusion MPT base driver initialization routine.
8241 *
8242 * Returns 0 for success, non-zero for failure.
8243 */
8244static int __init
8245fusion_init(void)
8246{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308247 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008248
8249 show_mptmod_ver(my_NAME, my_VERSION);
8250 printk(KERN_INFO COPYRIGHT "\n");
8251
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308252 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8253 MptCallbacks[cb_idx] = NULL;
8254 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8255 MptEvHandlers[cb_idx] = NULL;
8256 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008257 }
8258
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008259 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008260 * EventNotification handling.
8261 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05308262 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008263
8264 /* Register for hard reset handling callbacks.
8265 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308266 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008267
8268#ifdef CONFIG_PROC_FS
8269 (void) procmpt_create();
8270#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008271 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008272}
8273
8274/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008275/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008276 * fusion_exit - Perform driver unload cleanup.
8277 *
8278 * This routine frees all resources associated with each MPT adapter
8279 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8280 */
8281static void __exit
8282fusion_exit(void)
8283{
8284
Linus Torvalds1da177e2005-04-16 15:20:36 -07008285 mpt_reset_deregister(mpt_base_index);
8286
8287#ifdef CONFIG_PROC_FS
8288 procmpt_destroy();
8289#endif
8290}
8291
Linus Torvalds1da177e2005-04-16 15:20:36 -07008292module_init(fusion_init);
8293module_exit(fusion_exit);