blob: e63a6260b0a0c2c38d777718ee94de456cdf52d5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05308 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053082
83static int mpt_msi_enable_spi;
84module_param(mpt_msi_enable_spi, int, 0);
85MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
86 controllers (default=0)");
87
88static int mpt_msi_enable_fc;
89module_param(mpt_msi_enable_fc, int, 0);
90MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
91 controllers (default=0)");
92
93static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080094module_param(mpt_msi_enable_sas, int, 0);
Kashyap, Desaie3829682009-01-08 14:27:16 +053095MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
Yinghai Lu5ce78682009-02-18 11:25:32 -080096 controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053097
Christoph Hellwig4ddce142006-01-17 13:44:29 +000098
Eric Moore793955f2007-01-29 09:42:20 -070099static int mpt_channel_mapping;
100module_param(mpt_channel_mapping, int, 0);
101MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
102
Prakash, Sathya436ace72007-07-24 15:42:08 +0530103static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400104static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
105module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
106 &mpt_debug_level, 0600);
Kashyap, Desaie3829682009-01-08 14:27:16 +0530107MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
108 - (default=0)");
109
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530110int mpt_fwfault_debug;
111EXPORT_SYMBOL(mpt_fwfault_debug);
112module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
113 &mpt_fwfault_debug, 0600);
114MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
115 " and halt Firmware on fault - (default=0)");
116
117
Prakash, Sathya436ace72007-07-24 15:42:08 +0530118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#ifdef MFCNT
120static int mfcounter = 0;
121#define PRINT_MF_COUNT 20000
122#endif
123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * Public data...
127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Adrian Bunk15424922008-04-22 00:31:51 +0300129static struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131#define WHOINIT_UNKNOWN 0xAA
132
133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
134/*
135 * Private data...
136 */
137 /* Adapter link list */
138LIST_HEAD(ioc_list);
139 /* Callback lookup table */
140static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Protocol driver class lookup table */
142static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
143 /* Event handler lookup table */
144static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145 /* Reset handler lookup table */
146static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
147static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530150/*
151 * Driver Callback Index's
152 */
153static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
154static u8 last_drv_idx;
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
157/*
158 * Forward protos...
159 */
David Howells7d12e782006-10-05 14:55:46 +0100160static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530161static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
162 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
164 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
165 int sleepFlag);
166static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
167static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
168static void mpt_adapter_disable(MPT_ADAPTER *ioc);
169static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
170
171static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
172static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
174static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
175static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
176static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
177static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200178static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
180static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
181static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
182static int PrimeIocFifos(MPT_ADAPTER *ioc);
183static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
184static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
185static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200188int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
190static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
191static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
192static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530193static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530194static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
195 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200197static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
198static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200#ifdef CONFIG_PROC_FS
201static int procmpt_summary_read(char *buf, char **start, off_t offset,
202 int request, int *eof, void *data);
203static int procmpt_version_read(char *buf, char **start, off_t offset,
204 int request, int *eof, void *data);
205static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
206 int request, int *eof, void *data);
207#endif
208static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
209
210//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530211static int ProcessEventNotification(MPT_ADAPTER *ioc,
212 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700213static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700215static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600216static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700217static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700218static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221static int __init fusion_init (void);
222static void __exit fusion_exit (void);
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224#define CHIPREG_READ32(addr) readl_relaxed(addr)
225#define CHIPREG_READ32_dmasync(addr) readl(addr)
226#define CHIPREG_WRITE32(addr,val) writel(val, addr)
227#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
228#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
229
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600230static void
231pci_disable_io_access(struct pci_dev *pdev)
232{
233 u16 command_reg;
234
235 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
236 command_reg &= ~1;
237 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
238}
239
240static void
241pci_enable_io_access(struct pci_dev *pdev)
242{
243 u16 command_reg;
244
245 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
246 command_reg |= 1;
247 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
248}
249
James Bottomleydb47c2d2007-07-28 13:40:21 -0400250static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
251{
252 int ret = param_set_int(val, kp);
253 MPT_ADAPTER *ioc;
254
255 if (ret)
256 return ret;
257
258 list_for_each_entry(ioc, &ioc_list, list)
259 ioc->debug_level = mpt_debug_level;
260 return 0;
261}
262
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530263/**
264 * mpt_get_cb_idx - obtain cb_idx for registered driver
265 * @dclass: class driver enum
266 *
267 * Returns cb_idx, or zero means it wasn't found
268 **/
269static u8
270mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
271{
272 u8 cb_idx;
273
274 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
275 if (MptDriverClass[cb_idx] == dclass)
276 return cb_idx;
277 return 0;
278}
279
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530280/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530281 * mpt_is_discovery_complete - determine if discovery has completed
282 * @ioc: per adatper instance
283 *
284 * Returns 1 when discovery completed, else zero.
285 */
286static int
287mpt_is_discovery_complete(MPT_ADAPTER *ioc)
288{
289 ConfigExtendedPageHeader_t hdr;
290 CONFIGPARMS cfg;
291 SasIOUnitPage0_t *buffer;
292 dma_addr_t dma_handle;
293 int rc = 0;
294
295 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
296 memset(&cfg, 0, sizeof(CONFIGPARMS));
297 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
298 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
299 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
300 cfg.cfghdr.ehdr = &hdr;
301 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
302
303 if ((mpt_config(ioc, &cfg)))
304 goto out;
305 if (!hdr.ExtPageLength)
306 goto out;
307
308 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
309 &dma_handle);
310 if (!buffer)
311 goto out;
312
313 cfg.physAddr = dma_handle;
314 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
315
316 if ((mpt_config(ioc, &cfg)))
317 goto out_free_consistent;
318
319 if (!(buffer->PhyData[0].PortFlags &
320 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
321 rc = 1;
322
323 out_free_consistent:
324 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
325 buffer, dma_handle);
326 out:
327 return rc;
328}
329
330/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530331 * mpt_fault_reset_work - work performed on workq after ioc fault
332 * @work: input argument, used to derive ioc
333 *
334**/
335static void
336mpt_fault_reset_work(struct work_struct *work)
337{
338 MPT_ADAPTER *ioc =
339 container_of(work, MPT_ADAPTER, fault_reset_work.work);
340 u32 ioc_raw_state;
341 int rc;
342 unsigned long flags;
343
344 if (ioc->diagPending || !ioc->active)
345 goto out;
346
347 ioc_raw_state = mpt_GetIocState(ioc, 0);
348 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
349 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700350 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530351 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700352 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530353 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
354 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700355 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530356 ioc_raw_state = mpt_GetIocState(ioc, 0);
357 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
358 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
359 "reset (%04xh)\n", ioc->name, ioc_raw_state &
360 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530361 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
362 if ((mpt_is_discovery_complete(ioc))) {
363 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
364 "discovery_quiesce_io flag\n", ioc->name));
365 ioc->sas_discovery_quiesce_io = 0;
366 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530367 }
368
369 out:
370 /*
371 * Take turns polling alternate controller
372 */
373 if (ioc->alt_ioc)
374 ioc = ioc->alt_ioc;
375
376 /* rearm the timer */
377 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
378 if (ioc->reset_work_q)
379 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
380 msecs_to_jiffies(MPT_POLLING_INTERVAL));
381 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
382}
383
384
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600385/*
386 * Process turbo (context) reply...
387 */
388static void
389mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
390{
391 MPT_FRAME_HDR *mf = NULL;
392 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530393 u16 req_idx = 0;
394 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600395
Prakash, Sathya436ace72007-07-24 15:42:08 +0530396 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600397 ioc->name, pa));
398
399 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
400 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
401 req_idx = pa & 0x0000FFFF;
402 cb_idx = (pa & 0x00FF0000) >> 16;
403 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
404 break;
405 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530406 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600407 /*
408 * Blind set of mf to NULL here was fatal
409 * after lan_reply says "freeme"
410 * Fix sort of combined with an optimization here;
411 * added explicit check for case where lan_reply
412 * was just returning 1 and doing nothing else.
413 * For this case skip the callback, but set up
414 * proper mf value first here:-)
415 */
416 if ((pa & 0x58000000) == 0x58000000) {
417 req_idx = pa & 0x0000FFFF;
418 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
419 mpt_free_msg_frame(ioc, mf);
420 mb();
421 return;
422 break;
423 }
424 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
425 break;
426 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530427 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600428 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
429 break;
430 default:
431 cb_idx = 0;
432 BUG();
433 }
434
435 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530436 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600437 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600438 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700439 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600440 goto out;
441 }
442
443 if (MptCallbacks[cb_idx](ioc, mf, mr))
444 mpt_free_msg_frame(ioc, mf);
445 out:
446 mb();
447}
448
449static void
450mpt_reply(MPT_ADAPTER *ioc, u32 pa)
451{
452 MPT_FRAME_HDR *mf;
453 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530454 u16 req_idx;
455 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600456 int freeme;
457
458 u32 reply_dma_low;
459 u16 ioc_stat;
460
461 /* non-TURBO reply! Hmmm, something may be up...
462 * Newest turbo reply mechanism; get address
463 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
464 */
465
466 /* Map DMA address of reply header to cpu address.
467 * pa is 32 bits - but the dma address may be 32 or 64 bits
468 * get offset based only only the low addresses
469 */
470
471 reply_dma_low = (pa <<= 1);
472 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
473 (reply_dma_low - ioc->reply_frames_low_dma));
474
475 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
476 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
477 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
478
Prakash, Sathya436ace72007-07-24 15:42:08 +0530479 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600480 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600481 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600482
483 /* Check/log IOC log info
484 */
485 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
486 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
487 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
488 if (ioc->bus_type == FC)
489 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700490 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700491 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600492 else if (ioc->bus_type == SAS)
493 mpt_sas_log_info(ioc, log_info);
494 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600495
Eric Moorec6c727a2007-01-29 09:44:54 -0700496 if (ioc_stat & MPI_IOCSTATUS_MASK)
497 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600498
499 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530500 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600501 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600502 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700503 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600504 freeme = 0;
505 goto out;
506 }
507
508 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
509
510 out:
511 /* Flush (non-TURBO) reply with a WRITE! */
512 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
513
514 if (freeme)
515 mpt_free_msg_frame(ioc, mf);
516 mb();
517}
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800520/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
522 * @irq: irq number (not used)
523 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 *
525 * This routine is registered via the request_irq() kernel API call,
526 * and handles all interrupts generated from a specific MPT adapter
527 * (also referred to as a IO Controller or IOC).
528 * This routine must clear the interrupt from the adapter and does
529 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200530 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 *
532 * This routine handles register-level access of the adapter but
533 * dispatches (calls) a protocol-specific callback routine to handle
534 * the protocol-specific details of the MPT request completion.
535 */
536static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100537mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600539 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600540 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
541
542 if (pa == 0xFFFFFFFF)
543 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 /*
546 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600548 do {
549 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600550 mpt_reply(ioc, pa);
551 else
552 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600553 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
554 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 return IRQ_HANDLED;
557}
558
559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800560/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530561 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530563 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
565 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800566 * MPT base driver's callback routine; all base driver
567 * "internal" request/reply processing is routed here.
568 * Currently used for EventNotification and EventAck handling.
569 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200570 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 * should be freed, or 0 if it shouldn't.
572 */
573static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530574mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530576 EventNotificationReply_t *pEventReply;
577 u8 event;
578 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530581 switch (reply->u.hdr.Function) {
582 case MPI_FUNCTION_EVENT_NOTIFICATION:
583 pEventReply = (EventNotificationReply_t *)reply;
584 evHandlers = 0;
585 ProcessEventNotification(ioc, pEventReply, &evHandlers);
586 event = le32_to_cpu(pEventReply->Event) & 0xFF;
587 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530589 if (event != MPI_EVENT_EVENT_CHANGE)
590 break;
591 case MPI_FUNCTION_CONFIG:
592 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
593 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
594 if (reply) {
595 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
596 memcpy(ioc->mptbase_cmds.reply, reply,
597 min(MPT_DEFAULT_FRAME_SIZE,
598 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200599 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530600 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
601 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
602 complete(&ioc->mptbase_cmds.done);
603 } else
604 freereq = 0;
605 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
606 freereq = 1;
607 break;
608 case MPI_FUNCTION_EVENT_ACK:
609 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
610 "EventAck reply received\n", ioc->name));
611 break;
612 default:
613 printk(MYIOC_s_ERR_FMT
614 "Unexpected msg function (=%02Xh) reply received!\n",
615 ioc->name, reply->u.hdr.Function);
616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618
619 /*
620 * Conditionally tell caller to free the original
621 * EventNotification/EventAck/unexpected request frame!
622 */
623 return freereq;
624}
625
626/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
627/**
628 * mpt_register - Register protocol-specific main callback handler.
629 * @cbfunc: callback function pointer
630 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
631 *
632 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800633 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 * protocol-specific driver must do this before it will be able to
635 * use any IOC resources, such as obtaining request frames.
636 *
637 * NOTES: The SCSI protocol driver currently calls this routine thrice
638 * in order to register separate callbacks; one for "normal" SCSI IO;
639 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
640 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530641 * Returns u8 valued "handle" in the range (and S.O.D. order)
642 * {N,...,7,6,5,...,1} if successful.
643 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
644 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530646u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
648{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530649 u8 cb_idx;
650 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 /*
653 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
654 * (slot/handle 0 is reserved!)
655 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530656 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
657 if (MptCallbacks[cb_idx] == NULL) {
658 MptCallbacks[cb_idx] = cbfunc;
659 MptDriverClass[cb_idx] = dclass;
660 MptEvHandlers[cb_idx] = NULL;
661 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 break;
663 }
664 }
665
666 return last_drv_idx;
667}
668
669/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
670/**
671 * mpt_deregister - Deregister a protocol drivers resources.
672 * @cb_idx: previously registered callback handle
673 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800674 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 * module is unloaded.
676 */
677void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530678mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600680 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 MptCallbacks[cb_idx] = NULL;
682 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
683 MptEvHandlers[cb_idx] = NULL;
684
685 last_drv_idx++;
686 }
687}
688
689/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
690/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800691 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 * @cb_idx: previously registered (via mpt_register) callback handle
693 * @ev_cbfunc: callback function
694 *
695 * This routine can be called by one or more protocol-specific drivers
696 * if/when they choose to be notified of MPT events.
697 *
698 * Returns 0 for success.
699 */
700int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530701mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600703 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return -1;
705
706 MptEvHandlers[cb_idx] = ev_cbfunc;
707 return 0;
708}
709
710/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
711/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800712 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 * @cb_idx: previously registered callback handle
714 *
715 * Each protocol-specific driver should call this routine
716 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800717 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600722 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return;
724
725 MptEvHandlers[cb_idx] = NULL;
726}
727
728/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
729/**
730 * mpt_reset_register - Register protocol-specific IOC reset handler.
731 * @cb_idx: previously registered (via mpt_register) callback handle
732 * @reset_func: reset function
733 *
734 * This routine can be called by one or more protocol-specific drivers
735 * if/when they choose to be notified of IOC resets.
736 *
737 * Returns 0 for success.
738 */
739int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530740mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530742 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return -1;
744
745 MptResetHandlers[cb_idx] = reset_func;
746 return 0;
747}
748
749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
750/**
751 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
752 * @cb_idx: previously registered callback handle
753 *
754 * Each protocol-specific driver should call this routine
755 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800756 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 */
758void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530759mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530761 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return;
763
764 MptResetHandlers[cb_idx] = NULL;
765}
766
767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
768/**
769 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800770 * @dd_cbfunc: driver callbacks struct
771 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 */
773int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530774mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600777 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Eric Moore8d6d83e2007-09-14 18:47:40 -0600779 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400780 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
783
784 /* call per pci device probe entry point */
785 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600786 id = ioc->pcidev->driver ?
787 ioc->pcidev->driver->id_table : NULL;
788 if (dd_cbfunc->probe)
789 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400792 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
796/**
797 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800798 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 */
800void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530801mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 struct mpt_pci_driver *dd_cbfunc;
804 MPT_ADAPTER *ioc;
805
Eric Moore8d6d83e2007-09-14 18:47:40 -0600806 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 return;
808
809 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
810
811 list_for_each_entry(ioc, &ioc_list, list) {
812 if (dd_cbfunc->remove)
813 dd_cbfunc->remove(ioc->pcidev);
814 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 MptDeviceDriverHandlers[cb_idx] = NULL;
817}
818
819
820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
821/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800822 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530823 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * @ioc: Pointer to MPT adapter structure
825 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800826 * Obtain an MPT request frame from the pool (of 1024) that are
827 * allocated per MPT adapter.
828 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 * Returns pointer to a MPT request frame or %NULL if none are available
830 * or IOC is not active.
831 */
832MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 MPT_FRAME_HDR *mf;
836 unsigned long flags;
837 u16 req_idx; /* Request index */
838
839 /* validate handle and ioc identifier */
840
841#ifdef MFCNT
842 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600843 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
844 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845#endif
846
847 /* If interrupts are not attached, do not return a request frame */
848 if (!ioc->active)
849 return NULL;
850
851 spin_lock_irqsave(&ioc->FreeQlock, flags);
852 if (!list_empty(&ioc->FreeQ)) {
853 int req_offset;
854
855 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
856 u.frame.linkage.list);
857 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200858 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530859 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
861 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500862 req_idx = req_offset / ioc->req_sz;
863 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600865 /* Default, will be changed if necessary in SG generation */
866 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867#ifdef MFCNT
868 ioc->mfcnt++;
869#endif
870 }
871 else
872 mf = NULL;
873 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
874
875#ifdef MFCNT
876 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600877 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
878 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
879 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 mfcounter++;
881 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600882 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
883 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884#endif
885
Eric Moore29dd3602007-09-14 18:46:51 -0600886 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
887 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return mf;
889}
890
891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
892/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800893 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530894 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 * @ioc: Pointer to MPT adapter structure
896 * @mf: Pointer to MPT request frame
897 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800898 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 * specific MPT adapter.
900 */
901void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530902mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 u32 mf_dma_addr;
905 int req_offset;
906 u16 req_idx; /* Request index */
907
908 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530909 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
911 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500912 req_idx = req_offset / ioc->req_sz;
913 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
915
Prakash, Sathya436ace72007-07-24 15:42:08 +0530916 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200918 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600919 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
920 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
921 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
923}
924
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530925/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800926 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530927 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530928 * @ioc: Pointer to MPT adapter structure
929 * @mf: Pointer to MPT request frame
930 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800931 * Send a protocol-specific MPT request frame to an IOC using
932 * hi-priority request queue.
933 *
934 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530935 * specific MPT adapter.
936 **/
937void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530938mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530939{
940 u32 mf_dma_addr;
941 int req_offset;
942 u16 req_idx; /* Request index */
943
944 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530945 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530946 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
947 req_idx = req_offset / ioc->req_sz;
948 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
949 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
950
951 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
952
953 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
954 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
955 ioc->name, mf_dma_addr, req_idx));
956 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
960/**
961 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 * @ioc: Pointer to MPT adapter structure
963 * @mf: Pointer to MPT request frame
964 *
965 * This routine places a MPT request frame back on the MPT adapter's
966 * FreeQ.
967 */
968void
969mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
970{
971 unsigned long flags;
972
973 /* Put Request back on FreeQ! */
974 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200975 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
977#ifdef MFCNT
978 ioc->mfcnt--;
979#endif
980 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
981}
982
983/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
984/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530985 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 * @pAddr: virtual address for SGE
987 * @flagslength: SGE flags and data transfer length
988 * @dma_addr: Physical address
989 *
990 * This routine places a MPT request frame back on the MPT adapter's
991 * FreeQ.
992 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530993static void
994mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530996 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
997 pSge->FlagsLength = cpu_to_le32(flagslength);
998 pSge->Address = cpu_to_le32(dma_addr);
999}
1000
1001/**
1002 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1003 * @pAddr: virtual address for SGE
1004 * @flagslength: SGE flags and data transfer length
1005 * @dma_addr: Physical address
1006 *
1007 * This routine places a MPT request frame back on the MPT adapter's
1008 * FreeQ.
1009 **/
1010static void
1011mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1012{
1013 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1014 pSge->Address.Low = cpu_to_le32
1015 (lower_32_bits((unsigned long)(dma_addr)));
1016 pSge->Address.High = cpu_to_le32
1017 (upper_32_bits((unsigned long)dma_addr));
1018 pSge->FlagsLength = cpu_to_le32
1019 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1020}
1021
1022/**
1023 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
1024 * (1078 workaround).
1025 * @pAddr: virtual address for SGE
1026 * @flagslength: SGE flags and data transfer length
1027 * @dma_addr: Physical address
1028 *
1029 * This routine places a MPT request frame back on the MPT adapter's
1030 * FreeQ.
1031 **/
1032static void
1033mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1034{
1035 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1036 u32 tmp;
1037
1038 pSge->Address.Low = cpu_to_le32
1039 (lower_32_bits((unsigned long)(dma_addr)));
1040 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1041
1042 /*
1043 * 1078 errata workaround for the 36GB limitation
1044 */
1045 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1046 flagslength |=
1047 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1048 tmp |= (1<<31);
1049 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1050 printk(KERN_DEBUG "1078 P0M2 addressing for "
1051 "addr = 0x%llx len = %d\n",
1052 (unsigned long long)dma_addr,
1053 MPI_SGE_LENGTH(flagslength));
1054 }
1055
1056 pSge->Address.High = cpu_to_le32(tmp);
1057 pSge->FlagsLength = cpu_to_le32(
1058 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1059}
1060
1061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1062/**
1063 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1064 * @pAddr: virtual address for SGE
1065 * @next: nextChainOffset value (u32's)
1066 * @length: length of next SGL segment
1067 * @dma_addr: Physical address
1068 *
1069 */
1070static void
1071mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1072{
1073 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1074 pChain->Length = cpu_to_le16(length);
1075 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1076 pChain->NextChainOffset = next;
1077 pChain->Address = cpu_to_le32(dma_addr);
1078}
1079
1080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1081/**
1082 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1083 * @pAddr: virtual address for SGE
1084 * @next: nextChainOffset value (u32's)
1085 * @length: length of next SGL segment
1086 * @dma_addr: Physical address
1087 *
1088 */
1089static void
1090mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1091{
1092 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 u32 tmp = dma_addr & 0xFFFFFFFF;
1094
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301095 pChain->Length = cpu_to_le16(length);
1096 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1097 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301099 pChain->NextChainOffset = next;
1100
1101 pChain->Address.Low = cpu_to_le32(tmp);
1102 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1103 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
1105
1106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1107/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001108 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301109 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 * @ioc: Pointer to MPT adapter structure
1111 * @reqBytes: Size of the request in bytes
1112 * @req: Pointer to MPT request frame
1113 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1114 *
1115 * This routine is used exclusively to send MptScsiTaskMgmt
1116 * requests since they are required to be sent via doorbell handshake.
1117 *
1118 * NOTE: It is the callers responsibility to byte-swap fields in the
1119 * request which are greater than 1 byte in size.
1120 *
1121 * Returns 0 for success, non-zero for failure.
1122 */
1123int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301124mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125{
Eric Moorecd2c6192007-01-29 09:47:47 -07001126 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 u8 *req_as_bytes;
1128 int ii;
1129
1130 /* State is known to be good upon entering
1131 * this function so issue the bus reset
1132 * request.
1133 */
1134
1135 /*
1136 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1137 * setting cb_idx/req_idx. But ONLY if this request
1138 * is in proper (pre-alloc'd) request buffer range...
1139 */
1140 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1141 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1142 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1143 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301144 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 }
1146
1147 /* Make sure there are no doorbells */
1148 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1151 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1152 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1153
1154 /* Wait for IOC doorbell int */
1155 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1156 return ii;
1157 }
1158
1159 /* Read doorbell and check for active bit */
1160 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1161 return -5;
1162
Eric Moore29dd3602007-09-14 18:46:51 -06001163 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001164 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1167
1168 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1169 return -2;
1170 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001171
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 /* Send request via doorbell handshake */
1173 req_as_bytes = (u8 *) req;
1174 for (ii = 0; ii < reqBytes/4; ii++) {
1175 u32 word;
1176
1177 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1178 (req_as_bytes[(ii*4) + 1] << 8) |
1179 (req_as_bytes[(ii*4) + 2] << 16) |
1180 (req_as_bytes[(ii*4) + 3] << 24));
1181 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1182 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1183 r = -3;
1184 break;
1185 }
1186 }
1187
1188 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1189 r = 0;
1190 else
1191 r = -4;
1192
1193 /* Make sure there are no doorbells */
1194 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 return r;
1197}
1198
1199/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1200/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001201 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001202 * @ioc: Pointer to MPT adapter structure
1203 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001204 * @sleepFlag: Specifies whether the process can sleep
1205 *
1206 * Provides mechanism for the host driver to control the IOC's
1207 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001208 *
1209 * Access Control Value - bits[15:12]
1210 * 0h Reserved
1211 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1212 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1213 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1214 *
1215 * Returns 0 for success, non-zero for failure.
1216 */
1217
1218static int
1219mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1220{
1221 int r = 0;
1222
1223 /* return if in use */
1224 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1225 & MPI_DOORBELL_ACTIVE)
1226 return -1;
1227
1228 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1229
1230 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1231 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1232 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1233 (access_control_value<<12)));
1234
1235 /* Wait for IOC to clear Doorbell Status bit */
1236 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1237 return -2;
1238 }else
1239 return 0;
1240}
1241
1242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1243/**
1244 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001245 * @ioc: Pointer to pointer to IOC adapter
1246 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001247 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001248 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001249 * Returns 0 for success, non-zero for failure.
1250 */
1251static int
1252mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1253{
1254 char *psge;
1255 int flags_length;
1256 u32 host_page_buffer_sz=0;
1257
1258 if(!ioc->HostPageBuffer) {
1259
1260 host_page_buffer_sz =
1261 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1262
1263 if(!host_page_buffer_sz)
1264 return 0; /* fw doesn't need any host buffers */
1265
1266 /* spin till we get enough memory */
1267 while(host_page_buffer_sz > 0) {
1268
1269 if((ioc->HostPageBuffer = pci_alloc_consistent(
1270 ioc->pcidev,
1271 host_page_buffer_sz,
1272 &ioc->HostPageBuffer_dma)) != NULL) {
1273
Prakash, Sathya436ace72007-07-24 15:42:08 +05301274 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001275 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001276 ioc->name, ioc->HostPageBuffer,
1277 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001278 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001279 ioc->alloc_total += host_page_buffer_sz;
1280 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1281 break;
1282 }
1283
1284 host_page_buffer_sz -= (4*1024);
1285 }
1286 }
1287
1288 if(!ioc->HostPageBuffer) {
1289 printk(MYIOC_s_ERR_FMT
1290 "Failed to alloc memory for host_page_buffer!\n",
1291 ioc->name);
1292 return -999;
1293 }
1294
1295 psge = (char *)&ioc_init->HostPageBufferSGE;
1296 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1297 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1298 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1299 MPI_SGE_FLAGS_HOST_TO_IOC |
1300 MPI_SGE_FLAGS_END_OF_BUFFER;
1301 if (sizeof(dma_addr_t) == sizeof(u64)) {
1302 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1303 }
1304 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1305 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301306 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001307 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1308
1309return 0;
1310}
1311
1312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1313/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001314 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 * @iocid: IOC unique identifier (integer)
1316 * @iocpp: Pointer to pointer to IOC adapter
1317 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001318 * Given a unique IOC identifier, set pointer to the associated MPT
1319 * adapter structure.
1320 *
1321 * Returns iocid and sets iocpp if iocid is found.
1322 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 */
1324int
1325mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1326{
1327 MPT_ADAPTER *ioc;
1328
1329 list_for_each_entry(ioc,&ioc_list,list) {
1330 if (ioc->id == iocid) {
1331 *iocpp =ioc;
1332 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 *iocpp = NULL;
1337 return -1;
1338}
1339
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301340/**
1341 * mpt_get_product_name - returns product string
1342 * @vendor: pci vendor id
1343 * @device: pci device id
1344 * @revision: pci revision id
1345 * @prod_name: string returned
1346 *
1347 * Returns product string displayed when driver loads,
1348 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1349 *
1350 **/
1351static void
1352mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1353{
1354 char *product_str = NULL;
1355
1356 if (vendor == PCI_VENDOR_ID_BROCADE) {
1357 switch (device)
1358 {
1359 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1360 switch (revision)
1361 {
1362 case 0x00:
1363 product_str = "BRE040 A0";
1364 break;
1365 case 0x01:
1366 product_str = "BRE040 A1";
1367 break;
1368 default:
1369 product_str = "BRE040";
1370 break;
1371 }
1372 break;
1373 }
1374 goto out;
1375 }
1376
1377 switch (device)
1378 {
1379 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1380 product_str = "LSIFC909 B1";
1381 break;
1382 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1383 product_str = "LSIFC919 B0";
1384 break;
1385 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1386 product_str = "LSIFC929 B0";
1387 break;
1388 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1389 if (revision < 0x80)
1390 product_str = "LSIFC919X A0";
1391 else
1392 product_str = "LSIFC919XL A1";
1393 break;
1394 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1395 if (revision < 0x80)
1396 product_str = "LSIFC929X A0";
1397 else
1398 product_str = "LSIFC929XL A1";
1399 break;
1400 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1401 product_str = "LSIFC939X A1";
1402 break;
1403 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1404 product_str = "LSIFC949X A1";
1405 break;
1406 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1407 switch (revision)
1408 {
1409 case 0x00:
1410 product_str = "LSIFC949E A0";
1411 break;
1412 case 0x01:
1413 product_str = "LSIFC949E A1";
1414 break;
1415 default:
1416 product_str = "LSIFC949E";
1417 break;
1418 }
1419 break;
1420 case MPI_MANUFACTPAGE_DEVID_53C1030:
1421 switch (revision)
1422 {
1423 case 0x00:
1424 product_str = "LSI53C1030 A0";
1425 break;
1426 case 0x01:
1427 product_str = "LSI53C1030 B0";
1428 break;
1429 case 0x03:
1430 product_str = "LSI53C1030 B1";
1431 break;
1432 case 0x07:
1433 product_str = "LSI53C1030 B2";
1434 break;
1435 case 0x08:
1436 product_str = "LSI53C1030 C0";
1437 break;
1438 case 0x80:
1439 product_str = "LSI53C1030T A0";
1440 break;
1441 case 0x83:
1442 product_str = "LSI53C1030T A2";
1443 break;
1444 case 0x87:
1445 product_str = "LSI53C1030T A3";
1446 break;
1447 case 0xc1:
1448 product_str = "LSI53C1020A A1";
1449 break;
1450 default:
1451 product_str = "LSI53C1030";
1452 break;
1453 }
1454 break;
1455 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1456 switch (revision)
1457 {
1458 case 0x03:
1459 product_str = "LSI53C1035 A2";
1460 break;
1461 case 0x04:
1462 product_str = "LSI53C1035 B0";
1463 break;
1464 default:
1465 product_str = "LSI53C1035";
1466 break;
1467 }
1468 break;
1469 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1470 switch (revision)
1471 {
1472 case 0x00:
1473 product_str = "LSISAS1064 A1";
1474 break;
1475 case 0x01:
1476 product_str = "LSISAS1064 A2";
1477 break;
1478 case 0x02:
1479 product_str = "LSISAS1064 A3";
1480 break;
1481 case 0x03:
1482 product_str = "LSISAS1064 A4";
1483 break;
1484 default:
1485 product_str = "LSISAS1064";
1486 break;
1487 }
1488 break;
1489 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1490 switch (revision)
1491 {
1492 case 0x00:
1493 product_str = "LSISAS1064E A0";
1494 break;
1495 case 0x01:
1496 product_str = "LSISAS1064E B0";
1497 break;
1498 case 0x02:
1499 product_str = "LSISAS1064E B1";
1500 break;
1501 case 0x04:
1502 product_str = "LSISAS1064E B2";
1503 break;
1504 case 0x08:
1505 product_str = "LSISAS1064E B3";
1506 break;
1507 default:
1508 product_str = "LSISAS1064E";
1509 break;
1510 }
1511 break;
1512 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1513 switch (revision)
1514 {
1515 case 0x00:
1516 product_str = "LSISAS1068 A0";
1517 break;
1518 case 0x01:
1519 product_str = "LSISAS1068 B0";
1520 break;
1521 case 0x02:
1522 product_str = "LSISAS1068 B1";
1523 break;
1524 default:
1525 product_str = "LSISAS1068";
1526 break;
1527 }
1528 break;
1529 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1530 switch (revision)
1531 {
1532 case 0x00:
1533 product_str = "LSISAS1068E A0";
1534 break;
1535 case 0x01:
1536 product_str = "LSISAS1068E B0";
1537 break;
1538 case 0x02:
1539 product_str = "LSISAS1068E B1";
1540 break;
1541 case 0x04:
1542 product_str = "LSISAS1068E B2";
1543 break;
1544 case 0x08:
1545 product_str = "LSISAS1068E B3";
1546 break;
1547 default:
1548 product_str = "LSISAS1068E";
1549 break;
1550 }
1551 break;
1552 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1553 switch (revision)
1554 {
1555 case 0x00:
1556 product_str = "LSISAS1078 A0";
1557 break;
1558 case 0x01:
1559 product_str = "LSISAS1078 B0";
1560 break;
1561 case 0x02:
1562 product_str = "LSISAS1078 C0";
1563 break;
1564 case 0x03:
1565 product_str = "LSISAS1078 C1";
1566 break;
1567 case 0x04:
1568 product_str = "LSISAS1078 C2";
1569 break;
1570 default:
1571 product_str = "LSISAS1078";
1572 break;
1573 }
1574 break;
1575 }
1576
1577 out:
1578 if (product_str)
1579 sprintf(prod_name, "%s", product_str);
1580}
1581
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301582/**
1583 * mpt_mapresources - map in memory mapped io
1584 * @ioc: Pointer to pointer to IOC adapter
1585 *
1586 **/
1587static int
1588mpt_mapresources(MPT_ADAPTER *ioc)
1589{
1590 u8 __iomem *mem;
1591 int ii;
1592 unsigned long mem_phys;
1593 unsigned long port;
1594 u32 msize;
1595 u32 psize;
1596 u8 revision;
1597 int r = -ENODEV;
1598 struct pci_dev *pdev;
1599
1600 pdev = ioc->pcidev;
1601 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1602 if (pci_enable_device_mem(pdev)) {
1603 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1604 "failed\n", ioc->name);
1605 return r;
1606 }
1607 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1608 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1609 "MEM failed\n", ioc->name);
1610 return r;
1611 }
1612
1613 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1614
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301615 if (sizeof(dma_addr_t) > 4) {
1616 const uint64_t required_mask = dma_get_required_mask
1617 (&pdev->dev);
1618 if (required_mask > DMA_BIT_MASK(32)
1619 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1620 && !pci_set_consistent_dma_mask(pdev,
1621 DMA_BIT_MASK(64))) {
1622 ioc->dma_mask = DMA_BIT_MASK(64);
1623 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1624 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1625 ioc->name));
1626 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1627 && !pci_set_consistent_dma_mask(pdev,
1628 DMA_BIT_MASK(32))) {
1629 ioc->dma_mask = DMA_BIT_MASK(32);
1630 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1631 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1632 ioc->name));
1633 } else {
1634 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1635 ioc->name, pci_name(pdev));
1636 return r;
1637 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301638 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301639 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1640 && !pci_set_consistent_dma_mask(pdev,
1641 DMA_BIT_MASK(32))) {
1642 ioc->dma_mask = DMA_BIT_MASK(32);
1643 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1644 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1645 ioc->name));
1646 } else {
1647 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1648 ioc->name, pci_name(pdev));
1649 return r;
1650 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301651 }
1652
1653 mem_phys = msize = 0;
1654 port = psize = 0;
1655 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1656 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1657 if (psize)
1658 continue;
1659 /* Get I/O space! */
1660 port = pci_resource_start(pdev, ii);
1661 psize = pci_resource_len(pdev, ii);
1662 } else {
1663 if (msize)
1664 continue;
1665 /* Get memmap */
1666 mem_phys = pci_resource_start(pdev, ii);
1667 msize = pci_resource_len(pdev, ii);
1668 }
1669 }
1670 ioc->mem_size = msize;
1671
1672 mem = NULL;
1673 /* Get logical ptr for PciMem0 space */
1674 /*mem = ioremap(mem_phys, msize);*/
1675 mem = ioremap(mem_phys, msize);
1676 if (mem == NULL) {
1677 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1678 " memory!\n", ioc->name);
1679 return -EINVAL;
1680 }
1681 ioc->memmap = mem;
1682 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1683 ioc->name, mem, mem_phys));
1684
1685 ioc->mem_phys = mem_phys;
1686 ioc->chip = (SYSIF_REGS __iomem *)mem;
1687
1688 /* Save Port IO values in case we need to do downloadboot */
1689 ioc->pio_mem_phys = port;
1690 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1691
1692 return 0;
1693}
1694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001696/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001697 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001699 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 *
1701 * This routine performs all the steps necessary to bring the IOC of
1702 * a MPT adapter to a OPERATIONAL state. This includes registering
1703 * memory regions, registering the interrupt, and allocating request
1704 * and reply memory pools.
1705 *
1706 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1707 * MPT adapter.
1708 *
1709 * Returns 0 for success, non-zero for failure.
1710 *
1711 * TODO: Add support for polled controllers
1712 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001713int
1714mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
1716 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301717 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 u8 revision;
1720 u8 pcixcmd;
1721 static int mpt_ids = 0;
1722#ifdef CONFIG_PROC_FS
1723 struct proc_dir_entry *dent, *ent;
1724#endif
1725
Jesper Juhl56876192007-08-10 14:50:51 -07001726 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1727 if (ioc == NULL) {
1728 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1729 return -ENOMEM;
1730 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301731
Eric Moore29dd3602007-09-14 18:46:51 -06001732 ioc->id = mpt_ids++;
1733 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001734
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301735 /*
1736 * set initial debug level
1737 * (refer to mptdebug.h)
1738 *
1739 */
1740 ioc->debug_level = mpt_debug_level;
1741 if (mpt_debug_level)
1742 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301743
Eric Moore29dd3602007-09-14 18:46:51 -06001744 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001745
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301746 ioc->pcidev = pdev;
1747 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001748 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 return r;
1750 }
1751
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301752 /*
1753 * Setting up proper handlers for scatter gather handling
1754 */
1755 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1756 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1757 ioc->add_sge = &mpt_add_sge_64bit_1078;
1758 else
1759 ioc->add_sge = &mpt_add_sge_64bit;
1760 ioc->add_chain = &mpt_add_chain_64bit;
1761 ioc->sg_addr_size = 8;
1762 } else {
1763 ioc->add_sge = &mpt_add_sge;
1764 ioc->add_chain = &mpt_add_chain;
1765 ioc->sg_addr_size = 4;
1766 }
1767 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 ioc->alloc_total = sizeof(MPT_ADAPTER);
1770 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1771 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 ioc->pcidev = pdev;
1774 ioc->diagPending = 0;
1775 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001776 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301778 mutex_init(&ioc->mptbase_cmds.mutex);
1779 init_completion(&ioc->mptbase_cmds.done);
1780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 /* Initialize the event logging.
1782 */
1783 ioc->eventTypes = 0; /* None */
1784 ioc->eventContext = 0;
1785 ioc->eventLogSize = 0;
1786 ioc->events = NULL;
1787
1788#ifdef MFCNT
1789 ioc->mfcnt = 0;
1790#endif
1791
1792 ioc->cached_fw = NULL;
1793
1794 /* Initilize SCSI Config Data structure
1795 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001796 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
Michael Reed05e8ec12006-01-13 14:31:54 -06001798 /* Initialize the fc rport list head.
1799 */
1800 INIT_LIST_HEAD(&ioc->fc_rports);
1801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 /* Find lookup slot. */
1803 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001804
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301805
1806 /* Initialize workqueue */
1807 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1808 spin_lock_init(&ioc->fault_reset_work_lock);
1809
Kay Sieversaab0de22008-05-02 06:02:41 +02001810 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1811 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301812 ioc->reset_work_q =
1813 create_singlethread_workqueue(ioc->reset_work_q_name);
1814 if (!ioc->reset_work_q) {
1815 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1816 ioc->name);
1817 pci_release_selected_regions(pdev, ioc->bars);
1818 kfree(ioc);
1819 return -ENOMEM;
1820 }
1821
Eric Moore29dd3602007-09-14 18:46:51 -06001822 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1823 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301825 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1826 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1827
1828 switch (pdev->device)
1829 {
1830 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1831 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1832 ioc->errata_flag_1064 = 1;
1833 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1834 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1835 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1836 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301838 break;
1839
1840 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 /* 929X Chip Fix. Set Split transactions level
1843 * for PCIX. Set MOST bits to zero.
1844 */
1845 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1846 pcixcmd &= 0x8F;
1847 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1848 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 /* 929XL Chip Fix. Set MMRBC to 0x08.
1850 */
1851 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1852 pcixcmd |= 0x08;
1853 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301856 break;
1857
1858 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 /* 919X Chip Fix. Set Split transactions level
1860 * for PCIX. Set MOST bits to zero.
1861 */
1862 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1863 pcixcmd &= 0x8F;
1864 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001865 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301866 break;
1867
1868 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 /* 1030 Chip Fix. Disable Split transactions
1870 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1871 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 if (revision < C0_1030) {
1873 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1874 pcixcmd &= 0x8F;
1875 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1876 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301877
1878 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001879 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301880 break;
1881
1882 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1883 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001884 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301885
1886 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1887 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1888 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001889 ioc->bus_type = SAS;
1890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301892
Kashyap, Desaie3829682009-01-08 14:27:16 +05301893 switch (ioc->bus_type) {
1894
1895 case SAS:
1896 ioc->msi_enable = mpt_msi_enable_sas;
1897 break;
1898
1899 case SPI:
1900 ioc->msi_enable = mpt_msi_enable_spi;
1901 break;
1902
1903 case FC:
1904 ioc->msi_enable = mpt_msi_enable_fc;
1905 break;
1906
1907 default:
1908 ioc->msi_enable = 0;
1909 break;
1910 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001911 if (ioc->errata_flag_1064)
1912 pci_disable_io_access(pdev);
1913
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 spin_lock_init(&ioc->FreeQlock);
1915
1916 /* Disable all! */
1917 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1918 ioc->active = 0;
1919 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1920
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301921 /* Set IOC ptr in the pcidev's driver data. */
1922 pci_set_drvdata(ioc->pcidev, ioc);
1923
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 /* Set lookup ptr. */
1925 list_add_tail(&ioc->list, &ioc_list);
1926
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001927 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 */
1929 mpt_detect_bound_ports(ioc, pdev);
1930
James Bottomleyc92f2222006-03-01 09:02:49 -06001931 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1932 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001933 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1934 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001937 if (ioc->alt_ioc)
1938 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301939 iounmap(ioc->memmap);
1940 if (r != -5)
1941 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301942
1943 destroy_workqueue(ioc->reset_work_q);
1944 ioc->reset_work_q = NULL;
1945
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 kfree(ioc);
1947 pci_set_drvdata(pdev, NULL);
1948 return r;
1949 }
1950
1951 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001952 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301953 if(MptDeviceDriverHandlers[cb_idx] &&
1954 MptDeviceDriverHandlers[cb_idx]->probe) {
1955 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 }
1957 }
1958
1959#ifdef CONFIG_PROC_FS
1960 /*
1961 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1962 */
1963 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1964 if (dent) {
1965 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1966 if (ent) {
1967 ent->read_proc = procmpt_iocinfo_read;
1968 ent->data = ioc;
1969 }
1970 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1971 if (ent) {
1972 ent->read_proc = procmpt_summary_read;
1973 ent->data = ioc;
1974 }
1975 }
1976#endif
1977
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301978 if (!ioc->alt_ioc)
1979 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1980 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 return 0;
1983}
1984
1985/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001986/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001987 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 */
1990
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001991void
1992mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993{
1994 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1995 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301996 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301997 unsigned long flags;
1998 struct workqueue_struct *wq;
1999
2000 /*
2001 * Stop polling ioc for fault condition
2002 */
2003 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
2004 wq = ioc->reset_work_q;
2005 ioc->reset_work_q = NULL;
2006 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
2007 cancel_delayed_work(&ioc->fault_reset_work);
2008 destroy_workqueue(wq);
2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
2011 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2012 remove_proc_entry(pname, NULL);
2013 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2014 remove_proc_entry(pname, NULL);
2015 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2016 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002017
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002019 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302020 if(MptDeviceDriverHandlers[cb_idx] &&
2021 MptDeviceDriverHandlers[cb_idx]->remove) {
2022 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 }
2024 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002025
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 /* Disable interrupts! */
2027 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2028
2029 ioc->active = 0;
2030 synchronize_irq(pdev->irq);
2031
2032 /* Clear any lingering interrupt */
2033 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2034
2035 CHIPREG_READ32(&ioc->chip->IntStatus);
2036
2037 mpt_adapter_dispose(ioc);
2038
2039 pci_set_drvdata(pdev, NULL);
2040}
2041
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042/**************************************************************************
2043 * Power Management
2044 */
2045#ifdef CONFIG_PM
2046/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002047/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002048 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002049 * @pdev: Pointer to pci_dev structure
2050 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002052int
2053mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054{
2055 u32 device_state;
2056 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302058 device_state = pci_choose_state(pdev, state);
2059 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2060 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2061 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
2063 /* put ioc into READY_STATE */
2064 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2065 printk(MYIOC_s_ERR_FMT
2066 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2067 }
2068
2069 /* disable interrupts */
2070 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2071 ioc->active = 0;
2072
2073 /* Clear any lingering interrupt */
2074 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2075
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302076 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002077 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302078 pci_disable_msi(ioc->pcidev);
2079 ioc->pci_irq = -1;
2080 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302082 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 return 0;
2085}
2086
2087/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002088/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002089 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002090 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002092int
2093mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094{
2095 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2096 u32 device_state = pdev->current_state;
2097 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302098 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002099
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302100 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2101 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2102 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302104 pci_set_power_state(pdev, PCI_D0);
2105 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302107 ioc->pcidev = pdev;
2108 err = mpt_mapresources(ioc);
2109 if (err)
2110 return err;
2111
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302112 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2113 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2114 ioc->add_sge = &mpt_add_sge_64bit_1078;
2115 else
2116 ioc->add_sge = &mpt_add_sge_64bit;
2117 ioc->add_chain = &mpt_add_chain_64bit;
2118 ioc->sg_addr_size = 8;
2119 } else {
2120
2121 ioc->add_sge = &mpt_add_sge;
2122 ioc->add_chain = &mpt_add_chain;
2123 ioc->sg_addr_size = 4;
2124 }
2125 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2126
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302127 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2128 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2129 CHIPREG_READ32(&ioc->chip->Doorbell));
2130
2131 /*
2132 * Errata workaround for SAS pci express:
2133 * Upon returning to the D0 state, the contents of the doorbell will be
2134 * stale data, and this will incorrectly signal to the host driver that
2135 * the firmware is ready to process mpt commands. The workaround is
2136 * to issue a diagnostic reset.
2137 */
2138 if (ioc->bus_type == SAS && (pdev->device ==
2139 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2140 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2141 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2142 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2143 ioc->name);
2144 goto out;
2145 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147
2148 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302149 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2150 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2151 CAN_SLEEP);
2152 if (recovery_state != 0)
2153 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2154 "error:[%x]\n", ioc->name, recovery_state);
2155 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302157 "pci-resume: success\n", ioc->name);
2158 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302160
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161}
2162#endif
2163
James Bottomley4ff42a62006-05-17 18:06:52 -05002164static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302165mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002166{
2167 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2168 ioc->bus_type != SPI) ||
2169 (MptDriverClass[index] == MPTFC_DRIVER &&
2170 ioc->bus_type != FC) ||
2171 (MptDriverClass[index] == MPTSAS_DRIVER &&
2172 ioc->bus_type != SAS))
2173 /* make sure we only call the relevant reset handler
2174 * for the bus */
2175 return 0;
2176 return (MptResetHandlers[index])(ioc, reset_phase);
2177}
2178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002180/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2182 * @ioc: Pointer to MPT adapter structure
2183 * @reason: Event word / reason
2184 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2185 *
2186 * This routine performs all the steps necessary to bring the IOC
2187 * to a OPERATIONAL state.
2188 *
2189 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2190 * MPT adapter.
2191 *
2192 * Returns:
2193 * 0 for success
2194 * -1 if failed to get board READY
2195 * -2 if READY but IOCFacts Failed
2196 * -3 if READY but PrimeIOCFifos Failed
2197 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302198 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302199 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 */
2201static int
2202mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2203{
2204 int hard_reset_done = 0;
2205 int alt_ioc_ready = 0;
2206 int hard;
2207 int rc=0;
2208 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302209 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 int handlers;
2211 int ret = 0;
2212 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002213 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302214 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
Eric Moore29dd3602007-09-14 18:46:51 -06002216 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2217 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
2219 /* Disable reply interrupts (also blocks FreeQ) */
2220 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2221 ioc->active = 0;
2222
2223 if (ioc->alt_ioc) {
2224 if (ioc->alt_ioc->active)
2225 reset_alt_ioc_active = 1;
2226
2227 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2228 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2229 ioc->alt_ioc->active = 0;
2230 }
2231
2232 hard = 1;
2233 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2234 hard = 0;
2235
2236 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2237 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002238 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2239 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
2241 if (reset_alt_ioc_active && ioc->alt_ioc) {
2242 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002243 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2244 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002245 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 ioc->alt_ioc->active = 1;
2247 }
2248
2249 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002250 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 }
2252 return -1;
2253 }
2254
2255 /* hard_reset_done = 0 if a soft reset was performed
2256 * and 1 if a hard reset was performed.
2257 */
2258 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2259 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2260 alt_ioc_ready = 1;
2261 else
Eric Moore29dd3602007-09-14 18:46:51 -06002262 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 }
2264
2265 for (ii=0; ii<5; ii++) {
2266 /* Get IOC facts! Allow 5 retries */
2267 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2268 break;
2269 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002270
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271
2272 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002273 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2274 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 ret = -2;
2276 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2277 MptDisplayIocCapabilities(ioc);
2278 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002279
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 if (alt_ioc_ready) {
2281 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302282 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002283 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 /* Retry - alt IOC was initialized once
2285 */
2286 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2287 }
2288 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302289 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002290 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 alt_ioc_ready = 0;
2292 reset_alt_ioc_active = 0;
2293 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2294 MptDisplayIocCapabilities(ioc->alt_ioc);
2295 }
2296 }
2297
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302298 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2299 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2300 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2301 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2302 IORESOURCE_IO);
2303 if (pci_enable_device(ioc->pcidev))
2304 return -5;
2305 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2306 "mpt"))
2307 return -5;
2308 }
2309
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002310 /*
2311 * Device is reset now. It must have de-asserted the interrupt line
2312 * (if it was asserted) and it should be safe to register for the
2313 * interrupt now.
2314 */
2315 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2316 ioc->pci_irq = -1;
2317 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302318 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002319 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002320 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302321 else
2322 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002323 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002324 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002325 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002326 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002327 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302328 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002329 pci_disable_msi(ioc->pcidev);
2330 return -EBUSY;
2331 }
2332 irq_allocated = 1;
2333 ioc->pci_irq = ioc->pcidev->irq;
2334 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002335 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2336 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002337 }
2338 }
2339
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 /* Prime reply & request queues!
2341 * (mucho alloc's) Must be done prior to
2342 * init as upper addresses are needed for init.
2343 * If fails, continue with alt-ioc processing
2344 */
2345 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2346 ret = -3;
2347
2348 /* May need to check/upload firmware & data here!
2349 * If fails, continue with alt-ioc processing
2350 */
2351 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2352 ret = -4;
2353// NEW!
2354 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002355 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2356 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 alt_ioc_ready = 0;
2358 reset_alt_ioc_active = 0;
2359 }
2360
2361 if (alt_ioc_ready) {
2362 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2363 alt_ioc_ready = 0;
2364 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002365 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2366 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 }
2368 }
2369
2370 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2371 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302372 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002373 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
2375 /* Controller is not operational, cannot do upload
2376 */
2377 if (ret == 0) {
2378 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002379 if (rc == 0) {
2380 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2381 /*
2382 * Maintain only one pointer to FW memory
2383 * so there will not be two attempt to
2384 * downloadboot onboard dual function
2385 * chips (mpt_adapter_disable,
2386 * mpt_diag_reset)
2387 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302388 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002389 "mpt_upload: alt_%s has cached_fw=%p \n",
2390 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302391 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002392 }
2393 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002394 printk(MYIOC_s_WARN_FMT
2395 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302396 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 }
2399 }
2400 }
2401
Kashyap, Desaifd761752009-05-29 16:39:06 +05302402 /* Enable MPT base driver management of EventNotification
2403 * and EventAck handling.
2404 */
2405 if ((ret == 0) && (!ioc->facts.EventState)) {
2406 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2407 "SendEventNotification\n",
2408 ioc->name));
2409 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2410 }
2411
2412 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2413 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2414
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 if (ret == 0) {
2416 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002417 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 ioc->active = 1;
2419 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302420 if (rc == 0) { /* alt ioc */
2421 if (reset_alt_ioc_active && ioc->alt_ioc) {
2422 /* (re)Enable alt-IOC! (reply interrupt) */
2423 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2424 "reply irq re-enabled\n",
2425 ioc->alt_ioc->name));
2426 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2427 MPI_HIM_DIM);
2428 ioc->alt_ioc->active = 1;
2429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 }
2431
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002433 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2435 * recursive scenario; GetLanConfigPages times out, timer expired
2436 * routine calls HardResetHandler, which calls into here again,
2437 * and we try GetLanConfigPages again...
2438 */
2439 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002440
2441 /*
2442 * Initalize link list for inactive raid volumes.
2443 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002444 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002445 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2446
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002447 if (ioc->bus_type == SAS) {
2448
2449 /* clear persistency table */
2450 if(ioc->facts.IOCExceptions &
2451 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2452 ret = mptbase_sas_persist_operation(ioc,
2453 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2454 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002455 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002456 }
2457
2458 /* Find IM volumes
2459 */
2460 mpt_findImVolumes(ioc);
2461
2462 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2464 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2465 /*
2466 * Pre-fetch the ports LAN MAC address!
2467 * (LANPage1_t stuff)
2468 */
2469 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302470 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2471 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002472 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2473 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302474
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 }
2476 } else {
2477 /* Get NVRAM and adapter maximums from SPP 0 and 2
2478 */
2479 mpt_GetScsiPortSettings(ioc, 0);
2480
2481 /* Get version and length of SDP 1
2482 */
2483 mpt_readScsiDevicePageHeaders(ioc, 0);
2484
2485 /* Find IM volumes
2486 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002487 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 mpt_findImVolumes(ioc);
2489
2490 /* Check, and possibly reset, the coalescing value
2491 */
2492 mpt_read_ioc_pg_1(ioc);
2493
2494 mpt_read_ioc_pg_4(ioc);
2495 }
2496
2497 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302498 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 }
2500
2501 /*
2502 * Call each currently registered protocol IOC reset handler
2503 * with post-reset indication.
2504 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2505 * MptResetHandlers[] registered yet.
2506 */
2507 if (hard_reset_done) {
2508 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302509 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2510 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302511 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002512 "Calling IOC post_reset handler #%d\n",
2513 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302514 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 handlers++;
2516 }
2517
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302518 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302519 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002520 "Calling IOC post_reset handler #%d\n",
2521 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302522 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 handlers++;
2524 }
2525 }
2526 /* FIXME? Examine results here? */
2527 }
2528
Eric Moore0ccdb002006-07-11 17:33:13 -06002529 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002530 if ((ret != 0) && irq_allocated) {
2531 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302532 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002533 pci_disable_msi(ioc->pcidev);
2534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 return ret;
2536}
2537
2538/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002539/**
2540 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 * @ioc: Pointer to MPT adapter structure
2542 * @pdev: Pointer to (struct pci_dev) structure
2543 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002544 * Search for PCI bus/dev_function which matches
2545 * PCI bus/dev_function (+/-1) for newly discovered 929,
2546 * 929X, 1030 or 1035.
2547 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2549 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2550 */
2551static void
2552mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2553{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002554 struct pci_dev *peer=NULL;
2555 unsigned int slot = PCI_SLOT(pdev->devfn);
2556 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 MPT_ADAPTER *ioc_srch;
2558
Prakash, Sathya436ace72007-07-24 15:42:08 +05302559 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002560 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002561 ioc->name, pci_name(pdev), pdev->bus->number,
2562 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002563
2564 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2565 if (!peer) {
2566 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2567 if (!peer)
2568 return;
2569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570
2571 list_for_each_entry(ioc_srch, &ioc_list, list) {
2572 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002573 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 /* Paranoia checks */
2575 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002576 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002577 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 break;
2579 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002580 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002581 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 break;
2583 }
Eric Moore29dd3602007-09-14 18:46:51 -06002584 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002585 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 ioc_srch->alt_ioc = ioc;
2587 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 }
2589 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002590 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591}
2592
2593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002594/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002596 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 */
2598static void
2599mpt_adapter_disable(MPT_ADAPTER *ioc)
2600{
2601 int sz;
2602 int ret;
2603
2604 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302605 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002606 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302607 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2608 ioc->cached_fw, CAN_SLEEP)) < 0) {
2609 printk(MYIOC_s_WARN_FMT
2610 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002611 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 }
2613 }
2614
2615 /* Disable adapter interrupts! */
2616 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2617 ioc->active = 0;
2618 /* Clear any lingering interrupt */
2619 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2620
2621 if (ioc->alloc != NULL) {
2622 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002623 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2624 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 pci_free_consistent(ioc->pcidev, sz,
2626 ioc->alloc, ioc->alloc_dma);
2627 ioc->reply_frames = NULL;
2628 ioc->req_frames = NULL;
2629 ioc->alloc = NULL;
2630 ioc->alloc_total -= sz;
2631 }
2632
2633 if (ioc->sense_buf_pool != NULL) {
2634 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2635 pci_free_consistent(ioc->pcidev, sz,
2636 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2637 ioc->sense_buf_pool = NULL;
2638 ioc->alloc_total -= sz;
2639 }
2640
2641 if (ioc->events != NULL){
2642 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2643 kfree(ioc->events);
2644 ioc->events = NULL;
2645 ioc->alloc_total -= sz;
2646 }
2647
Prakash, Sathya984621b2008-01-11 14:42:17 +05302648 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002650 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002651 mpt_inactive_raid_list_free(ioc);
2652 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002653 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002654 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002655 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
2657 if (ioc->spi_data.pIocPg4 != NULL) {
2658 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302659 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 ioc->spi_data.pIocPg4,
2661 ioc->spi_data.IocPg4_dma);
2662 ioc->spi_data.pIocPg4 = NULL;
2663 ioc->alloc_total -= sz;
2664 }
2665
2666 if (ioc->ReqToChain != NULL) {
2667 kfree(ioc->ReqToChain);
2668 kfree(ioc->RequestNB);
2669 ioc->ReqToChain = NULL;
2670 }
2671
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002672 kfree(ioc->ChainToChain);
2673 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002674
2675 if (ioc->HostPageBuffer != NULL) {
2676 if((ret = mpt_host_page_access_control(ioc,
2677 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002678 printk(MYIOC_s_ERR_FMT
2679 "host page buffers free failed (%d)!\n",
2680 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002681 }
Eric Moore29dd3602007-09-14 18:46:51 -06002682 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002683 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2684 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002685 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002686 ioc->HostPageBuffer = NULL;
2687 ioc->HostPageBuffer_sz = 0;
2688 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690}
2691
2692/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002693/**
2694 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 * @ioc: Pointer to MPT adapter structure
2696 *
2697 * This routine unregisters h/w resources and frees all alloc'd memory
2698 * associated with a MPT adapter structure.
2699 */
2700static void
2701mpt_adapter_dispose(MPT_ADAPTER *ioc)
2702{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002703 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002705 if (ioc == NULL)
2706 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002708 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002710 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002712 if (ioc->pci_irq != -1) {
2713 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302714 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002715 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002716 ioc->pci_irq = -1;
2717 }
2718
2719 if (ioc->memmap != NULL) {
2720 iounmap(ioc->memmap);
2721 ioc->memmap = NULL;
2722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302724 pci_disable_device(ioc->pcidev);
2725 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2726
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002728 if (ioc->mtrr_reg > 0) {
2729 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002730 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732#endif
2733
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002734 /* Zap the adapter lookup ptr! */
2735 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002737 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002738 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2739 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002740
2741 if (ioc->alt_ioc)
2742 ioc->alt_ioc->alt_ioc = NULL;
2743
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002744 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745}
2746
2747/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002748/**
2749 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 * @ioc: Pointer to MPT adapter structure
2751 */
2752static void
2753MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2754{
2755 int i = 0;
2756
2757 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302758 if (ioc->prod_name)
2759 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 printk("Capabilities={");
2761
2762 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2763 printk("Initiator");
2764 i++;
2765 }
2766
2767 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2768 printk("%sTarget", i ? "," : "");
2769 i++;
2770 }
2771
2772 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2773 printk("%sLAN", i ? "," : "");
2774 i++;
2775 }
2776
2777#if 0
2778 /*
2779 * This would probably evoke more questions than it's worth
2780 */
2781 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2782 printk("%sLogBusAddr", i ? "," : "");
2783 i++;
2784 }
2785#endif
2786
2787 printk("}\n");
2788}
2789
2790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002791/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2793 * @ioc: Pointer to MPT_ADAPTER structure
2794 * @force: Force hard KickStart of IOC
2795 * @sleepFlag: Specifies whether the process can sleep
2796 *
2797 * Returns:
2798 * 1 - DIAG reset and READY
2799 * 0 - READY initially OR soft reset and READY
2800 * -1 - Any failure on KickStart
2801 * -2 - Msg Unit Reset Failed
2802 * -3 - IO Unit Reset Failed
2803 * -4 - IOC owned by a PEER
2804 */
2805static int
2806MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2807{
2808 u32 ioc_state;
2809 int statefault = 0;
2810 int cntdn;
2811 int hard_reset_done = 0;
2812 int r;
2813 int ii;
2814 int whoinit;
2815
2816 /* Get current [raw] IOC state */
2817 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002818 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819
2820 /*
2821 * Check to see if IOC got left/stuck in doorbell handshake
2822 * grip of death. If so, hard reset the IOC.
2823 */
2824 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2825 statefault = 1;
2826 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2827 ioc->name);
2828 }
2829
2830 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002831 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 return 0;
2833
2834 /*
2835 * Check to see if IOC is in FAULT state.
2836 */
2837 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2838 statefault = 2;
2839 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002840 ioc->name);
2841 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2842 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 }
2844
2845 /*
2846 * Hmmm... Did it get left operational?
2847 */
2848 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302849 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 ioc->name));
2851
2852 /* Check WhoInit.
2853 * If PCI Peer, exit.
2854 * Else, if no fault conditions are present, issue a MessageUnitReset
2855 * Else, fall through to KickStart case
2856 */
2857 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002858 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2859 "whoinit 0x%x statefault %d force %d\n",
2860 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 if (whoinit == MPI_WHOINIT_PCI_PEER)
2862 return -4;
2863 else {
2864 if ((statefault == 0 ) && (force == 0)) {
2865 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2866 return 0;
2867 }
2868 statefault = 3;
2869 }
2870 }
2871
2872 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2873 if (hard_reset_done < 0)
2874 return -1;
2875
2876 /*
2877 * Loop here waiting for IOC to come READY.
2878 */
2879 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002880 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881
2882 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2883 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2884 /*
2885 * BIOS or previous driver load left IOC in OP state.
2886 * Reset messaging FIFOs.
2887 */
2888 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2889 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2890 return -2;
2891 }
2892 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2893 /*
2894 * Something is wrong. Try to get IOC back
2895 * to a known state.
2896 */
2897 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2898 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2899 return -3;
2900 }
2901 }
2902
2903 ii++; cntdn--;
2904 if (!cntdn) {
2905 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2906 ioc->name, (int)((ii+5)/HZ));
2907 return -ETIME;
2908 }
2909
2910 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002911 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 } else {
2913 mdelay (1); /* 1 msec delay */
2914 }
2915
2916 }
2917
2918 if (statefault < 3) {
2919 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2920 ioc->name,
2921 statefault==1 ? "stuck handshake" : "IOC FAULT");
2922 }
2923
2924 return hard_reset_done;
2925}
2926
2927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002928/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 * mpt_GetIocState - Get the current state of a MPT adapter.
2930 * @ioc: Pointer to MPT_ADAPTER structure
2931 * @cooked: Request raw or cooked IOC state
2932 *
2933 * Returns all IOC Doorbell register bits if cooked==0, else just the
2934 * Doorbell bits in MPI_IOC_STATE_MASK.
2935 */
2936u32
2937mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2938{
2939 u32 s, sc;
2940
2941 /* Get! */
2942 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 sc = s & MPI_IOC_STATE_MASK;
2944
2945 /* Save! */
2946 ioc->last_state = sc;
2947
2948 return cooked ? sc : s;
2949}
2950
2951/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002952/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 * GetIocFacts - Send IOCFacts request to MPT adapter.
2954 * @ioc: Pointer to MPT_ADAPTER structure
2955 * @sleepFlag: Specifies whether the process can sleep
2956 * @reason: If recovery, only update facts.
2957 *
2958 * Returns 0 for success, non-zero for failure.
2959 */
2960static int
2961GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2962{
2963 IOCFacts_t get_facts;
2964 IOCFactsReply_t *facts;
2965 int r;
2966 int req_sz;
2967 int reply_sz;
2968 int sz;
2969 u32 status, vv;
2970 u8 shiftFactor=1;
2971
2972 /* IOC *must* NOT be in RESET state! */
2973 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002974 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2975 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 return -44;
2977 }
2978
2979 facts = &ioc->facts;
2980
2981 /* Destination (reply area)... */
2982 reply_sz = sizeof(*facts);
2983 memset(facts, 0, reply_sz);
2984
2985 /* Request area (get_facts on the stack right now!) */
2986 req_sz = sizeof(get_facts);
2987 memset(&get_facts, 0, req_sz);
2988
2989 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2990 /* Assert: All other get_facts fields are zero! */
2991
Prakash, Sathya436ace72007-07-24 15:42:08 +05302992 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002993 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 ioc->name, req_sz, reply_sz));
2995
2996 /* No non-zero fields in the get_facts request are greater than
2997 * 1 byte in size, so we can just fire it off as is.
2998 */
2999 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3000 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3001 if (r != 0)
3002 return r;
3003
3004 /*
3005 * Now byte swap (GRRR) the necessary fields before any further
3006 * inspection of reply contents.
3007 *
3008 * But need to do some sanity checks on MsgLength (byte) field
3009 * to make sure we don't zero IOC's req_sz!
3010 */
3011 /* Did we get a valid reply? */
3012 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3013 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3014 /*
3015 * If not been here, done that, save off first WhoInit value
3016 */
3017 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3018 ioc->FirstWhoInit = facts->WhoInit;
3019 }
3020
3021 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3022 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3023 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3024 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3025 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003026 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 /* CHECKME! IOCStatus, IOCLogInfo */
3028
3029 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3030 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3031
3032 /*
3033 * FC f/w version changed between 1.1 and 1.2
3034 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3035 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3036 */
3037 if (facts->MsgVersion < 0x0102) {
3038 /*
3039 * Handle old FC f/w style, convert to new...
3040 */
3041 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3042 facts->FWVersion.Word =
3043 ((oldv<<12) & 0xFF000000) |
3044 ((oldv<<8) & 0x000FFF00);
3045 } else
3046 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3047
3048 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07003049 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3050 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3051 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 facts->CurrentHostMfaHighAddr =
3053 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3054 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3055 facts->CurrentSenseBufferHighAddr =
3056 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3057 facts->CurReplyFrameSize =
3058 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003059 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
3061 /*
3062 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3063 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3064 * to 14 in MPI-1.01.0x.
3065 */
3066 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
3067 facts->MsgVersion > 0x0100) {
3068 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3069 }
3070
3071 sz = facts->FWImageSize;
3072 if ( sz & 0x01 )
3073 sz += 1;
3074 if ( sz & 0x02 )
3075 sz += 2;
3076 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003077
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 if (!facts->RequestFrameSize) {
3079 /* Something is wrong! */
3080 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3081 ioc->name);
3082 return -55;
3083 }
3084
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003085 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 vv = ((63 / (sz * 4)) + 1) & 0x03;
3087 ioc->NB_for_64_byte_frame = vv;
3088 while ( sz )
3089 {
3090 shiftFactor++;
3091 sz = sz >> 1;
3092 }
3093 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303094 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003095 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3096 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003097
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3099 /*
3100 * Set values for this IOC's request & reply frame sizes,
3101 * and request & reply queue depths...
3102 */
3103 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3104 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3105 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3106 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3107
Prakash, Sathya436ace72007-07-24 15:42:08 +05303108 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303110 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 ioc->name, ioc->req_sz, ioc->req_depth));
3112
3113 /* Get port facts! */
3114 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3115 return r;
3116 }
3117 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003118 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3120 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3121 RequestFrameSize)/sizeof(u32)));
3122 return -66;
3123 }
3124
3125 return 0;
3126}
3127
3128/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003129/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 * GetPortFacts - Send PortFacts request to MPT adapter.
3131 * @ioc: Pointer to MPT_ADAPTER structure
3132 * @portnum: Port number
3133 * @sleepFlag: Specifies whether the process can sleep
3134 *
3135 * Returns 0 for success, non-zero for failure.
3136 */
3137static int
3138GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3139{
3140 PortFacts_t get_pfacts;
3141 PortFactsReply_t *pfacts;
3142 int ii;
3143 int req_sz;
3144 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003145 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
3147 /* IOC *must* NOT be in RESET state! */
3148 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003149 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3150 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 return -4;
3152 }
3153
3154 pfacts = &ioc->pfacts[portnum];
3155
3156 /* Destination (reply area)... */
3157 reply_sz = sizeof(*pfacts);
3158 memset(pfacts, 0, reply_sz);
3159
3160 /* Request area (get_pfacts on the stack right now!) */
3161 req_sz = sizeof(get_pfacts);
3162 memset(&get_pfacts, 0, req_sz);
3163
3164 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3165 get_pfacts.PortNumber = portnum;
3166 /* Assert: All other get_pfacts fields are zero! */
3167
Prakash, Sathya436ace72007-07-24 15:42:08 +05303168 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 ioc->name, portnum));
3170
3171 /* No non-zero fields in the get_pfacts request are greater than
3172 * 1 byte in size, so we can just fire it off as is.
3173 */
3174 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3175 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3176 if (ii != 0)
3177 return ii;
3178
3179 /* Did we get a valid reply? */
3180
3181 /* Now byte swap the necessary fields in the response. */
3182 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3183 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3184 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3185 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3186 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3187 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3188 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3189 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3190 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3191
Eric Moore793955f2007-01-29 09:42:20 -07003192 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3193 pfacts->MaxDevices;
3194 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3195 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3196
3197 /*
3198 * Place all the devices on channels
3199 *
3200 * (for debuging)
3201 */
3202 if (mpt_channel_mapping) {
3203 ioc->devices_per_bus = 1;
3204 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3205 }
3206
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 return 0;
3208}
3209
3210/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003211/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 * SendIocInit - Send IOCInit request to MPT adapter.
3213 * @ioc: Pointer to MPT_ADAPTER structure
3214 * @sleepFlag: Specifies whether the process can sleep
3215 *
3216 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3217 *
3218 * Returns 0 for success, non-zero for failure.
3219 */
3220static int
3221SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3222{
3223 IOCInit_t ioc_init;
3224 MPIDefaultReply_t init_reply;
3225 u32 state;
3226 int r;
3227 int count;
3228 int cntdn;
3229
3230 memset(&ioc_init, 0, sizeof(ioc_init));
3231 memset(&init_reply, 0, sizeof(init_reply));
3232
3233 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3234 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3235
3236 /* If we are in a recovery mode and we uploaded the FW image,
3237 * then this pointer is not NULL. Skip the upload a second time.
3238 * Set this flag if cached_fw set for either IOC.
3239 */
3240 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3241 ioc->upload_fw = 1;
3242 else
3243 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303244 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3246
Eric Moore793955f2007-01-29 09:42:20 -07003247 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3248 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303249 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003250 ioc->name, ioc->facts.MsgVersion));
3251 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3252 // set MsgVersion and HeaderVersion host driver was built with
3253 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3254 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003256 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3257 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3258 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3259 return -99;
3260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3262
3263 if (sizeof(dma_addr_t) == sizeof(u64)) {
3264 /* Save the upper 32-bits of the request
3265 * (reply) and sense buffers.
3266 */
3267 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3268 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3269 } else {
3270 /* Force 32-bit addressing */
3271 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3272 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3273 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003274
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3276 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003277 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3278 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
Prakash, Sathya436ace72007-07-24 15:42:08 +05303280 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 ioc->name, &ioc_init));
3282
3283 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3284 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003285 if (r != 0) {
3286 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289
3290 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003291 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 */
3293
Prakash, Sathya436ace72007-07-24 15:42:08 +05303294 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003296
3297 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3298 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301
3302 /* YIKES! SUPER IMPORTANT!!!
3303 * Poll IocState until _OPERATIONAL while IOC is doing
3304 * LoopInit and TargetDiscovery!
3305 */
3306 count = 0;
3307 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3308 state = mpt_GetIocState(ioc, 1);
3309 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3310 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003311 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 } else {
3313 mdelay(1);
3314 }
3315
3316 if (!cntdn) {
3317 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3318 ioc->name, (int)((count+5)/HZ));
3319 return -9;
3320 }
3321
3322 state = mpt_GetIocState(ioc, 1);
3323 count++;
3324 }
Eric Moore29dd3602007-09-14 18:46:51 -06003325 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 ioc->name, count));
3327
Eric Mooreba856d32006-07-11 17:34:01 -06003328 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 return r;
3330}
3331
3332/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003333/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 * SendPortEnable - Send PortEnable request to MPT adapter port.
3335 * @ioc: Pointer to MPT_ADAPTER structure
3336 * @portnum: Port number to enable
3337 * @sleepFlag: Specifies whether the process can sleep
3338 *
3339 * Send PortEnable to bring IOC to OPERATIONAL state.
3340 *
3341 * Returns 0 for success, non-zero for failure.
3342 */
3343static int
3344SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3345{
3346 PortEnable_t port_enable;
3347 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003348 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 int req_sz;
3350 int reply_sz;
3351
3352 /* Destination... */
3353 reply_sz = sizeof(MPIDefaultReply_t);
3354 memset(&reply_buf, 0, reply_sz);
3355
3356 req_sz = sizeof(PortEnable_t);
3357 memset(&port_enable, 0, req_sz);
3358
3359 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3360 port_enable.PortNumber = portnum;
3361/* port_enable.ChainOffset = 0; */
3362/* port_enable.MsgFlags = 0; */
3363/* port_enable.MsgContext = 0; */
3364
Prakash, Sathya436ace72007-07-24 15:42:08 +05303365 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 ioc->name, portnum, &port_enable));
3367
3368 /* RAID FW may take a long time to enable
3369 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003370 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003371 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3372 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3373 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003374 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003375 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3376 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3377 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003379 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380}
3381
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003382/**
3383 * mpt_alloc_fw_memory - allocate firmware memory
3384 * @ioc: Pointer to MPT_ADAPTER structure
3385 * @size: total FW bytes
3386 *
3387 * If memory has already been allocated, the same (cached) value
3388 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303389 *
3390 * Return 0 if successfull, or non-zero for failure
3391 **/
3392int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3394{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303395 int rc;
3396
3397 if (ioc->cached_fw) {
3398 rc = 0; /* use already allocated memory */
3399 goto out;
3400 }
3401 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3403 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303404 rc = 0;
3405 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303407 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3408 if (!ioc->cached_fw) {
3409 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3410 ioc->name);
3411 rc = -1;
3412 } else {
3413 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3414 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3415 ioc->alloc_total += size;
3416 rc = 0;
3417 }
3418 out:
3419 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303421
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003422/**
3423 * mpt_free_fw_memory - free firmware memory
3424 * @ioc: Pointer to MPT_ADAPTER structure
3425 *
3426 * If alt_img is NULL, delete from ioc structure.
3427 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303428 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429void
3430mpt_free_fw_memory(MPT_ADAPTER *ioc)
3431{
3432 int sz;
3433
Prakash, Sathya984621b2008-01-11 14:42:17 +05303434 if (!ioc->cached_fw)
3435 return;
3436
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303438 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3439 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003440 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303441 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443}
3444
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003446/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3448 * @ioc: Pointer to MPT_ADAPTER structure
3449 * @sleepFlag: Specifies whether the process can sleep
3450 *
3451 * Returns 0 for success, >0 for handshake failure
3452 * <0 for fw upload failure.
3453 *
3454 * Remark: If bound IOC and a successful FWUpload was performed
3455 * on the bound IOC, the second image is discarded
3456 * and memory is free'd. Both channels must upload to prevent
3457 * IOC from running in degraded mode.
3458 */
3459static int
3460mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3461{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 u8 reply[sizeof(FWUploadReply_t)];
3463 FWUpload_t *prequest;
3464 FWUploadReply_t *preply;
3465 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 u32 flagsLength;
3467 int ii, sz, reply_sz;
3468 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303469 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 /* If the image size is 0, we are done.
3471 */
3472 if ((sz = ioc->facts.FWImageSize) == 0)
3473 return 0;
3474
Prakash, Sathya984621b2008-01-11 14:42:17 +05303475 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3476 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477
Eric Moore29dd3602007-09-14 18:46:51 -06003478 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3479 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003480
Eric Moorebc6e0892007-09-29 10:16:28 -06003481 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3482 kzalloc(ioc->req_sz, GFP_KERNEL);
3483 if (!prequest) {
3484 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3485 "while allocating memory \n", ioc->name));
3486 mpt_free_fw_memory(ioc);
3487 return -ENOMEM;
3488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489
Eric Moorebc6e0892007-09-29 10:16:28 -06003490 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
3492 reply_sz = sizeof(reply);
3493 memset(preply, 0, reply_sz);
3494
3495 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3496 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3497
3498 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3499 ptcsge->DetailsLength = 12;
3500 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3501 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003502 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303505 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3506 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3507 ioc->SGE_size;
3508 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3509 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3510 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003511 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303513 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3514 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515
Eric Moore29dd3602007-09-14 18:46:51 -06003516 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
3518 cmdStatus = -EFAULT;
3519 if (ii == 0) {
3520 /* Handshake transfer was complete and successful.
3521 * Check the Reply Frame.
3522 */
3523 int status, transfer_sz;
3524 status = le16_to_cpu(preply->IOCStatus);
3525 if (status == MPI_IOCSTATUS_SUCCESS) {
3526 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3527 if (transfer_sz == sz)
3528 cmdStatus = 0;
3529 }
3530 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303531 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 ioc->name, cmdStatus));
3533
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003534
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 if (cmdStatus) {
3536
Prakash, Sathya436ace72007-07-24 15:42:08 +05303537 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 ioc->name));
3539 mpt_free_fw_memory(ioc);
3540 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003541 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
3543 return cmdStatus;
3544}
3545
3546/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003547/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548 * mpt_downloadboot - DownloadBoot code
3549 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003550 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 * @sleepFlag: Specifies whether the process can sleep
3552 *
3553 * FwDownloadBoot requires Programmed IO access.
3554 *
3555 * Returns 0 for success
3556 * -1 FW Image size is 0
3557 * -2 No valid cached_fw Pointer
3558 * <0 for fw upload failure.
3559 */
3560static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003561mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 MpiExtImageHeader_t *pExtImage;
3564 u32 fwSize;
3565 u32 diag0val;
3566 int count;
3567 u32 *ptrFw;
3568 u32 diagRwData;
3569 u32 nextImage;
3570 u32 load_addr;
3571 u32 ioc_state=0;
3572
Prakash, Sathya436ace72007-07-24 15:42:08 +05303573 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003574 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003575
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3577 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3578 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3579 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3580 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3581 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3582
3583 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3584
3585 /* wait 1 msec */
3586 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003587 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 } else {
3589 mdelay (1);
3590 }
3591
3592 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3593 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3594
3595 for (count = 0; count < 30; count ++) {
3596 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3597 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303598 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 ioc->name, count));
3600 break;
3601 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003602 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003604 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003606 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 }
3608 }
3609
3610 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303611 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003612 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 ioc->name, diag0val));
3614 return -3;
3615 }
3616
3617 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3618 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3619 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3620 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3621 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3622 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3623
3624 /* Set the DiagRwEn and Disable ARM bits */
3625 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3626
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 fwSize = (pFwHeader->ImageSize + 3)/4;
3628 ptrFw = (u32 *) pFwHeader;
3629
3630 /* Write the LoadStartAddress to the DiagRw Address Register
3631 * using Programmed IO
3632 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003633 if (ioc->errata_flag_1064)
3634 pci_enable_io_access(ioc->pcidev);
3635
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303637 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 ioc->name, pFwHeader->LoadStartAddress));
3639
Prakash, Sathya436ace72007-07-24 15:42:08 +05303640 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 ioc->name, fwSize*4, ptrFw));
3642 while (fwSize--) {
3643 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3644 }
3645
3646 nextImage = pFwHeader->NextImageHeaderOffset;
3647 while (nextImage) {
3648 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3649
3650 load_addr = pExtImage->LoadStartAddress;
3651
3652 fwSize = (pExtImage->ImageSize + 3) >> 2;
3653 ptrFw = (u32 *)pExtImage;
3654
Prakash, Sathya436ace72007-07-24 15:42:08 +05303655 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 +02003656 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3658
3659 while (fwSize--) {
3660 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3661 }
3662 nextImage = pExtImage->NextImageHeaderOffset;
3663 }
3664
3665 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303666 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3668
3669 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303670 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3672
3673 /* Clear the internal flash bad bit - autoincrementing register,
3674 * so must do two writes.
3675 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003676 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003677 /*
3678 * 1030 and 1035 H/W errata, workaround to access
3679 * the ClearFlashBadSignatureBit
3680 */
3681 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3682 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3683 diagRwData |= 0x40000000;
3684 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3685 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3686
3687 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3688 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3689 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3690 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3691
3692 /* wait 1 msec */
3693 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003694 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003695 } else {
3696 mdelay (1);
3697 }
3698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003700 if (ioc->errata_flag_1064)
3701 pci_disable_io_access(ioc->pcidev);
3702
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303704 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003705 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003707 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303708 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 ioc->name, diag0val));
3710 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3711
3712 /* Write 0xFF to reset the sequencer */
3713 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3714
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003715 if (ioc->bus_type == SAS) {
3716 ioc_state = mpt_GetIocState(ioc, 0);
3717 if ( (GetIocFacts(ioc, sleepFlag,
3718 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303719 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003720 ioc->name, ioc_state));
3721 return -EFAULT;
3722 }
3723 }
3724
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 for (count=0; count<HZ*20; count++) {
3726 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303727 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3728 "downloadboot successful! (count=%d) IocState=%x\n",
3729 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003730 if (ioc->bus_type == SAS) {
3731 return 0;
3732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303734 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3735 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 ioc->name));
3737 return -EFAULT;
3738 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303739 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3740 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 ioc->name));
3742 return 0;
3743 }
3744 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003745 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 } else {
3747 mdelay (10);
3748 }
3749 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303750 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3751 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 return -EFAULT;
3753}
3754
3755/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003756/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 * KickStart - Perform hard reset of MPT adapter.
3758 * @ioc: Pointer to MPT_ADAPTER structure
3759 * @force: Force hard reset
3760 * @sleepFlag: Specifies whether the process can sleep
3761 *
3762 * This routine places MPT adapter in diagnostic mode via the
3763 * WriteSequence register, and then performs a hard reset of adapter
3764 * via the Diagnostic register.
3765 *
3766 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3767 * or NO_SLEEP (interrupt thread, use mdelay)
3768 * force - 1 if doorbell active, board fault state
3769 * board operational, IOC_RECOVERY or
3770 * IOC_BRINGUP and there is an alt_ioc.
3771 * 0 else
3772 *
3773 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003774 * 1 - hard reset, READY
3775 * 0 - no reset due to History bit, READY
3776 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 * OR reset but failed to come READY
3778 * -2 - no reset, could not enter DIAG mode
3779 * -3 - reset but bad FW bit
3780 */
3781static int
3782KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3783{
3784 int hard_reset_done = 0;
3785 u32 ioc_state=0;
3786 int cnt,cntdn;
3787
Eric Moore29dd3602007-09-14 18:46:51 -06003788 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003789 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 /* Always issue a Msg Unit Reset first. This will clear some
3791 * SCSI bus hang conditions.
3792 */
3793 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3794
3795 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003796 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 } else {
3798 mdelay (1000);
3799 }
3800 }
3801
3802 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3803 if (hard_reset_done < 0)
3804 return hard_reset_done;
3805
Prakash, Sathya436ace72007-07-24 15:42:08 +05303806 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003807 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808
3809 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3810 for (cnt=0; cnt<cntdn; cnt++) {
3811 ioc_state = mpt_GetIocState(ioc, 1);
3812 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303813 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 ioc->name, cnt));
3815 return hard_reset_done;
3816 }
3817 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003818 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 } else {
3820 mdelay (10);
3821 }
3822 }
3823
Eric Moore29dd3602007-09-14 18:46:51 -06003824 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3825 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 return -1;
3827}
3828
3829/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003830/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 * mpt_diag_reset - Perform hard reset of the adapter.
3832 * @ioc: Pointer to MPT_ADAPTER structure
3833 * @ignore: Set if to honor and clear to ignore
3834 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003835 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 * else set to NO_SLEEP (use mdelay instead)
3837 *
3838 * This routine places the adapter in diagnostic mode via the
3839 * WriteSequence register and then performs a hard reset of adapter
3840 * via the Diagnostic register. Adapter should be in ready state
3841 * upon successful completion.
3842 *
3843 * Returns: 1 hard reset successful
3844 * 0 no reset performed because reset history bit set
3845 * -2 enabling diagnostic mode failed
3846 * -3 diagnostic reset failed
3847 */
3848static int
3849mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3850{
3851 u32 diag0val;
3852 u32 doorbell;
3853 int hard_reset_done = 0;
3854 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303856 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857
Eric Moorecd2c6192007-01-29 09:47:47 -07003858 /* Clear any existing interrupts */
3859 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3860
Eric Moore87cf8982006-06-27 16:09:26 -06003861 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303862 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003863 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003864 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3865 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3866 if (sleepFlag == CAN_SLEEP)
3867 msleep(1);
3868 else
3869 mdelay(1);
3870
3871 for (count = 0; count < 60; count ++) {
3872 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3873 doorbell &= MPI_IOC_STATE_MASK;
3874
Prakash, Sathya436ace72007-07-24 15:42:08 +05303875 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003876 "looking for READY STATE: doorbell=%x"
3877 " count=%d\n",
3878 ioc->name, doorbell, count));
3879 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003880 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003881 }
3882
3883 /* wait 1 sec */
3884 if (sleepFlag == CAN_SLEEP)
3885 msleep(1000);
3886 else
3887 mdelay(1000);
3888 }
3889 return -1;
3890 }
3891
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 /* Use "Diagnostic reset" method! (only thing available!) */
3893 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3894
Prakash, Sathya436ace72007-07-24 15:42:08 +05303895 if (ioc->debug_level & MPT_DEBUG) {
3896 if (ioc->alt_ioc)
3897 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3898 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901
3902 /* Do the reset if we are told to ignore the reset history
3903 * or if the reset history is 0
3904 */
3905 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3906 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3907 /* Write magic sequence to WriteSequence register
3908 * Loop until in diagnostic mode
3909 */
3910 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3911 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3912 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3913 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3914 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3915 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3916
3917 /* wait 100 msec */
3918 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003919 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 } else {
3921 mdelay (100);
3922 }
3923
3924 count++;
3925 if (count > 20) {
3926 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3927 ioc->name, diag0val);
3928 return -2;
3929
3930 }
3931
3932 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3933
Prakash, Sathya436ace72007-07-24 15:42:08 +05303934 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 ioc->name, diag0val));
3936 }
3937
Prakash, Sathya436ace72007-07-24 15:42:08 +05303938 if (ioc->debug_level & MPT_DEBUG) {
3939 if (ioc->alt_ioc)
3940 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3941 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 /*
3945 * Disable the ARM (Bug fix)
3946 *
3947 */
3948 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003949 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950
3951 /*
3952 * Now hit the reset bit in the Diagnostic register
3953 * (THE BIG HAMMER!) (Clears DRWE bit).
3954 */
3955 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3956 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303957 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 ioc->name));
3959
3960 /*
3961 * Call each currently registered protocol IOC reset handler
3962 * with pre-reset indication.
3963 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3964 * MptResetHandlers[] registered yet.
3965 */
3966 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303967 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 int r = 0;
3969
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303970 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3971 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303972 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3973 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303974 ioc->name, cb_idx));
3975 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303977 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3978 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303979 ioc->name, ioc->alt_ioc->name, cb_idx));
3980 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 }
3982 }
3983 }
3984 /* FIXME? Examine results here? */
3985 }
3986
Eric Moore0ccdb002006-07-11 17:33:13 -06003987 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303988 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003989 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303990 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3991 else
3992 cached_fw = NULL;
3993 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 /* If the DownloadBoot operation fails, the
3995 * IOC will be left unusable. This is a fatal error
3996 * case. _diag_reset will return < 0
3997 */
3998 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303999 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4001 break;
4002 }
4003
Prakash, Sathya436ace72007-07-24 15:42:08 +05304004 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304005 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 /* wait 1 sec */
4007 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004008 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 } else {
4010 mdelay (1000);
4011 }
4012 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304013 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004014 printk(MYIOC_s_WARN_FMT
4015 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 }
4017
4018 } else {
4019 /* Wait for FW to reload and for board
4020 * to go to the READY state.
4021 * Maximum wait is 60 seconds.
4022 * If fail, no error will check again
4023 * with calling program.
4024 */
4025 for (count = 0; count < 60; count ++) {
4026 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4027 doorbell &= MPI_IOC_STATE_MASK;
4028
4029 if (doorbell == MPI_IOC_STATE_READY) {
4030 break;
4031 }
4032
4033 /* wait 1 sec */
4034 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004035 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 } else {
4037 mdelay (1000);
4038 }
4039 }
4040 }
4041 }
4042
4043 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304044 if (ioc->debug_level & MPT_DEBUG) {
4045 if (ioc->alt_ioc)
4046 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4047 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4048 ioc->name, diag0val, diag1val));
4049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050
4051 /* Clear RESET_HISTORY bit! Place board in the
4052 * diagnostic mode to update the diag register.
4053 */
4054 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4055 count = 0;
4056 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4057 /* Write magic sequence to WriteSequence register
4058 * Loop until in diagnostic mode
4059 */
4060 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4061 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4062 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4063 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4064 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4065 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4066
4067 /* wait 100 msec */
4068 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004069 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 } else {
4071 mdelay (100);
4072 }
4073
4074 count++;
4075 if (count > 20) {
4076 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4077 ioc->name, diag0val);
4078 break;
4079 }
4080 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4081 }
4082 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4083 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4084 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4085 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4086 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4087 ioc->name);
4088 }
4089
4090 /* Disable Diagnostic Mode
4091 */
4092 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4093
4094 /* Check FW reload status flags.
4095 */
4096 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4097 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4098 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4099 ioc->name, diag0val);
4100 return -3;
4101 }
4102
Prakash, Sathya436ace72007-07-24 15:42:08 +05304103 if (ioc->debug_level & MPT_DEBUG) {
4104 if (ioc->alt_ioc)
4105 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4106 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109
4110 /*
4111 * Reset flag that says we've enabled event notification
4112 */
4113 ioc->facts.EventState = 0;
4114
4115 if (ioc->alt_ioc)
4116 ioc->alt_ioc->facts.EventState = 0;
4117
4118 return hard_reset_done;
4119}
4120
4121/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004122/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 * SendIocReset - Send IOCReset request to MPT adapter.
4124 * @ioc: Pointer to MPT_ADAPTER structure
4125 * @reset_type: reset type, expected values are
4126 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004127 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 *
4129 * Send IOCReset request to the MPT adapter.
4130 *
4131 * Returns 0 for success, non-zero for failure.
4132 */
4133static int
4134SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4135{
4136 int r;
4137 u32 state;
4138 int cntdn, count;
4139
Prakash, Sathya436ace72007-07-24 15:42:08 +05304140 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 ioc->name, reset_type));
4142 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4143 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4144 return r;
4145
4146 /* FW ACK'd request, wait for READY state
4147 */
4148 count = 0;
4149 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4150
4151 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4152 cntdn--;
4153 count++;
4154 if (!cntdn) {
4155 if (sleepFlag != CAN_SLEEP)
4156 count *= 10;
4157
Eric Moore29dd3602007-09-14 18:46:51 -06004158 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
4159 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 return -ETIME;
4161 }
4162
4163 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004164 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 } else {
4166 mdelay (1); /* 1 msec delay */
4167 }
4168 }
4169
4170 /* TODO!
4171 * Cleanup all event stuff for this IOC; re-issue EventNotification
4172 * request if needed.
4173 */
4174 if (ioc->facts.Function)
4175 ioc->facts.EventState = 0;
4176
4177 return 0;
4178}
4179
4180/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004181/**
4182 * initChainBuffers - Allocate memory for and initialize chain buffers
4183 * @ioc: Pointer to MPT_ADAPTER structure
4184 *
4185 * Allocates memory for and initializes chain buffers,
4186 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 */
4188static int
4189initChainBuffers(MPT_ADAPTER *ioc)
4190{
4191 u8 *mem;
4192 int sz, ii, num_chain;
4193 int scale, num_sge, numSGE;
4194
4195 /* ReqToChain size must equal the req_depth
4196 * index = req_idx
4197 */
4198 if (ioc->ReqToChain == NULL) {
4199 sz = ioc->req_depth * sizeof(int);
4200 mem = kmalloc(sz, GFP_ATOMIC);
4201 if (mem == NULL)
4202 return -1;
4203
4204 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304205 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 ioc->name, mem, sz));
4207 mem = kmalloc(sz, GFP_ATOMIC);
4208 if (mem == NULL)
4209 return -1;
4210
4211 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304212 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 ioc->name, mem, sz));
4214 }
4215 for (ii = 0; ii < ioc->req_depth; ii++) {
4216 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4217 }
4218
4219 /* ChainToChain size must equal the total number
4220 * of chain buffers to be allocated.
4221 * index = chain_idx
4222 *
4223 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004224 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 *
4226 * num_sge = num sge in request frame + last chain buffer
4227 * scale = num sge per chain buffer if no chain element
4228 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304229 scale = ioc->req_sz / ioc->SGE_size;
4230 if (ioc->sg_addr_size == sizeof(u64))
4231 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304233 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304235 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304237 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304239 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4240 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304242 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 ioc->name, num_sge, numSGE));
4244
4245 if ( numSGE > MPT_SCSI_SG_DEPTH )
4246 numSGE = MPT_SCSI_SG_DEPTH;
4247
4248 num_chain = 1;
4249 while (numSGE - num_sge > 0) {
4250 num_chain++;
4251 num_sge += (scale - 1);
4252 }
4253 num_chain++;
4254
Prakash, Sathya436ace72007-07-24 15:42:08 +05304255 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 ioc->name, numSGE, num_sge, num_chain));
4257
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004258 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 num_chain *= MPT_SCSI_CAN_QUEUE;
4260 else
4261 num_chain *= MPT_FC_CAN_QUEUE;
4262
4263 ioc->num_chain = num_chain;
4264
4265 sz = num_chain * sizeof(int);
4266 if (ioc->ChainToChain == NULL) {
4267 mem = kmalloc(sz, GFP_ATOMIC);
4268 if (mem == NULL)
4269 return -1;
4270
4271 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304272 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 ioc->name, mem, sz));
4274 } else {
4275 mem = (u8 *) ioc->ChainToChain;
4276 }
4277 memset(mem, 0xFF, sz);
4278 return num_chain;
4279}
4280
4281/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004282/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4284 * @ioc: Pointer to MPT_ADAPTER structure
4285 *
4286 * This routine allocates memory for the MPT reply and request frame
4287 * pools (if necessary), and primes the IOC reply FIFO with
4288 * reply frames.
4289 *
4290 * Returns 0 for success, non-zero for failure.
4291 */
4292static int
4293PrimeIocFifos(MPT_ADAPTER *ioc)
4294{
4295 MPT_FRAME_HDR *mf;
4296 unsigned long flags;
4297 dma_addr_t alloc_dma;
4298 u8 *mem;
4299 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304300 u64 dma_mask;
4301
4302 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303
4304 /* Prime reply FIFO... */
4305
4306 if (ioc->reply_frames == NULL) {
4307 if ( (num_chain = initChainBuffers(ioc)) < 0)
4308 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304309 /*
4310 * 1078 errata workaround for the 36GB limitation
4311 */
4312 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4313 ioc->dma_mask > DMA_35BIT_MASK) {
4314 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4315 && !pci_set_consistent_dma_mask(ioc->pcidev,
4316 DMA_BIT_MASK(32))) {
4317 dma_mask = DMA_35BIT_MASK;
4318 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4319 "setting 35 bit addressing for "
4320 "Request/Reply/Chain and Sense Buffers\n",
4321 ioc->name));
4322 } else {
4323 /*Reseting DMA mask to 64 bit*/
4324 pci_set_dma_mask(ioc->pcidev,
4325 DMA_BIT_MASK(64));
4326 pci_set_consistent_dma_mask(ioc->pcidev,
4327 DMA_BIT_MASK(64));
4328
4329 printk(MYIOC_s_ERR_FMT
4330 "failed setting 35 bit addressing for "
4331 "Request/Reply/Chain and Sense Buffers\n",
4332 ioc->name);
4333 return -1;
4334 }
4335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
4337 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304338 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304340 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 ioc->name, reply_sz, reply_sz));
4342
4343 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304344 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304346 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 ioc->name, sz, sz));
4348 total_size += sz;
4349
4350 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304351 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304353 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 ioc->name, sz, sz, num_chain));
4355
4356 total_size += sz;
4357 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4358 if (mem == NULL) {
4359 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4360 ioc->name);
4361 goto out_fail;
4362 }
4363
Prakash, Sathya436ace72007-07-24 15:42:08 +05304364 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4366
4367 memset(mem, 0, total_size);
4368 ioc->alloc_total += total_size;
4369 ioc->alloc = mem;
4370 ioc->alloc_dma = alloc_dma;
4371 ioc->alloc_sz = total_size;
4372 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4373 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4374
Prakash, Sathya436ace72007-07-24 15:42:08 +05304375 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004376 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4377
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 alloc_dma += reply_sz;
4379 mem += reply_sz;
4380
4381 /* Request FIFO - WE manage this! */
4382
4383 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4384 ioc->req_frames_dma = alloc_dma;
4385
Prakash, Sathya436ace72007-07-24 15:42:08 +05304386 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 ioc->name, mem, (void *)(ulong)alloc_dma));
4388
4389 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4390
4391#if defined(CONFIG_MTRR) && 0
4392 /*
4393 * Enable Write Combining MTRR for IOC's memory region.
4394 * (at least as much as we can; "size and base must be
4395 * multiples of 4 kiB"
4396 */
4397 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4398 sz,
4399 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304400 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 ioc->name, ioc->req_frames_dma, sz));
4402#endif
4403
4404 for (i = 0; i < ioc->req_depth; i++) {
4405 alloc_dma += ioc->req_sz;
4406 mem += ioc->req_sz;
4407 }
4408
4409 ioc->ChainBuffer = mem;
4410 ioc->ChainBufferDMA = alloc_dma;
4411
Prakash, Sathya436ace72007-07-24 15:42:08 +05304412 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4414
4415 /* Initialize the free chain Q.
4416 */
4417
4418 INIT_LIST_HEAD(&ioc->FreeChainQ);
4419
4420 /* Post the chain buffers to the FreeChainQ.
4421 */
4422 mem = (u8 *)ioc->ChainBuffer;
4423 for (i=0; i < num_chain; i++) {
4424 mf = (MPT_FRAME_HDR *) mem;
4425 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4426 mem += ioc->req_sz;
4427 }
4428
4429 /* Initialize Request frames linked list
4430 */
4431 alloc_dma = ioc->req_frames_dma;
4432 mem = (u8 *) ioc->req_frames;
4433
4434 spin_lock_irqsave(&ioc->FreeQlock, flags);
4435 INIT_LIST_HEAD(&ioc->FreeQ);
4436 for (i = 0; i < ioc->req_depth; i++) {
4437 mf = (MPT_FRAME_HDR *) mem;
4438
4439 /* Queue REQUESTs *internally*! */
4440 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4441
4442 mem += ioc->req_sz;
4443 }
4444 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4445
4446 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4447 ioc->sense_buf_pool =
4448 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4449 if (ioc->sense_buf_pool == NULL) {
4450 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4451 ioc->name);
4452 goto out_fail;
4453 }
4454
4455 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4456 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304457 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4459
4460 }
4461
4462 /* Post Reply frames to FIFO
4463 */
4464 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304465 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4467
4468 for (i = 0; i < ioc->reply_depth; i++) {
4469 /* Write each address to the IOC! */
4470 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4471 alloc_dma += ioc->reply_sz;
4472 }
4473
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304474 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4475 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4476 ioc->dma_mask))
4477 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4478 "restoring 64 bit addressing\n", ioc->name));
4479
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 return 0;
4481
4482out_fail:
4483 if (ioc->alloc != NULL) {
4484 sz = ioc->alloc_sz;
4485 pci_free_consistent(ioc->pcidev,
4486 sz,
4487 ioc->alloc, ioc->alloc_dma);
4488 ioc->reply_frames = NULL;
4489 ioc->req_frames = NULL;
4490 ioc->alloc_total -= sz;
4491 }
4492 if (ioc->sense_buf_pool != NULL) {
4493 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4494 pci_free_consistent(ioc->pcidev,
4495 sz,
4496 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4497 ioc->sense_buf_pool = NULL;
4498 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304499
4500 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4501 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4502 DMA_BIT_MASK(64)))
4503 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4504 "restoring 64 bit addressing\n", ioc->name));
4505
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 return -1;
4507}
4508
4509/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4510/**
4511 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4512 * from IOC via doorbell handshake method.
4513 * @ioc: Pointer to MPT_ADAPTER structure
4514 * @reqBytes: Size of the request in bytes
4515 * @req: Pointer to MPT request frame
4516 * @replyBytes: Expected size of the reply in bytes
4517 * @u16reply: Pointer to area where reply should be written
4518 * @maxwait: Max wait time for a reply (in seconds)
4519 * @sleepFlag: Specifies whether the process can sleep
4520 *
4521 * NOTES: It is the callers responsibility to byte-swap fields in the
4522 * request which are greater than 1 byte in size. It is also the
4523 * callers responsibility to byte-swap response fields which are
4524 * greater than 1 byte in size.
4525 *
4526 * Returns 0 for success, non-zero for failure.
4527 */
4528static int
4529mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004530 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531{
4532 MPIDefaultReply_t *mptReply;
4533 int failcnt = 0;
4534 int t;
4535
4536 /*
4537 * Get ready to cache a handshake reply
4538 */
4539 ioc->hs_reply_idx = 0;
4540 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4541 mptReply->MsgLength = 0;
4542
4543 /*
4544 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4545 * then tell IOC that we want to handshake a request of N words.
4546 * (WRITE u32val to Doorbell reg).
4547 */
4548 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4549 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4550 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4551 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4552
4553 /*
4554 * Wait for IOC's doorbell handshake int
4555 */
4556 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4557 failcnt++;
4558
Prakash, Sathya436ace72007-07-24 15:42:08 +05304559 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4561
4562 /* Read doorbell and check for active bit */
4563 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4564 return -1;
4565
4566 /*
4567 * Clear doorbell int (WRITE 0 to IntStatus reg),
4568 * then wait for IOC to ACKnowledge that it's ready for
4569 * our handshake request.
4570 */
4571 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4572 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4573 failcnt++;
4574
4575 if (!failcnt) {
4576 int ii;
4577 u8 *req_as_bytes = (u8 *) req;
4578
4579 /*
4580 * Stuff request words via doorbell handshake,
4581 * with ACK from IOC for each.
4582 */
4583 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4584 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4585 (req_as_bytes[(ii*4) + 1] << 8) |
4586 (req_as_bytes[(ii*4) + 2] << 16) |
4587 (req_as_bytes[(ii*4) + 3] << 24));
4588
4589 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4590 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4591 failcnt++;
4592 }
4593
Prakash, Sathya436ace72007-07-24 15:42:08 +05304594 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004595 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596
Prakash, Sathya436ace72007-07-24 15:42:08 +05304597 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4599
4600 /*
4601 * Wait for completion of doorbell handshake reply from the IOC
4602 */
4603 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4604 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004605
Prakash, Sathya436ace72007-07-24 15:42:08 +05304606 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4608
4609 /*
4610 * Copy out the cached reply...
4611 */
4612 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4613 u16reply[ii] = ioc->hs_reply[ii];
4614 } else {
4615 return -99;
4616 }
4617
4618 return -failcnt;
4619}
4620
4621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004622/**
4623 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 * @ioc: Pointer to MPT_ADAPTER structure
4625 * @howlong: How long to wait (in seconds)
4626 * @sleepFlag: Specifies whether the process can sleep
4627 *
4628 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004629 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4630 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 *
4632 * Returns a negative value on failure, else wait loop count.
4633 */
4634static int
4635WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4636{
4637 int cntdn;
4638 int count = 0;
4639 u32 intstat=0;
4640
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004641 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642
4643 if (sleepFlag == CAN_SLEEP) {
4644 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004645 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4647 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4648 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 count++;
4650 }
4651 } else {
4652 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004653 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4655 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4656 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 count++;
4658 }
4659 }
4660
4661 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304662 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 ioc->name, count));
4664 return count;
4665 }
4666
4667 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4668 ioc->name, count, intstat);
4669 return -1;
4670}
4671
4672/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004673/**
4674 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 * @ioc: Pointer to MPT_ADAPTER structure
4676 * @howlong: How long to wait (in seconds)
4677 * @sleepFlag: Specifies whether the process can sleep
4678 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004679 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4680 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 *
4682 * Returns a negative value on failure, else wait loop count.
4683 */
4684static int
4685WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4686{
4687 int cntdn;
4688 int count = 0;
4689 u32 intstat=0;
4690
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004691 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 if (sleepFlag == CAN_SLEEP) {
4693 while (--cntdn) {
4694 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4695 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4696 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004697 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 count++;
4699 }
4700 } else {
4701 while (--cntdn) {
4702 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4703 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4704 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004705 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 count++;
4707 }
4708 }
4709
4710 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304711 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 ioc->name, count, howlong));
4713 return count;
4714 }
4715
4716 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4717 ioc->name, count, intstat);
4718 return -1;
4719}
4720
4721/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004722/**
4723 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 * @ioc: Pointer to MPT_ADAPTER structure
4725 * @howlong: How long to wait (in seconds)
4726 * @sleepFlag: Specifies whether the process can sleep
4727 *
4728 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4729 * Reply is cached to IOC private area large enough to hold a maximum
4730 * of 128 bytes of reply data.
4731 *
4732 * Returns a negative value on failure, else size of reply in WORDS.
4733 */
4734static int
4735WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4736{
4737 int u16cnt = 0;
4738 int failcnt = 0;
4739 int t;
4740 u16 *hs_reply = ioc->hs_reply;
4741 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4742 u16 hword;
4743
4744 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4745
4746 /*
4747 * Get first two u16's so we can look at IOC's intended reply MsgLength
4748 */
4749 u16cnt=0;
4750 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4751 failcnt++;
4752 } else {
4753 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4754 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4755 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4756 failcnt++;
4757 else {
4758 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4759 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4760 }
4761 }
4762
Prakash, Sathya436ace72007-07-24 15:42:08 +05304763 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004764 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4766
4767 /*
4768 * If no error (and IOC said MsgLength is > 0), piece together
4769 * reply 16 bits at a time.
4770 */
4771 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4772 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4773 failcnt++;
4774 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4775 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004776 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 hs_reply[u16cnt] = hword;
4778 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4779 }
4780
4781 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4782 failcnt++;
4783 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4784
4785 if (failcnt) {
4786 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4787 ioc->name);
4788 return -failcnt;
4789 }
4790#if 0
4791 else if (u16cnt != (2 * mptReply->MsgLength)) {
4792 return -101;
4793 }
4794 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4795 return -102;
4796 }
4797#endif
4798
Prakash, Sathya436ace72007-07-24 15:42:08 +05304799 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004800 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801
Prakash, Sathya436ace72007-07-24 15:42:08 +05304802 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 ioc->name, t, u16cnt/2));
4804 return u16cnt/2;
4805}
4806
4807/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004808/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 * GetLanConfigPages - Fetch LANConfig pages.
4810 * @ioc: Pointer to MPT_ADAPTER structure
4811 *
4812 * Return: 0 for success
4813 * -ENOMEM if no memory available
4814 * -EPERM if not allowed due to ISR context
4815 * -EAGAIN if no msg frames currently available
4816 * -EFAULT for non-successful reply or no reply (timeout)
4817 */
4818static int
4819GetLanConfigPages(MPT_ADAPTER *ioc)
4820{
4821 ConfigPageHeader_t hdr;
4822 CONFIGPARMS cfg;
4823 LANPage0_t *ppage0_alloc;
4824 dma_addr_t page0_dma;
4825 LANPage1_t *ppage1_alloc;
4826 dma_addr_t page1_dma;
4827 int rc = 0;
4828 int data_sz;
4829 int copy_sz;
4830
4831 /* Get LAN Page 0 header */
4832 hdr.PageVersion = 0;
4833 hdr.PageLength = 0;
4834 hdr.PageNumber = 0;
4835 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004836 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 cfg.physAddr = -1;
4838 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4839 cfg.dir = 0;
4840 cfg.pageAddr = 0;
4841 cfg.timeout = 0;
4842
4843 if ((rc = mpt_config(ioc, &cfg)) != 0)
4844 return rc;
4845
4846 if (hdr.PageLength > 0) {
4847 data_sz = hdr.PageLength * 4;
4848 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4849 rc = -ENOMEM;
4850 if (ppage0_alloc) {
4851 memset((u8 *)ppage0_alloc, 0, data_sz);
4852 cfg.physAddr = page0_dma;
4853 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4854
4855 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4856 /* save the data */
4857 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4858 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4859
4860 }
4861
4862 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4863
4864 /* FIXME!
4865 * Normalize endianness of structure data,
4866 * by byte-swapping all > 1 byte fields!
4867 */
4868
4869 }
4870
4871 if (rc)
4872 return rc;
4873 }
4874
4875 /* Get LAN Page 1 header */
4876 hdr.PageVersion = 0;
4877 hdr.PageLength = 0;
4878 hdr.PageNumber = 1;
4879 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004880 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 cfg.physAddr = -1;
4882 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4883 cfg.dir = 0;
4884 cfg.pageAddr = 0;
4885
4886 if ((rc = mpt_config(ioc, &cfg)) != 0)
4887 return rc;
4888
4889 if (hdr.PageLength == 0)
4890 return 0;
4891
4892 data_sz = hdr.PageLength * 4;
4893 rc = -ENOMEM;
4894 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4895 if (ppage1_alloc) {
4896 memset((u8 *)ppage1_alloc, 0, data_sz);
4897 cfg.physAddr = page1_dma;
4898 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4899
4900 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4901 /* save the data */
4902 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4903 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4904 }
4905
4906 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4907
4908 /* FIXME!
4909 * Normalize endianness of structure data,
4910 * by byte-swapping all > 1 byte fields!
4911 */
4912
4913 }
4914
4915 return rc;
4916}
4917
4918/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004919/**
4920 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004921 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004922 * @persist_opcode: see below
4923 *
4924 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4925 * devices not currently present.
4926 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4927 *
4928 * NOTE: Don't use not this function during interrupt time.
4929 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004930 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004931 */
4932
4933/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4934int
4935mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4936{
4937 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4938 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4939 MPT_FRAME_HDR *mf = NULL;
4940 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304941 int ret = 0;
4942 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004943
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304944 mutex_lock(&ioc->mptbase_cmds.mutex);
4945
4946 /* init the internal cmd struct */
4947 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
4948 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004949
4950 /* insure garbage is not sent to fw */
4951 switch(persist_opcode) {
4952
4953 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4954 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4955 break;
4956
4957 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304958 ret = -1;
4959 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004960 }
4961
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304962 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
4963 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004964
4965 /* Get a MF for this command.
4966 */
4967 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304968 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
4969 ret = -1;
4970 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004971 }
4972
4973 mpi_hdr = (MPIHeader_t *) mf;
4974 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4975 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4976 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4977 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4978 sasIoUnitCntrReq->Operation = persist_opcode;
4979
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004980 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304981 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
4982 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4983 ret = -ETIME;
4984 printk(KERN_DEBUG "%s: failed\n", __func__);
4985 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4986 goto out;
4987 if (!timeleft) {
4988 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
4989 ioc->name, __func__);
4990 mpt_HardResetHandler(ioc, CAN_SLEEP);
4991 mpt_free_msg_frame(ioc, mf);
4992 }
4993 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004994 }
4995
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304996 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4997 ret = -1;
4998 goto out;
4999 }
5000
5001 sasIoUnitCntrReply =
5002 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5003 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5004 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5005 __func__, sasIoUnitCntrReply->IOCStatus,
5006 sasIoUnitCntrReply->IOCLogInfo);
5007 printk(KERN_DEBUG "%s: failed\n", __func__);
5008 ret = -1;
5009 } else
5010 printk(KERN_DEBUG "%s: success\n", __func__);
5011 out:
5012
5013 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5014 mutex_unlock(&ioc->mptbase_cmds.mutex);
5015 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005016}
5017
5018/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005019
5020static void
5021mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5022 MpiEventDataRaid_t * pRaidEventData)
5023{
5024 int volume;
5025 int reason;
5026 int disk;
5027 int status;
5028 int flags;
5029 int state;
5030
5031 volume = pRaidEventData->VolumeID;
5032 reason = pRaidEventData->ReasonCode;
5033 disk = pRaidEventData->PhysDiskNum;
5034 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5035 flags = (status >> 0) & 0xff;
5036 state = (status >> 8) & 0xff;
5037
5038 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5039 return;
5040 }
5041
5042 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5043 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5044 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005045 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5046 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005047 } else {
5048 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5049 ioc->name, volume);
5050 }
5051
5052 switch(reason) {
5053 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5054 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5055 ioc->name);
5056 break;
5057
5058 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5059
5060 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5061 ioc->name);
5062 break;
5063
5064 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5065 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5066 ioc->name);
5067 break;
5068
5069 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5070 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5071 ioc->name,
5072 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5073 ? "optimal"
5074 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5075 ? "degraded"
5076 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5077 ? "failed"
5078 : "state unknown",
5079 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5080 ? ", enabled" : "",
5081 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5082 ? ", quiesced" : "",
5083 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5084 ? ", resync in progress" : "" );
5085 break;
5086
5087 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5088 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5089 ioc->name, disk);
5090 break;
5091
5092 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5093 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5094 ioc->name);
5095 break;
5096
5097 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5098 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5099 ioc->name);
5100 break;
5101
5102 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5103 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5104 ioc->name);
5105 break;
5106
5107 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5108 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5109 ioc->name,
5110 state == MPI_PHYSDISK0_STATUS_ONLINE
5111 ? "online"
5112 : state == MPI_PHYSDISK0_STATUS_MISSING
5113 ? "missing"
5114 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5115 ? "not compatible"
5116 : state == MPI_PHYSDISK0_STATUS_FAILED
5117 ? "failed"
5118 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5119 ? "initializing"
5120 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5121 ? "offline requested"
5122 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5123 ? "failed requested"
5124 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5125 ? "offline"
5126 : "state unknown",
5127 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5128 ? ", out of sync" : "",
5129 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5130 ? ", quiesced" : "" );
5131 break;
5132
5133 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5134 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5135 ioc->name, disk);
5136 break;
5137
5138 case MPI_EVENT_RAID_RC_SMART_DATA:
5139 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5140 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5141 break;
5142
5143 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5144 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5145 ioc->name, disk);
5146 break;
5147 }
5148}
5149
5150/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005151/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5153 * @ioc: Pointer to MPT_ADAPTER structure
5154 *
5155 * Returns: 0 for success
5156 * -ENOMEM if no memory available
5157 * -EPERM if not allowed due to ISR context
5158 * -EAGAIN if no msg frames currently available
5159 * -EFAULT for non-successful reply or no reply (timeout)
5160 */
5161static int
5162GetIoUnitPage2(MPT_ADAPTER *ioc)
5163{
5164 ConfigPageHeader_t hdr;
5165 CONFIGPARMS cfg;
5166 IOUnitPage2_t *ppage_alloc;
5167 dma_addr_t page_dma;
5168 int data_sz;
5169 int rc;
5170
5171 /* Get the page header */
5172 hdr.PageVersion = 0;
5173 hdr.PageLength = 0;
5174 hdr.PageNumber = 2;
5175 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005176 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 cfg.physAddr = -1;
5178 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5179 cfg.dir = 0;
5180 cfg.pageAddr = 0;
5181 cfg.timeout = 0;
5182
5183 if ((rc = mpt_config(ioc, &cfg)) != 0)
5184 return rc;
5185
5186 if (hdr.PageLength == 0)
5187 return 0;
5188
5189 /* Read the config page */
5190 data_sz = hdr.PageLength * 4;
5191 rc = -ENOMEM;
5192 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5193 if (ppage_alloc) {
5194 memset((u8 *)ppage_alloc, 0, data_sz);
5195 cfg.physAddr = page_dma;
5196 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5197
5198 /* If Good, save data */
5199 if ((rc = mpt_config(ioc, &cfg)) == 0)
5200 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5201
5202 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5203 }
5204
5205 return rc;
5206}
5207
5208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005209/**
5210 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 * @ioc: Pointer to a Adapter Strucutre
5212 * @portnum: IOC port number
5213 *
5214 * Return: -EFAULT if read of config page header fails
5215 * or if no nvram
5216 * If read of SCSI Port Page 0 fails,
5217 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5218 * Adapter settings: async, narrow
5219 * Return 1
5220 * If read of SCSI Port Page 2 fails,
5221 * Adapter settings valid
5222 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5223 * Return 1
5224 * Else
5225 * Both valid
5226 * Return 0
5227 * CHECK - what type of locking mechanisms should be used????
5228 */
5229static int
5230mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5231{
5232 u8 *pbuf;
5233 dma_addr_t buf_dma;
5234 CONFIGPARMS cfg;
5235 ConfigPageHeader_t header;
5236 int ii;
5237 int data, rc = 0;
5238
5239 /* Allocate memory
5240 */
5241 if (!ioc->spi_data.nvram) {
5242 int sz;
5243 u8 *mem;
5244 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5245 mem = kmalloc(sz, GFP_ATOMIC);
5246 if (mem == NULL)
5247 return -EFAULT;
5248
5249 ioc->spi_data.nvram = (int *) mem;
5250
Prakash, Sathya436ace72007-07-24 15:42:08 +05305251 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 ioc->name, ioc->spi_data.nvram, sz));
5253 }
5254
5255 /* Invalidate NVRAM information
5256 */
5257 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5258 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5259 }
5260
5261 /* Read SPP0 header, allocate memory, then read page.
5262 */
5263 header.PageVersion = 0;
5264 header.PageLength = 0;
5265 header.PageNumber = 0;
5266 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005267 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 cfg.physAddr = -1;
5269 cfg.pageAddr = portnum;
5270 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5271 cfg.dir = 0;
5272 cfg.timeout = 0; /* use default */
5273 if (mpt_config(ioc, &cfg) != 0)
5274 return -EFAULT;
5275
5276 if (header.PageLength > 0) {
5277 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5278 if (pbuf) {
5279 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5280 cfg.physAddr = buf_dma;
5281 if (mpt_config(ioc, &cfg) != 0) {
5282 ioc->spi_data.maxBusWidth = MPT_NARROW;
5283 ioc->spi_data.maxSyncOffset = 0;
5284 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5285 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5286 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305287 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5288 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005289 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 } else {
5291 /* Save the Port Page 0 data
5292 */
5293 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5294 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5295 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5296
5297 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5298 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005299 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5300 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 ioc->name, pPP0->Capabilities));
5302 }
5303 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5304 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5305 if (data) {
5306 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5307 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5308 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305309 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5310 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005311 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312 } else {
5313 ioc->spi_data.maxSyncOffset = 0;
5314 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5315 }
5316
5317 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5318
5319 /* Update the minSyncFactor based on bus type.
5320 */
5321 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5322 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5323
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005324 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305326 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5327 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005328 ioc->name, ioc->spi_data.minSyncFactor));
5329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 }
5331 }
5332 if (pbuf) {
5333 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5334 }
5335 }
5336 }
5337
5338 /* SCSI Port Page 2 - Read the header then the page.
5339 */
5340 header.PageVersion = 0;
5341 header.PageLength = 0;
5342 header.PageNumber = 2;
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 if (mpt_config(ioc, &cfg) != 0)
5350 return -EFAULT;
5351
5352 if (header.PageLength > 0) {
5353 /* Allocate memory and read SCSI Port Page 2
5354 */
5355 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5356 if (pbuf) {
5357 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5358 cfg.physAddr = buf_dma;
5359 if (mpt_config(ioc, &cfg) != 0) {
5360 /* Nvram data is left with INVALID mark
5361 */
5362 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005363 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5364
5365 /* This is an ATTO adapter, read Page2 accordingly
5366 */
5367 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5368 ATTODeviceInfo_t *pdevice = NULL;
5369 u16 ATTOFlags;
5370
5371 /* Save the Port Page 2 data
5372 * (reformat into a 32bit quantity)
5373 */
5374 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5375 pdevice = &pPP2->DeviceSettings[ii];
5376 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5377 data = 0;
5378
5379 /* Translate ATTO device flags to LSI format
5380 */
5381 if (ATTOFlags & ATTOFLAG_DISC)
5382 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5383 if (ATTOFlags & ATTOFLAG_ID_ENB)
5384 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5385 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5386 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5387 if (ATTOFlags & ATTOFLAG_TAGGED)
5388 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5389 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5390 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5391
5392 data = (data << 16) | (pdevice->Period << 8) | 10;
5393 ioc->spi_data.nvram[ii] = data;
5394 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 } else {
5396 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5397 MpiDeviceInfo_t *pdevice = NULL;
5398
Moore, Ericd8e925d2006-01-16 18:53:06 -07005399 /*
5400 * Save "Set to Avoid SCSI Bus Resets" flag
5401 */
5402 ioc->spi_data.bus_reset =
5403 (le32_to_cpu(pPP2->PortFlags) &
5404 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5405 0 : 1 ;
5406
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 /* Save the Port Page 2 data
5408 * (reformat into a 32bit quantity)
5409 */
5410 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5411 ioc->spi_data.PortFlags = data;
5412 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5413 pdevice = &pPP2->DeviceSettings[ii];
5414 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5415 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5416 ioc->spi_data.nvram[ii] = data;
5417 }
5418 }
5419
5420 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5421 }
5422 }
5423
5424 /* Update Adapter limits with those from NVRAM
5425 * Comment: Don't need to do this. Target performance
5426 * parameters will never exceed the adapters limits.
5427 */
5428
5429 return rc;
5430}
5431
5432/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005433/**
5434 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 * @ioc: Pointer to a Adapter Strucutre
5436 * @portnum: IOC port number
5437 *
5438 * Return: -EFAULT if read of config page header fails
5439 * or 0 if success.
5440 */
5441static int
5442mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5443{
5444 CONFIGPARMS cfg;
5445 ConfigPageHeader_t header;
5446
5447 /* Read the SCSI Device Page 1 header
5448 */
5449 header.PageVersion = 0;
5450 header.PageLength = 0;
5451 header.PageNumber = 1;
5452 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005453 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 cfg.physAddr = -1;
5455 cfg.pageAddr = portnum;
5456 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5457 cfg.dir = 0;
5458 cfg.timeout = 0;
5459 if (mpt_config(ioc, &cfg) != 0)
5460 return -EFAULT;
5461
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005462 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5463 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
5465 header.PageVersion = 0;
5466 header.PageLength = 0;
5467 header.PageNumber = 0;
5468 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5469 if (mpt_config(ioc, &cfg) != 0)
5470 return -EFAULT;
5471
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005472 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5473 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474
Prakash, Sathya436ace72007-07-24 15:42:08 +05305475 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5477
Prakash, Sathya436ace72007-07-24 15:42:08 +05305478 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5480 return 0;
5481}
5482
Eric Mooreb506ade2007-01-29 09:45:37 -07005483/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005484 * mpt_inactive_raid_list_free - This clears this link list.
5485 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005486 **/
5487static void
5488mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5489{
5490 struct inactive_raid_component_info *component_info, *pNext;
5491
5492 if (list_empty(&ioc->raid_data.inactive_list))
5493 return;
5494
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005495 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005496 list_for_each_entry_safe(component_info, pNext,
5497 &ioc->raid_data.inactive_list, list) {
5498 list_del(&component_info->list);
5499 kfree(component_info);
5500 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005501 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005502}
5503
5504/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005505 * 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 -07005506 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005507 * @ioc : pointer to per adapter structure
5508 * @channel : volume channel
5509 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005510 **/
5511static void
5512mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5513{
5514 CONFIGPARMS cfg;
5515 ConfigPageHeader_t hdr;
5516 dma_addr_t dma_handle;
5517 pRaidVolumePage0_t buffer = NULL;
5518 int i;
5519 RaidPhysDiskPage0_t phys_disk;
5520 struct inactive_raid_component_info *component_info;
5521 int handle_inactive_volumes;
5522
5523 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5524 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5525 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5526 cfg.pageAddr = (channel << 8) + id;
5527 cfg.cfghdr.hdr = &hdr;
5528 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5529
5530 if (mpt_config(ioc, &cfg) != 0)
5531 goto out;
5532
5533 if (!hdr.PageLength)
5534 goto out;
5535
5536 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5537 &dma_handle);
5538
5539 if (!buffer)
5540 goto out;
5541
5542 cfg.physAddr = dma_handle;
5543 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5544
5545 if (mpt_config(ioc, &cfg) != 0)
5546 goto out;
5547
5548 if (!buffer->NumPhysDisks)
5549 goto out;
5550
5551 handle_inactive_volumes =
5552 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5553 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5554 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5555 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5556
5557 if (!handle_inactive_volumes)
5558 goto out;
5559
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005560 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005561 for (i = 0; i < buffer->NumPhysDisks; i++) {
5562 if(mpt_raid_phys_disk_pg0(ioc,
5563 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5564 continue;
5565
5566 if ((component_info = kmalloc(sizeof (*component_info),
5567 GFP_KERNEL)) == NULL)
5568 continue;
5569
5570 component_info->volumeID = id;
5571 component_info->volumeBus = channel;
5572 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5573 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5574 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5575 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5576
5577 list_add_tail(&component_info->list,
5578 &ioc->raid_data.inactive_list);
5579 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005580 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005581
5582 out:
5583 if (buffer)
5584 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5585 dma_handle);
5586}
5587
5588/**
5589 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5590 * @ioc: Pointer to a Adapter Structure
5591 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5592 * @phys_disk: requested payload data returned
5593 *
5594 * Return:
5595 * 0 on success
5596 * -EFAULT if read of config page header fails or data pointer not NULL
5597 * -ENOMEM if pci_alloc failed
5598 **/
5599int
5600mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5601{
5602 CONFIGPARMS cfg;
5603 ConfigPageHeader_t hdr;
5604 dma_addr_t dma_handle;
5605 pRaidPhysDiskPage0_t buffer = NULL;
5606 int rc;
5607
5608 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5609 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5610
5611 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5612 cfg.cfghdr.hdr = &hdr;
5613 cfg.physAddr = -1;
5614 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5615
5616 if (mpt_config(ioc, &cfg) != 0) {
5617 rc = -EFAULT;
5618 goto out;
5619 }
5620
5621 if (!hdr.PageLength) {
5622 rc = -EFAULT;
5623 goto out;
5624 }
5625
5626 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5627 &dma_handle);
5628
5629 if (!buffer) {
5630 rc = -ENOMEM;
5631 goto out;
5632 }
5633
5634 cfg.physAddr = dma_handle;
5635 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5636 cfg.pageAddr = phys_disk_num;
5637
5638 if (mpt_config(ioc, &cfg) != 0) {
5639 rc = -EFAULT;
5640 goto out;
5641 }
5642
5643 rc = 0;
5644 memcpy(phys_disk, buffer, sizeof(*buffer));
5645 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5646
5647 out:
5648
5649 if (buffer)
5650 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5651 dma_handle);
5652
5653 return rc;
5654}
5655
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656/**
5657 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5658 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 *
5660 * Return:
5661 * 0 on success
5662 * -EFAULT if read of config page header fails or data pointer not NULL
5663 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005664 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665int
5666mpt_findImVolumes(MPT_ADAPTER *ioc)
5667{
5668 IOCPage2_t *pIoc2;
5669 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 dma_addr_t ioc2_dma;
5671 CONFIGPARMS cfg;
5672 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 int rc = 0;
5674 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005675 int i;
5676
5677 if (!ioc->ir_firmware)
5678 return 0;
5679
5680 /* Free the old page
5681 */
5682 kfree(ioc->raid_data.pIocPg2);
5683 ioc->raid_data.pIocPg2 = NULL;
5684 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685
5686 /* Read IOCP2 header then the page.
5687 */
5688 header.PageVersion = 0;
5689 header.PageLength = 0;
5690 header.PageNumber = 2;
5691 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005692 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 cfg.physAddr = -1;
5694 cfg.pageAddr = 0;
5695 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5696 cfg.dir = 0;
5697 cfg.timeout = 0;
5698 if (mpt_config(ioc, &cfg) != 0)
5699 return -EFAULT;
5700
5701 if (header.PageLength == 0)
5702 return -EFAULT;
5703
5704 iocpage2sz = header.PageLength * 4;
5705 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5706 if (!pIoc2)
5707 return -ENOMEM;
5708
5709 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5710 cfg.physAddr = ioc2_dma;
5711 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005712 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713
Eric Mooreb506ade2007-01-29 09:45:37 -07005714 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5715 if (!mem)
5716 goto out;
5717
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005719 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720
Eric Mooreb506ade2007-01-29 09:45:37 -07005721 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722
Eric Mooreb506ade2007-01-29 09:45:37 -07005723 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5724 mpt_inactive_raid_volumes(ioc,
5725 pIoc2->RaidVolume[i].VolumeBus,
5726 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727
Eric Mooreb506ade2007-01-29 09:45:37 -07005728 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5730
5731 return rc;
5732}
5733
Moore, Ericc972c702006-03-14 09:14:06 -07005734static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5736{
5737 IOCPage3_t *pIoc3;
5738 u8 *mem;
5739 CONFIGPARMS cfg;
5740 ConfigPageHeader_t header;
5741 dma_addr_t ioc3_dma;
5742 int iocpage3sz = 0;
5743
5744 /* Free the old page
5745 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005746 kfree(ioc->raid_data.pIocPg3);
5747 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748
5749 /* There is at least one physical disk.
5750 * Read and save IOC Page 3
5751 */
5752 header.PageVersion = 0;
5753 header.PageLength = 0;
5754 header.PageNumber = 3;
5755 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005756 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 cfg.physAddr = -1;
5758 cfg.pageAddr = 0;
5759 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5760 cfg.dir = 0;
5761 cfg.timeout = 0;
5762 if (mpt_config(ioc, &cfg) != 0)
5763 return 0;
5764
5765 if (header.PageLength == 0)
5766 return 0;
5767
5768 /* Read Header good, alloc memory
5769 */
5770 iocpage3sz = header.PageLength * 4;
5771 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5772 if (!pIoc3)
5773 return 0;
5774
5775 /* Read the Page and save the data
5776 * into malloc'd memory.
5777 */
5778 cfg.physAddr = ioc3_dma;
5779 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5780 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005781 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 if (mem) {
5783 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005784 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 }
5786 }
5787
5788 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5789
5790 return 0;
5791}
5792
5793static void
5794mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5795{
5796 IOCPage4_t *pIoc4;
5797 CONFIGPARMS cfg;
5798 ConfigPageHeader_t header;
5799 dma_addr_t ioc4_dma;
5800 int iocpage4sz;
5801
5802 /* Read and save IOC Page 4
5803 */
5804 header.PageVersion = 0;
5805 header.PageLength = 0;
5806 header.PageNumber = 4;
5807 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005808 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 cfg.physAddr = -1;
5810 cfg.pageAddr = 0;
5811 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5812 cfg.dir = 0;
5813 cfg.timeout = 0;
5814 if (mpt_config(ioc, &cfg) != 0)
5815 return;
5816
5817 if (header.PageLength == 0)
5818 return;
5819
5820 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5821 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5822 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5823 if (!pIoc4)
5824 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005825 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 } else {
5827 ioc4_dma = ioc->spi_data.IocPg4_dma;
5828 iocpage4sz = ioc->spi_data.IocPg4Sz;
5829 }
5830
5831 /* Read the Page into dma memory.
5832 */
5833 cfg.physAddr = ioc4_dma;
5834 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5835 if (mpt_config(ioc, &cfg) == 0) {
5836 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5837 ioc->spi_data.IocPg4_dma = ioc4_dma;
5838 ioc->spi_data.IocPg4Sz = iocpage4sz;
5839 } else {
5840 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5841 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005842 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843 }
5844}
5845
5846static void
5847mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5848{
5849 IOCPage1_t *pIoc1;
5850 CONFIGPARMS cfg;
5851 ConfigPageHeader_t header;
5852 dma_addr_t ioc1_dma;
5853 int iocpage1sz = 0;
5854 u32 tmp;
5855
5856 /* Check the Coalescing Timeout in IOC Page 1
5857 */
5858 header.PageVersion = 0;
5859 header.PageLength = 0;
5860 header.PageNumber = 1;
5861 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005862 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863 cfg.physAddr = -1;
5864 cfg.pageAddr = 0;
5865 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5866 cfg.dir = 0;
5867 cfg.timeout = 0;
5868 if (mpt_config(ioc, &cfg) != 0)
5869 return;
5870
5871 if (header.PageLength == 0)
5872 return;
5873
5874 /* Read Header good, alloc memory
5875 */
5876 iocpage1sz = header.PageLength * 4;
5877 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5878 if (!pIoc1)
5879 return;
5880
5881 /* Read the Page and check coalescing timeout
5882 */
5883 cfg.physAddr = ioc1_dma;
5884 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5885 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305886
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5888 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5889 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5890
Prakash, Sathya436ace72007-07-24 15:42:08 +05305891 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 ioc->name, tmp));
5893
5894 if (tmp > MPT_COALESCING_TIMEOUT) {
5895 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5896
5897 /* Write NVRAM and current
5898 */
5899 cfg.dir = 1;
5900 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5901 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305902 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903 ioc->name, MPT_COALESCING_TIMEOUT));
5904
5905 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5906 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305907 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5908 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909 ioc->name, MPT_COALESCING_TIMEOUT));
5910 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305911 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5912 "Reset NVRAM Coalescing Timeout Failed\n",
5913 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914 }
5915
5916 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305917 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5918 "Reset of Current Coalescing Timeout Failed!\n",
5919 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920 }
5921 }
5922
5923 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305924 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 }
5926 }
5927
5928 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5929
5930 return;
5931}
5932
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305933static void
5934mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5935{
5936 CONFIGPARMS cfg;
5937 ConfigPageHeader_t hdr;
5938 dma_addr_t buf_dma;
5939 ManufacturingPage0_t *pbuf = NULL;
5940
5941 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5942 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5943
5944 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5945 cfg.cfghdr.hdr = &hdr;
5946 cfg.physAddr = -1;
5947 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5948 cfg.timeout = 10;
5949
5950 if (mpt_config(ioc, &cfg) != 0)
5951 goto out;
5952
5953 if (!cfg.cfghdr.hdr->PageLength)
5954 goto out;
5955
5956 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5957 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5958 if (!pbuf)
5959 goto out;
5960
5961 cfg.physAddr = buf_dma;
5962
5963 if (mpt_config(ioc, &cfg) != 0)
5964 goto out;
5965
5966 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5967 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5968 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5969
5970 out:
5971
5972 if (pbuf)
5973 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5974}
5975
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005977/**
5978 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979 * @ioc: Pointer to MPT_ADAPTER structure
5980 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05305981 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 */
5983static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05305984SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985{
Kashyap, Desaifd761752009-05-29 16:39:06 +05305986 EventNotification_t evn;
5987 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988
Kashyap, Desaifd761752009-05-29 16:39:06 +05305989 memset(&evn, 0, sizeof(EventNotification_t));
5990 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991
Kashyap, Desaifd761752009-05-29 16:39:06 +05305992 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5993 evn.Switch = EvSwitch;
5994 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995
Kashyap, Desaifd761752009-05-29 16:39:06 +05305996 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5997 "Sending EventNotification (%d) request %p\n",
5998 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999
Kashyap, Desaifd761752009-05-29 16:39:06 +05306000 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6001 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6002 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003}
6004
6005/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6006/**
6007 * SendEventAck - Send EventAck request to MPT adapter.
6008 * @ioc: Pointer to MPT_ADAPTER structure
6009 * @evnp: Pointer to original EventNotification request
6010 */
6011static int
6012SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6013{
6014 EventAck_t *pAck;
6015
6016 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306017 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306018 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019 return -1;
6020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021
Prakash, Sathya436ace72007-07-24 15:42:08 +05306022 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023
6024 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6025 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006026 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006028 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029 pAck->Event = evnp->Event;
6030 pAck->EventContext = evnp->EventContext;
6031
6032 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6033
6034 return 0;
6035}
6036
6037/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6038/**
6039 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006040 * @ioc: Pointer to an adapter structure
6041 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042 * action, page address, direction, physical address
6043 * and pointer to a configuration page header
6044 * Page header is updated.
6045 *
6046 * Returns 0 for success
6047 * -EPERM if not allowed due to ISR context
6048 * -EAGAIN if no msg frames currently available
6049 * -EFAULT for non-successful reply or no reply (timeout)
6050 */
6051int
6052mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6053{
6054 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306055 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006056 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306058 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006059 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306060 long timeout;
6061 int ret;
6062 u8 page_type = 0, extend_page;
6063 unsigned long timeleft;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306065 u8 issue_hard_reset = 0;
6066 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006068 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069 * to be in ISR context, because that is fatal!
6070 */
6071 in_isr = in_interrupt();
6072 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306073 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 ioc->name));
6075 return -EPERM;
6076 }
6077
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306078 /* don't send if no chance of success */
6079 if (!ioc->active ||
6080 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6081 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6082 "%s: ioc not operational, %d, %xh\n",
6083 ioc->name, __func__, ioc->active,
6084 mpt_GetIocState(ioc, 0)));
6085 return -EFAULT;
6086 }
6087
6088 retry_config:
6089 mutex_lock(&ioc->mptbase_cmds.mutex);
6090 /* init the internal cmd struct */
6091 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6092 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6093
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 /* Get and Populate a free Frame
6095 */
6096 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306097 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6098 "mpt_config: no msg frames!\n", ioc->name));
6099 ret = -EAGAIN;
6100 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306102
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 pReq = (Config_t *)mf;
6104 pReq->Action = pCfg->action;
6105 pReq->Reserved = 0;
6106 pReq->ChainOffset = 0;
6107 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006108
6109 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006110 pReq->ExtPageLength = 0;
6111 pReq->ExtPageType = 0;
6112 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006113
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114 for (ii=0; ii < 8; ii++)
6115 pReq->Reserved2[ii] = 0;
6116
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006117 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6118 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6119 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6120 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6121
6122 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6123 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6124 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6125 pReq->ExtPageType = pExtHdr->ExtPageType;
6126 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6127
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306128 /* Page Length must be treated as a reserved field for the
6129 * extended header.
6130 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006131 pReq->Header.PageLength = 0;
6132 }
6133
Linus Torvalds1da177e2005-04-16 15:20:36 -07006134 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6135
6136 /* Add a SGE to the config request.
6137 */
6138 if (pCfg->dir)
6139 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6140 else
6141 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6142
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306143 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6144 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006145 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306146 page_type = pReq->ExtPageType;
6147 extend_page = 1;
6148 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006149 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306150 page_type = pReq->Header.PageType;
6151 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306154 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6155 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6156 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6157
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306158 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306159 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306161 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6162 timeout);
6163 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6164 ret = -ETIME;
6165 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6166 "Failed Sending Config request type 0x%x, page 0x%x,"
6167 " action %d, status %xh, time left %ld\n\n",
6168 ioc->name, page_type, pReq->Header.PageNumber,
6169 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6170 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6171 goto out;
6172 if (!timeleft)
6173 issue_hard_reset = 1;
6174 goto out;
6175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306177 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6178 ret = -1;
6179 goto out;
6180 }
6181 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6182 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6183 if (ret == MPI_IOCSTATUS_SUCCESS) {
6184 if (extend_page) {
6185 pCfg->cfghdr.ehdr->ExtPageLength =
6186 le16_to_cpu(pReply->ExtPageLength);
6187 pCfg->cfghdr.ehdr->ExtPageType =
6188 pReply->ExtPageType;
6189 }
6190 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6191 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6192 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6193 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006194
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306195 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306197 if (retry_count)
6198 printk(MYIOC_s_INFO_FMT "Retry completed "
6199 "ret=0x%x timeleft=%ld\n",
6200 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306202 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6203 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306205out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306207 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6208 mutex_unlock(&ioc->mptbase_cmds.mutex);
6209 if (issue_hard_reset) {
6210 issue_hard_reset = 0;
6211 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6212 ioc->name, __func__);
6213 mpt_HardResetHandler(ioc, CAN_SLEEP);
6214 mpt_free_msg_frame(ioc, mf);
6215 /* attempt one retry for a timed out command */
6216 if (!retry_count) {
6217 printk(MYIOC_s_INFO_FMT
6218 "Attempting Retry Config request"
6219 " type 0x%x, page 0x%x,"
6220 " action %d\n", ioc->name, page_type,
6221 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6222 retry_count++;
6223 goto retry_config;
6224 }
6225 }
6226 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228}
6229
6230/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006231/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 * mpt_ioc_reset - Base cleanup for hard reset
6233 * @ioc: Pointer to the adapter structure
6234 * @reset_phase: Indicates pre- or post-reset functionality
6235 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006236 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237 */
6238static int
6239mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6240{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306241 switch (reset_phase) {
6242 case MPT_IOC_SETUP_RESET:
6243 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6244 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6245 break;
6246 case MPT_IOC_PRE_RESET:
6247 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6248 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6249 break;
6250 case MPT_IOC_POST_RESET:
6251 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6252 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6253/* wake up mptbase_cmds */
6254 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6255 ioc->mptbase_cmds.status |=
6256 MPT_MGMT_STATUS_DID_IOCRESET;
6257 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306259 break;
6260 default:
6261 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 }
6263
6264 return 1; /* currently means nothing really */
6265}
6266
6267
6268#ifdef CONFIG_PROC_FS /* { */
6269/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6270/*
6271 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6272 */
6273/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006274/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006275 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6276 *
6277 * Returns 0 for success, non-zero for failure.
6278 */
6279static int
6280procmpt_create(void)
6281{
6282 struct proc_dir_entry *ent;
6283
6284 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6285 if (mpt_proc_root_dir == NULL)
6286 return -ENOTDIR;
6287
6288 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6289 if (ent)
6290 ent->read_proc = procmpt_summary_read;
6291
6292 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6293 if (ent)
6294 ent->read_proc = procmpt_version_read;
6295
6296 return 0;
6297}
6298
6299/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006300/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6302 *
6303 * Returns 0 for success, non-zero for failure.
6304 */
6305static void
6306procmpt_destroy(void)
6307{
6308 remove_proc_entry("version", mpt_proc_root_dir);
6309 remove_proc_entry("summary", mpt_proc_root_dir);
6310 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6311}
6312
6313/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006314/**
6315 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316 * @buf: Pointer to area to write information
6317 * @start: Pointer to start pointer
6318 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006319 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 * @eof: Pointer to EOF integer
6321 * @data: Pointer
6322 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006323 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324 * Returns number of characters written to process performing the read.
6325 */
6326static int
6327procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6328{
6329 MPT_ADAPTER *ioc;
6330 char *out = buf;
6331 int len;
6332
6333 if (data) {
6334 int more = 0;
6335
6336 ioc = data;
6337 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6338
6339 out += more;
6340 } else {
6341 list_for_each_entry(ioc, &ioc_list, list) {
6342 int more = 0;
6343
6344 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6345
6346 out += more;
6347 if ((out-buf) >= request)
6348 break;
6349 }
6350 }
6351
6352 len = out - buf;
6353
6354 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6355}
6356
6357/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006358/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359 * procmpt_version_read - Handle read request from /proc/mpt/version.
6360 * @buf: Pointer to area to write information
6361 * @start: Pointer to start pointer
6362 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006363 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 * @eof: Pointer to EOF integer
6365 * @data: Pointer
6366 *
6367 * Returns number of characters written to process performing the read.
6368 */
6369static int
6370procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6371{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306372 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006373 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374 char *drvname;
6375 int len;
6376
6377 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6378 len += sprintf(buf+len, " Fusion MPT base driver\n");
6379
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006380 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006381 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306383 if (MptCallbacks[cb_idx]) {
6384 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006385 case MPTSPI_DRIVER:
6386 if (!scsi++) drvname = "SPI host";
6387 break;
6388 case MPTFC_DRIVER:
6389 if (!fc++) drvname = "FC host";
6390 break;
6391 case MPTSAS_DRIVER:
6392 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393 break;
6394 case MPTLAN_DRIVER:
6395 if (!lan++) drvname = "LAN";
6396 break;
6397 case MPTSTM_DRIVER:
6398 if (!targ++) drvname = "SCSI target";
6399 break;
6400 case MPTCTL_DRIVER:
6401 if (!ctl++) drvname = "ioctl";
6402 break;
6403 }
6404
6405 if (drvname)
6406 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6407 }
6408 }
6409
6410 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6411}
6412
6413/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006414/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006415 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6416 * @buf: Pointer to area to write information
6417 * @start: Pointer to start pointer
6418 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006419 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420 * @eof: Pointer to EOF integer
6421 * @data: Pointer
6422 *
6423 * Returns number of characters written to process performing the read.
6424 */
6425static int
6426procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6427{
6428 MPT_ADAPTER *ioc = data;
6429 int len;
6430 char expVer[32];
6431 int sz;
6432 int p;
6433
6434 mpt_get_fw_exp_ver(expVer, ioc);
6435
6436 len = sprintf(buf, "%s:", ioc->name);
6437 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6438 len += sprintf(buf+len, " (f/w download boot flag set)");
6439// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6440// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6441
6442 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6443 ioc->facts.ProductID,
6444 ioc->prod_name);
6445 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6446 if (ioc->facts.FWImageSize)
6447 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6448 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6449 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6450 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6451
6452 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6453 ioc->facts.CurrentHostMfaHighAddr);
6454 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6455 ioc->facts.CurrentSenseBufferHighAddr);
6456
6457 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6458 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6459
6460 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6461 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6462 /*
6463 * Rounding UP to nearest 4-kB boundary here...
6464 */
6465 sz = (ioc->req_sz * ioc->req_depth) + 128;
6466 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6467 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6468 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6469 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6470 4*ioc->facts.RequestFrameSize,
6471 ioc->facts.GlobalCredits);
6472
6473 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6474 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6475 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6476 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6477 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6478 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6479 ioc->facts.CurReplyFrameSize,
6480 ioc->facts.ReplyQueueDepth);
6481
6482 len += sprintf(buf+len, " MaxDevices = %d\n",
6483 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6484 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6485
6486 /* per-port info */
6487 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6488 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6489 p+1,
6490 ioc->facts.NumberOfPorts);
6491 if (ioc->bus_type == FC) {
6492 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6493 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6494 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6495 a[5], a[4], a[3], a[2], a[1], a[0]);
6496 }
6497 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6498 ioc->fc_port_page0[p].WWNN.High,
6499 ioc->fc_port_page0[p].WWNN.Low,
6500 ioc->fc_port_page0[p].WWPN.High,
6501 ioc->fc_port_page0[p].WWPN.Low);
6502 }
6503 }
6504
6505 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6506}
6507
6508#endif /* CONFIG_PROC_FS } */
6509
6510/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6511static void
6512mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6513{
6514 buf[0] ='\0';
6515 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6516 sprintf(buf, " (Exp %02d%02d)",
6517 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6518 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6519
6520 /* insider hack! */
6521 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6522 strcat(buf, " [MDBG]");
6523 }
6524}
6525
6526/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6527/**
6528 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6529 * @ioc: Pointer to MPT_ADAPTER structure
6530 * @buffer: Pointer to buffer where IOC summary info should be written
6531 * @size: Pointer to number of bytes we wrote (set by this routine)
6532 * @len: Offset at which to start writing in buffer
6533 * @showlan: Display LAN stuff?
6534 *
6535 * This routine writes (english readable) ASCII text, which represents
6536 * a summary of IOC information, to a buffer.
6537 */
6538void
6539mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6540{
6541 char expVer[32];
6542 int y;
6543
6544 mpt_get_fw_exp_ver(expVer, ioc);
6545
6546 /*
6547 * Shorter summary of attached ioc's...
6548 */
6549 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6550 ioc->name,
6551 ioc->prod_name,
6552 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6553 ioc->facts.FWVersion.Word,
6554 expVer,
6555 ioc->facts.NumberOfPorts,
6556 ioc->req_depth);
6557
6558 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6559 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6560 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6561 a[5], a[4], a[3], a[2], a[1], a[0]);
6562 }
6563
Linus Torvalds1da177e2005-04-16 15:20:36 -07006564 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006565
6566 if (!ioc->active)
6567 y += sprintf(buffer+len+y, " (disabled)");
6568
6569 y += sprintf(buffer+len+y, "\n");
6570
6571 *size = y;
6572}
6573
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306574
6575/**
6576 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6577 * the kernel
6578 * @ioc: Pointer to MPT_ADAPTER structure
6579 *
6580 **/
6581void
6582mpt_halt_firmware(MPT_ADAPTER *ioc)
6583{
6584 u32 ioc_raw_state;
6585
6586 ioc_raw_state = mpt_GetIocState(ioc, 0);
6587
6588 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6589 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6590 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6591 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6592 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6593 } else {
6594 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6595 panic("%s: Firmware is halted due to command timeout\n",
6596 ioc->name);
6597 }
6598}
6599EXPORT_SYMBOL(mpt_halt_firmware);
6600
Linus Torvalds1da177e2005-04-16 15:20:36 -07006601/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6602/*
6603 * Reset Handling
6604 */
6605/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6606/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006607 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006608 * @ioc: Pointer to MPT_ADAPTER structure
6609 * @sleepFlag: Indicates if sleep or schedule must be called.
6610 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006611 * Issues SCSI Task Management call based on input arg values.
6612 * If TaskMgmt fails, returns associated SCSI request.
6613 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006614 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6615 * or a non-interrupt thread. In the former, must not call schedule().
6616 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006617 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006618 * FW reload/initialization failed.
6619 *
6620 * Returns 0 for SUCCESS or -1 if FAILED.
6621 */
6622int
6623mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6624{
6625 int rc;
6626 unsigned long flags;
6627
Prakash, Sathya436ace72007-07-24 15:42:08 +05306628 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006629#ifdef MFCNT
6630 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6631 printk("MF count 0x%x !\n", ioc->mfcnt);
6632#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306633 if (mpt_fwfault_debug)
6634 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006635
6636 /* Reset the adapter. Prevent more than 1 call to
6637 * mpt_do_ioc_recovery at any instant in time.
6638 */
6639 spin_lock_irqsave(&ioc->diagLock, flags);
6640 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6641 spin_unlock_irqrestore(&ioc->diagLock, flags);
6642 return 0;
6643 } else {
6644 ioc->diagPending = 1;
6645 }
6646 spin_unlock_irqrestore(&ioc->diagLock, flags);
6647
6648 /* FIXME: If do_ioc_recovery fails, repeat....
6649 */
6650
6651 /* The SCSI driver needs to adjust timeouts on all current
6652 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006653 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654 * For all other protocol drivers, this is a no-op.
6655 */
6656 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306657 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006658 int r = 0;
6659
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306660 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6661 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306662 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306663 ioc->name, cb_idx));
6664 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306666 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306667 ioc->name, ioc->alt_ioc->name, cb_idx));
6668 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669 }
6670 }
6671 }
6672 }
6673
6674 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006675 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676 }
6677 ioc->reload_fw = 0;
6678 if (ioc->alt_ioc)
6679 ioc->alt_ioc->reload_fw = 0;
6680
6681 spin_lock_irqsave(&ioc->diagLock, flags);
6682 ioc->diagPending = 0;
6683 if (ioc->alt_ioc)
6684 ioc->alt_ioc->diagPending = 0;
6685 spin_unlock_irqrestore(&ioc->diagLock, flags);
6686
Prakash, Sathya436ace72007-07-24 15:42:08 +05306687 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006688
6689 return rc;
6690}
6691
6692/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006693static void
6694EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695{
Eric Moore509e5e52006-04-26 13:22:37 -06006696 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006697
6698 switch(event) {
6699 case MPI_EVENT_NONE:
6700 ds = "None";
6701 break;
6702 case MPI_EVENT_LOG_DATA:
6703 ds = "Log Data";
6704 break;
6705 case MPI_EVENT_STATE_CHANGE:
6706 ds = "State Change";
6707 break;
6708 case MPI_EVENT_UNIT_ATTENTION:
6709 ds = "Unit Attention";
6710 break;
6711 case MPI_EVENT_IOC_BUS_RESET:
6712 ds = "IOC Bus Reset";
6713 break;
6714 case MPI_EVENT_EXT_BUS_RESET:
6715 ds = "External Bus Reset";
6716 break;
6717 case MPI_EVENT_RESCAN:
6718 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006719 break;
6720 case MPI_EVENT_LINK_STATUS_CHANGE:
6721 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6722 ds = "Link Status(FAILURE) Change";
6723 else
6724 ds = "Link Status(ACTIVE) Change";
6725 break;
6726 case MPI_EVENT_LOOP_STATE_CHANGE:
6727 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6728 ds = "Loop State(LIP) Change";
6729 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006730 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006731 else
Eric Moore509e5e52006-04-26 13:22:37 -06006732 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733 break;
6734 case MPI_EVENT_LOGOUT:
6735 ds = "Logout";
6736 break;
6737 case MPI_EVENT_EVENT_CHANGE:
6738 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006739 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006740 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006741 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742 break;
6743 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006744 {
6745 u8 ReasonCode = (u8)(evData0 >> 16);
6746 switch (ReasonCode) {
6747 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6748 ds = "Integrated Raid: Volume Created";
6749 break;
6750 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6751 ds = "Integrated Raid: Volume Deleted";
6752 break;
6753 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6754 ds = "Integrated Raid: Volume Settings Changed";
6755 break;
6756 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6757 ds = "Integrated Raid: Volume Status Changed";
6758 break;
6759 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6760 ds = "Integrated Raid: Volume Physdisk Changed";
6761 break;
6762 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6763 ds = "Integrated Raid: Physdisk Created";
6764 break;
6765 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6766 ds = "Integrated Raid: Physdisk Deleted";
6767 break;
6768 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6769 ds = "Integrated Raid: Physdisk Settings Changed";
6770 break;
6771 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6772 ds = "Integrated Raid: Physdisk Status Changed";
6773 break;
6774 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6775 ds = "Integrated Raid: Domain Validation Needed";
6776 break;
6777 case MPI_EVENT_RAID_RC_SMART_DATA :
6778 ds = "Integrated Raid; Smart Data";
6779 break;
6780 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6781 ds = "Integrated Raid: Replace Action Started";
6782 break;
6783 default:
6784 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006785 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006786 }
6787 break;
6788 }
6789 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6790 ds = "SCSI Device Status Change";
6791 break;
6792 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6793 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006794 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006795 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006796 u8 ReasonCode = (u8)(evData0 >> 16);
6797 switch (ReasonCode) {
6798 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006799 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006800 "SAS Device Status Change: Added: "
6801 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006802 break;
6803 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006804 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006805 "SAS Device Status Change: Deleted: "
6806 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006807 break;
6808 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006809 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006810 "SAS Device Status Change: SMART Data: "
6811 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006812 break;
6813 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006814 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006815 "SAS Device Status Change: No Persistancy: "
6816 "id=%d channel=%d", id, channel);
6817 break;
6818 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6819 snprintf(evStr, EVENT_DESCR_STR_SZ,
6820 "SAS Device Status Change: Unsupported Device "
6821 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006822 break;
6823 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6824 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006825 "SAS Device Status Change: Internal Device "
6826 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006827 break;
6828 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6829 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006830 "SAS Device Status Change: Internal Task "
6831 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006832 break;
6833 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6834 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006835 "SAS Device Status Change: Internal Abort "
6836 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006837 break;
6838 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6839 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006840 "SAS Device Status Change: Internal Clear "
6841 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006842 break;
6843 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6844 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006845 "SAS Device Status Change: Internal Query "
6846 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006847 break;
6848 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006849 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006850 "SAS Device Status Change: Unknown: "
6851 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006852 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006853 }
6854 break;
6855 }
6856 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6857 ds = "Bus Timer Expired";
6858 break;
6859 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006860 {
6861 u16 curr_depth = (u16)(evData0 >> 16);
6862 u8 channel = (u8)(evData0 >> 8);
6863 u8 id = (u8)(evData0);
6864
6865 snprintf(evStr, EVENT_DESCR_STR_SZ,
6866 "Queue Full: channel=%d id=%d depth=%d",
6867 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006868 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006869 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006870 case MPI_EVENT_SAS_SES:
6871 ds = "SAS SES Event";
6872 break;
6873 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6874 ds = "Persistent Table Full";
6875 break;
6876 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006877 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006878 u8 LinkRates = (u8)(evData0 >> 8);
6879 u8 PhyNumber = (u8)(evData0);
6880 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6881 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6882 switch (LinkRates) {
6883 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006884 snprintf(evStr, EVENT_DESCR_STR_SZ,
6885 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006886 " Rate Unknown",PhyNumber);
6887 break;
6888 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006889 snprintf(evStr, EVENT_DESCR_STR_SZ,
6890 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006891 " Phy Disabled",PhyNumber);
6892 break;
6893 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006894 snprintf(evStr, EVENT_DESCR_STR_SZ,
6895 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006896 " Failed Speed Nego",PhyNumber);
6897 break;
6898 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006899 snprintf(evStr, EVENT_DESCR_STR_SZ,
6900 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006901 " Sata OOB Completed",PhyNumber);
6902 break;
6903 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006904 snprintf(evStr, EVENT_DESCR_STR_SZ,
6905 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006906 " Rate 1.5 Gbps",PhyNumber);
6907 break;
6908 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006909 snprintf(evStr, EVENT_DESCR_STR_SZ,
6910 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006911 " Rate 3.0 Gpbs",PhyNumber);
6912 break;
6913 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006914 snprintf(evStr, EVENT_DESCR_STR_SZ,
6915 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006916 break;
6917 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006918 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006919 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006920 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6921 ds = "SAS Discovery Error";
6922 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006923 case MPI_EVENT_IR_RESYNC_UPDATE:
6924 {
6925 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006926 snprintf(evStr, EVENT_DESCR_STR_SZ,
6927 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006928 break;
6929 }
6930 case MPI_EVENT_IR2:
6931 {
6932 u8 ReasonCode = (u8)(evData0 >> 16);
6933 switch (ReasonCode) {
6934 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6935 ds = "IR2: LD State Changed";
6936 break;
6937 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6938 ds = "IR2: PD State Changed";
6939 break;
6940 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6941 ds = "IR2: Bad Block Table Full";
6942 break;
6943 case MPI_EVENT_IR2_RC_PD_INSERTED:
6944 ds = "IR2: PD Inserted";
6945 break;
6946 case MPI_EVENT_IR2_RC_PD_REMOVED:
6947 ds = "IR2: PD Removed";
6948 break;
6949 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6950 ds = "IR2: Foreign CFG Detected";
6951 break;
6952 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6953 ds = "IR2: Rebuild Medium Error";
6954 break;
6955 default:
6956 ds = "IR2";
6957 break;
6958 }
6959 break;
6960 }
6961 case MPI_EVENT_SAS_DISCOVERY:
6962 {
6963 if (evData0)
6964 ds = "SAS Discovery: Start";
6965 else
6966 ds = "SAS Discovery: Stop";
6967 break;
6968 }
6969 case MPI_EVENT_LOG_ENTRY_ADDED:
6970 ds = "SAS Log Entry Added";
6971 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006972
Eric Moorec6c727a2007-01-29 09:44:54 -07006973 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6974 {
6975 u8 phy_num = (u8)(evData0);
6976 u8 port_num = (u8)(evData0 >> 8);
6977 u8 port_width = (u8)(evData0 >> 16);
6978 u8 primative = (u8)(evData0 >> 24);
6979 snprintf(evStr, EVENT_DESCR_STR_SZ,
6980 "SAS Broadcase Primative: phy=%d port=%d "
6981 "width=%d primative=0x%02x",
6982 phy_num, port_num, port_width, primative);
6983 break;
6984 }
6985
6986 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6987 {
6988 u8 reason = (u8)(evData0);
6989 u8 port_num = (u8)(evData0 >> 8);
6990 u16 handle = le16_to_cpu(evData0 >> 16);
6991
6992 snprintf(evStr, EVENT_DESCR_STR_SZ,
6993 "SAS Initiator Device Status Change: reason=0x%02x "
6994 "port=%d handle=0x%04x",
6995 reason, port_num, handle);
6996 break;
6997 }
6998
6999 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7000 {
7001 u8 max_init = (u8)(evData0);
7002 u8 current_init = (u8)(evData0 >> 8);
7003
7004 snprintf(evStr, EVENT_DESCR_STR_SZ,
7005 "SAS Initiator Device Table Overflow: max initiators=%02d "
7006 "current initators=%02d",
7007 max_init, current_init);
7008 break;
7009 }
7010 case MPI_EVENT_SAS_SMP_ERROR:
7011 {
7012 u8 status = (u8)(evData0);
7013 u8 port_num = (u8)(evData0 >> 8);
7014 u8 result = (u8)(evData0 >> 16);
7015
7016 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7017 snprintf(evStr, EVENT_DESCR_STR_SZ,
7018 "SAS SMP Error: port=%d result=0x%02x",
7019 port_num, result);
7020 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7021 snprintf(evStr, EVENT_DESCR_STR_SZ,
7022 "SAS SMP Error: port=%d : CRC Error",
7023 port_num);
7024 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7025 snprintf(evStr, EVENT_DESCR_STR_SZ,
7026 "SAS SMP Error: port=%d : Timeout",
7027 port_num);
7028 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7029 snprintf(evStr, EVENT_DESCR_STR_SZ,
7030 "SAS SMP Error: port=%d : No Destination",
7031 port_num);
7032 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7033 snprintf(evStr, EVENT_DESCR_STR_SZ,
7034 "SAS SMP Error: port=%d : Bad Destination",
7035 port_num);
7036 else
7037 snprintf(evStr, EVENT_DESCR_STR_SZ,
7038 "SAS SMP Error: port=%d : status=0x%02x",
7039 port_num, status);
7040 break;
7041 }
7042
Linus Torvalds1da177e2005-04-16 15:20:36 -07007043 /*
7044 * MPT base "custom" events may be added here...
7045 */
7046 default:
7047 ds = "Unknown";
7048 break;
7049 }
Eric Moore509e5e52006-04-26 13:22:37 -06007050 if (ds)
7051 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007052}
7053
7054/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007055/**
7056 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007057 * @ioc: Pointer to MPT_ADAPTER structure
7058 * @pEventReply: Pointer to EventNotification reply frame
7059 * @evHandlers: Pointer to integer, number of event handlers
7060 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007061 * Routes a received EventNotificationReply to all currently registered
7062 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007063 * Returns sum of event handlers return values.
7064 */
7065static int
7066ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7067{
7068 u16 evDataLen;
7069 u32 evData0 = 0;
7070// u32 evCtx;
7071 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307072 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007073 int r = 0;
7074 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06007075 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007076 u8 event;
7077
7078 /*
7079 * Do platform normalization of values
7080 */
7081 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7082// evCtx = le32_to_cpu(pEventReply->EventContext);
7083 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7084 if (evDataLen) {
7085 evData0 = le32_to_cpu(pEventReply->Data[0]);
7086 }
7087
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007088 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05307089 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007090 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07007091 event,
7092 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007093
Prakash, Sathya436ace72007-07-24 15:42:08 +05307094#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06007095 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7096 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007097 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05307098 devtverboseprintk(ioc, printk(" %08x",
7099 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06007100 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101#endif
7102
7103 /*
7104 * Do general / base driver event processing
7105 */
7106 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7108 if (evDataLen) {
7109 u8 evState = evData0 & 0xFF;
7110
7111 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7112
7113 /* Update EventState field in cached IocFacts */
7114 if (ioc->facts.Function) {
7115 ioc->facts.EventState = evState;
7116 }
7117 }
7118 break;
Moore, Ericece50912006-01-16 18:53:19 -07007119 case MPI_EVENT_INTEGRATED_RAID:
7120 mptbase_raid_process_event_data(ioc,
7121 (MpiEventDataRaid_t *)pEventReply->Data);
7122 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007123 default:
7124 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007125 }
7126
7127 /*
7128 * Should this event be logged? Events are written sequentially.
7129 * When buffer is full, start again at the top.
7130 */
7131 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7132 int idx;
7133
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007134 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007135
7136 ioc->events[idx].event = event;
7137 ioc->events[idx].eventContext = ioc->eventContext;
7138
7139 for (ii = 0; ii < 2; ii++) {
7140 if (ii < evDataLen)
7141 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7142 else
7143 ioc->events[idx].data[ii] = 0;
7144 }
7145
7146 ioc->eventContext++;
7147 }
7148
7149
7150 /*
7151 * Call each currently registered protocol event handler.
7152 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007153 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307154 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307155 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307156 ioc->name, cb_idx));
7157 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007158 handlers++;
7159 }
7160 }
7161 /* FIXME? Examine results here? */
7162
7163 /*
7164 * If needed, send (a single) EventAck.
7165 */
7166 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307167 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007168 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007169 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307170 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007171 ioc->name, ii));
7172 }
7173 }
7174
7175 *evHandlers = handlers;
7176 return r;
7177}
7178
7179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007180/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007181 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7182 * @ioc: Pointer to MPT_ADAPTER structure
7183 * @log_info: U32 LogInfo reply word from the IOC
7184 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007185 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007186 */
7187static void
7188mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7189{
Eric Moore7c431e52007-06-13 16:34:36 -06007190 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007191
Eric Moore7c431e52007-06-13 16:34:36 -06007192 switch (log_info & 0xFF000000) {
7193 case MPI_IOCLOGINFO_FC_INIT_BASE:
7194 desc = "FCP Initiator";
7195 break;
7196 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7197 desc = "FCP Target";
7198 break;
7199 case MPI_IOCLOGINFO_FC_LAN_BASE:
7200 desc = "LAN";
7201 break;
7202 case MPI_IOCLOGINFO_FC_MSG_BASE:
7203 desc = "MPI Message Layer";
7204 break;
7205 case MPI_IOCLOGINFO_FC_LINK_BASE:
7206 desc = "FC Link";
7207 break;
7208 case MPI_IOCLOGINFO_FC_CTX_BASE:
7209 desc = "Context Manager";
7210 break;
7211 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7212 desc = "Invalid Field Offset";
7213 break;
7214 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7215 desc = "State Change Info";
7216 break;
7217 }
7218
7219 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7220 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007221}
7222
7223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007224/**
Moore, Eric335a9412006-01-17 17:06:23 -07007225 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007226 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227 * @log_info: U32 LogInfo word from the IOC
7228 *
7229 * Refer to lsi/sp_log.h.
7230 */
7231static void
Moore, Eric335a9412006-01-17 17:06:23 -07007232mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233{
7234 u32 info = log_info & 0x00FF0000;
7235 char *desc = "unknown";
7236
7237 switch (info) {
7238 case 0x00010000:
7239 desc = "bug! MID not found";
7240 if (ioc->reload_fw == 0)
7241 ioc->reload_fw++;
7242 break;
7243
7244 case 0x00020000:
7245 desc = "Parity Error";
7246 break;
7247
7248 case 0x00030000:
7249 desc = "ASYNC Outbound Overrun";
7250 break;
7251
7252 case 0x00040000:
7253 desc = "SYNC Offset Error";
7254 break;
7255
7256 case 0x00050000:
7257 desc = "BM Change";
7258 break;
7259
7260 case 0x00060000:
7261 desc = "Msg In Overflow";
7262 break;
7263
7264 case 0x00070000:
7265 desc = "DMA Error";
7266 break;
7267
7268 case 0x00080000:
7269 desc = "Outbound DMA Overrun";
7270 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007271
Linus Torvalds1da177e2005-04-16 15:20:36 -07007272 case 0x00090000:
7273 desc = "Task Management";
7274 break;
7275
7276 case 0x000A0000:
7277 desc = "Device Problem";
7278 break;
7279
7280 case 0x000B0000:
7281 desc = "Invalid Phase Change";
7282 break;
7283
7284 case 0x000C0000:
7285 desc = "Untagged Table Size";
7286 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007287
Linus Torvalds1da177e2005-04-16 15:20:36 -07007288 }
7289
7290 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7291}
7292
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007293/* strings for sas loginfo */
7294 static char *originator_str[] = {
7295 "IOP", /* 00h */
7296 "PL", /* 01h */
7297 "IR" /* 02h */
7298 };
7299 static char *iop_code_str[] = {
7300 NULL, /* 00h */
7301 "Invalid SAS Address", /* 01h */
7302 NULL, /* 02h */
7303 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007304 "Diag Message Error", /* 04h */
7305 "Task Terminated", /* 05h */
7306 "Enclosure Management", /* 06h */
7307 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007308 };
7309 static char *pl_code_str[] = {
7310 NULL, /* 00h */
7311 "Open Failure", /* 01h */
7312 "Invalid Scatter Gather List", /* 02h */
7313 "Wrong Relative Offset or Frame Length", /* 03h */
7314 "Frame Transfer Error", /* 04h */
7315 "Transmit Frame Connected Low", /* 05h */
7316 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7317 "SATA Read Log Receive Data Error", /* 07h */
7318 "SATA NCQ Fail All Commands After Error", /* 08h */
7319 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7320 "Receive Frame Invalid Message", /* 0Ah */
7321 "Receive Context Message Valid Error", /* 0Bh */
7322 "Receive Frame Current Frame Error", /* 0Ch */
7323 "SATA Link Down", /* 0Dh */
7324 "Discovery SATA Init W IOS", /* 0Eh */
7325 "Config Invalid Page", /* 0Fh */
7326 "Discovery SATA Init Timeout", /* 10h */
7327 "Reset", /* 11h */
7328 "Abort", /* 12h */
7329 "IO Not Yet Executed", /* 13h */
7330 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007331 "Persistent Reservation Out Not Affiliation "
7332 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007333 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007334 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007335 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007336 NULL, /* 19h */
7337 NULL, /* 1Ah */
7338 NULL, /* 1Bh */
7339 NULL, /* 1Ch */
7340 NULL, /* 1Dh */
7341 NULL, /* 1Eh */
7342 NULL, /* 1Fh */
7343 "Enclosure Management" /* 20h */
7344 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007345 static char *ir_code_str[] = {
7346 "Raid Action Error", /* 00h */
7347 NULL, /* 00h */
7348 NULL, /* 01h */
7349 NULL, /* 02h */
7350 NULL, /* 03h */
7351 NULL, /* 04h */
7352 NULL, /* 05h */
7353 NULL, /* 06h */
7354 NULL /* 07h */
7355 };
7356 static char *raid_sub_code_str[] = {
7357 NULL, /* 00h */
7358 "Volume Creation Failed: Data Passed too "
7359 "Large", /* 01h */
7360 "Volume Creation Failed: Duplicate Volumes "
7361 "Attempted", /* 02h */
7362 "Volume Creation Failed: Max Number "
7363 "Supported Volumes Exceeded", /* 03h */
7364 "Volume Creation Failed: DMA Error", /* 04h */
7365 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7366 "Volume Creation Failed: Error Reading "
7367 "MFG Page 4", /* 06h */
7368 "Volume Creation Failed: Creating Internal "
7369 "Structures", /* 07h */
7370 NULL, /* 08h */
7371 NULL, /* 09h */
7372 NULL, /* 0Ah */
7373 NULL, /* 0Bh */
7374 NULL, /* 0Ch */
7375 NULL, /* 0Dh */
7376 NULL, /* 0Eh */
7377 NULL, /* 0Fh */
7378 "Activation failed: Already Active Volume", /* 10h */
7379 "Activation failed: Unsupported Volume Type", /* 11h */
7380 "Activation failed: Too Many Active Volumes", /* 12h */
7381 "Activation failed: Volume ID in Use", /* 13h */
7382 "Activation failed: Reported Failure", /* 14h */
7383 "Activation failed: Importing a Volume", /* 15h */
7384 NULL, /* 16h */
7385 NULL, /* 17h */
7386 NULL, /* 18h */
7387 NULL, /* 19h */
7388 NULL, /* 1Ah */
7389 NULL, /* 1Bh */
7390 NULL, /* 1Ch */
7391 NULL, /* 1Dh */
7392 NULL, /* 1Eh */
7393 NULL, /* 1Fh */
7394 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7395 "Phys Disk failed: Data Passed too Large", /* 21h */
7396 "Phys Disk failed: DMA Error", /* 22h */
7397 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7398 "Phys Disk failed: Creating Phys Disk Config "
7399 "Page", /* 24h */
7400 NULL, /* 25h */
7401 NULL, /* 26h */
7402 NULL, /* 27h */
7403 NULL, /* 28h */
7404 NULL, /* 29h */
7405 NULL, /* 2Ah */
7406 NULL, /* 2Bh */
7407 NULL, /* 2Ch */
7408 NULL, /* 2Dh */
7409 NULL, /* 2Eh */
7410 NULL, /* 2Fh */
7411 "Compatibility Error: IR Disabled", /* 30h */
7412 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7413 "Compatibility Error: Device not Direct Access "
7414 "Device ", /* 32h */
7415 "Compatibility Error: Removable Device Found", /* 33h */
7416 "Compatibility Error: Device SCSI Version not "
7417 "2 or Higher", /* 34h */
7418 "Compatibility Error: SATA Device, 48 BIT LBA "
7419 "not Supported", /* 35h */
7420 "Compatibility Error: Device doesn't have "
7421 "512 Byte Block Sizes", /* 36h */
7422 "Compatibility Error: Volume Type Check Failed", /* 37h */
7423 "Compatibility Error: Volume Type is "
7424 "Unsupported by FW", /* 38h */
7425 "Compatibility Error: Disk Drive too Small for "
7426 "use in Volume", /* 39h */
7427 "Compatibility Error: Phys Disk for Create "
7428 "Volume not Found", /* 3Ah */
7429 "Compatibility Error: Too Many or too Few "
7430 "Disks for Volume Type", /* 3Bh */
7431 "Compatibility Error: Disk stripe Sizes "
7432 "Must be 64KB", /* 3Ch */
7433 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7434 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007435
7436/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007437/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007438 * mpt_sas_log_info - Log information returned from SAS IOC.
7439 * @ioc: Pointer to MPT_ADAPTER structure
7440 * @log_info: U32 LogInfo reply word from the IOC
7441 *
7442 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007443 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007444static void
7445mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7446{
7447union loginfo_type {
7448 u32 loginfo;
7449 struct {
7450 u32 subcode:16;
7451 u32 code:8;
7452 u32 originator:4;
7453 u32 bus_type:4;
7454 }dw;
7455};
7456 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007457 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007458 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007459 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007460
7461 sas_loginfo.loginfo = log_info;
7462 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007463 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007464 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007465
7466 originator_desc = originator_str[sas_loginfo.dw.originator];
7467
7468 switch (sas_loginfo.dw.originator) {
7469
7470 case 0: /* IOP */
7471 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007472 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007473 code_desc = iop_code_str[sas_loginfo.dw.code];
7474 break;
7475 case 1: /* PL */
7476 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007477 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007478 code_desc = pl_code_str[sas_loginfo.dw.code];
7479 break;
7480 case 2: /* IR */
7481 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007482 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007483 break;
7484 code_desc = ir_code_str[sas_loginfo.dw.code];
7485 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007486 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007487 break;
7488 if (sas_loginfo.dw.code == 0)
7489 sub_code_desc =
7490 raid_sub_code_str[sas_loginfo.dw.subcode];
7491 break;
7492 default:
7493 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007494 }
7495
Eric Moorec6c727a2007-01-29 09:44:54 -07007496 if (sub_code_desc != NULL)
7497 printk(MYIOC_s_INFO_FMT
7498 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7499 " SubCode={%s}\n",
7500 ioc->name, log_info, originator_desc, code_desc,
7501 sub_code_desc);
7502 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007503 printk(MYIOC_s_INFO_FMT
7504 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7505 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007506 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007507 sas_loginfo.dw.subcode);
7508 else
7509 printk(MYIOC_s_INFO_FMT
7510 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7511 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007512 ioc->name, log_info, originator_desc,
7513 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007514}
7515
Linus Torvalds1da177e2005-04-16 15:20:36 -07007516/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007517/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007518 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7519 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007520 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007521 * @mf: Pointer to MPT request frame
7522 *
7523 * Refer to lsi/mpi.h.
7524 **/
7525static void
7526mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7527{
7528 Config_t *pReq = (Config_t *)mf;
7529 char extend_desc[EVENT_DESCR_STR_SZ];
7530 char *desc = NULL;
7531 u32 form;
7532 u8 page_type;
7533
7534 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7535 page_type = pReq->ExtPageType;
7536 else
7537 page_type = pReq->Header.PageType;
7538
7539 /*
7540 * ignore invalid page messages for GET_NEXT_HANDLE
7541 */
7542 form = le32_to_cpu(pReq->PageAddress);
7543 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7544 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7545 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7546 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7547 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7548 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7549 return;
7550 }
7551 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7552 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7553 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7554 return;
7555 }
7556
7557 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7558 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7559 page_type, pReq->Header.PageNumber, pReq->Action, form);
7560
7561 switch (ioc_status) {
7562
7563 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7564 desc = "Config Page Invalid Action";
7565 break;
7566
7567 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7568 desc = "Config Page Invalid Type";
7569 break;
7570
7571 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7572 desc = "Config Page Invalid Page";
7573 break;
7574
7575 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7576 desc = "Config Page Invalid Data";
7577 break;
7578
7579 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7580 desc = "Config Page No Defaults";
7581 break;
7582
7583 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7584 desc = "Config Page Can't Commit";
7585 break;
7586 }
7587
7588 if (!desc)
7589 return;
7590
Eric Moore29dd3602007-09-14 18:46:51 -06007591 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7592 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007593}
7594
7595/**
7596 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007597 * @ioc: Pointer to MPT_ADAPTER structure
7598 * @ioc_status: U32 IOCStatus word from IOC
7599 * @mf: Pointer to MPT request frame
7600 *
7601 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007602 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007604mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605{
7606 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007607 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007608
7609 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007610
7611/****************************************************************************/
7612/* Common IOCStatus values for all replies */
7613/****************************************************************************/
7614
Linus Torvalds1da177e2005-04-16 15:20:36 -07007615 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7616 desc = "Invalid Function";
7617 break;
7618
7619 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7620 desc = "Busy";
7621 break;
7622
7623 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7624 desc = "Invalid SGL";
7625 break;
7626
7627 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7628 desc = "Internal Error";
7629 break;
7630
7631 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7632 desc = "Reserved";
7633 break;
7634
7635 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7636 desc = "Insufficient Resources";
7637 break;
7638
7639 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7640 desc = "Invalid Field";
7641 break;
7642
7643 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7644 desc = "Invalid State";
7645 break;
7646
Eric Moorec6c727a2007-01-29 09:44:54 -07007647/****************************************************************************/
7648/* Config IOCStatus values */
7649/****************************************************************************/
7650
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7652 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7653 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7654 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7655 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7656 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007657 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007658 break;
7659
Eric Moorec6c727a2007-01-29 09:44:54 -07007660/****************************************************************************/
7661/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7662/* */
7663/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7664/* */
7665/****************************************************************************/
7666
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007668 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007669 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7670 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7671 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7672 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007675 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007676 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007679 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007680 break;
7681
Eric Moorec6c727a2007-01-29 09:44:54 -07007682/****************************************************************************/
7683/* SCSI Target values */
7684/****************************************************************************/
7685
7686 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7687 desc = "Target: Priority IO";
7688 break;
7689
7690 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7691 desc = "Target: Invalid Port";
7692 break;
7693
7694 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7695 desc = "Target Invalid IO Index:";
7696 break;
7697
7698 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7699 desc = "Target: Aborted";
7700 break;
7701
7702 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7703 desc = "Target: No Conn Retryable";
7704 break;
7705
7706 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7707 desc = "Target: No Connection";
7708 break;
7709
7710 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7711 desc = "Target: Transfer Count Mismatch";
7712 break;
7713
7714 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7715 desc = "Target: STS Data not Sent";
7716 break;
7717
7718 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7719 desc = "Target: Data Offset Error";
7720 break;
7721
7722 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7723 desc = "Target: Too Much Write Data";
7724 break;
7725
7726 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7727 desc = "Target: IU Too Short";
7728 break;
7729
7730 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7731 desc = "Target: ACK NAK Timeout";
7732 break;
7733
7734 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7735 desc = "Target: Nak Received";
7736 break;
7737
7738/****************************************************************************/
7739/* Fibre Channel Direct Access values */
7740/****************************************************************************/
7741
7742 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7743 desc = "FC: Aborted";
7744 break;
7745
7746 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7747 desc = "FC: RX ID Invalid";
7748 break;
7749
7750 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7751 desc = "FC: DID Invalid";
7752 break;
7753
7754 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7755 desc = "FC: Node Logged Out";
7756 break;
7757
7758 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7759 desc = "FC: Exchange Canceled";
7760 break;
7761
7762/****************************************************************************/
7763/* LAN values */
7764/****************************************************************************/
7765
7766 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7767 desc = "LAN: Device not Found";
7768 break;
7769
7770 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7771 desc = "LAN: Device Failure";
7772 break;
7773
7774 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7775 desc = "LAN: Transmit Error";
7776 break;
7777
7778 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7779 desc = "LAN: Transmit Aborted";
7780 break;
7781
7782 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7783 desc = "LAN: Receive Error";
7784 break;
7785
7786 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7787 desc = "LAN: Receive Aborted";
7788 break;
7789
7790 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7791 desc = "LAN: Partial Packet";
7792 break;
7793
7794 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7795 desc = "LAN: Canceled";
7796 break;
7797
7798/****************************************************************************/
7799/* Serial Attached SCSI values */
7800/****************************************************************************/
7801
7802 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7803 desc = "SAS: SMP Request Failed";
7804 break;
7805
7806 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7807 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007808 break;
7809
7810 default:
7811 desc = "Others";
7812 break;
7813 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007814
7815 if (!desc)
7816 return;
7817
Eric Moore29dd3602007-09-14 18:46:51 -06007818 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7819 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007820}
7821
7822/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007823EXPORT_SYMBOL(mpt_attach);
7824EXPORT_SYMBOL(mpt_detach);
7825#ifdef CONFIG_PM
7826EXPORT_SYMBOL(mpt_resume);
7827EXPORT_SYMBOL(mpt_suspend);
7828#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007829EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007830EXPORT_SYMBOL(mpt_register);
7831EXPORT_SYMBOL(mpt_deregister);
7832EXPORT_SYMBOL(mpt_event_register);
7833EXPORT_SYMBOL(mpt_event_deregister);
7834EXPORT_SYMBOL(mpt_reset_register);
7835EXPORT_SYMBOL(mpt_reset_deregister);
7836EXPORT_SYMBOL(mpt_device_driver_register);
7837EXPORT_SYMBOL(mpt_device_driver_deregister);
7838EXPORT_SYMBOL(mpt_get_msg_frame);
7839EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307840EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007841EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007842EXPORT_SYMBOL(mpt_send_handshake_request);
7843EXPORT_SYMBOL(mpt_verify_adapter);
7844EXPORT_SYMBOL(mpt_GetIocState);
7845EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007846EXPORT_SYMBOL(mpt_HardResetHandler);
7847EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007848EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007849EXPORT_SYMBOL(mpt_alloc_fw_memory);
7850EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007851EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007852EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007853
Linus Torvalds1da177e2005-04-16 15:20:36 -07007854/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007855/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007856 * fusion_init - Fusion MPT base driver initialization routine.
7857 *
7858 * Returns 0 for success, non-zero for failure.
7859 */
7860static int __init
7861fusion_init(void)
7862{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307863 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007864
7865 show_mptmod_ver(my_NAME, my_VERSION);
7866 printk(KERN_INFO COPYRIGHT "\n");
7867
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307868 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7869 MptCallbacks[cb_idx] = NULL;
7870 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7871 MptEvHandlers[cb_idx] = NULL;
7872 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007873 }
7874
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007875 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007876 * EventNotification handling.
7877 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05307878 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007879
7880 /* Register for hard reset handling callbacks.
7881 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307882 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007883
7884#ifdef CONFIG_PROC_FS
7885 (void) procmpt_create();
7886#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007887 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007888}
7889
7890/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007891/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007892 * fusion_exit - Perform driver unload cleanup.
7893 *
7894 * This routine frees all resources associated with each MPT adapter
7895 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7896 */
7897static void __exit
7898fusion_exit(void)
7899{
7900
Linus Torvalds1da177e2005-04-16 15:20:36 -07007901 mpt_reset_deregister(mpt_base_index);
7902
7903#ifdef CONFIG_PROC_FS
7904 procmpt_destroy();
7905#endif
7906}
7907
Linus Torvalds1da177e2005-04-16 15:20:36 -07007908module_init(fusion_init);
7909module_exit(fusion_exit);