blob: 98026016a9353b1fa0358d9ae7b43cb7e8d1733f [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 -0700149static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
150
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530151/*
152 * Driver Callback Index's
153 */
154static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
155static u8 last_drv_idx;
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
158/*
159 * Forward protos...
160 */
David Howells7d12e782006-10-05 14:55:46 +0100161static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
163static 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);
193static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530194static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
196static 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);
211static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700212static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700214static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600215static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700216static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700217static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220static int __init fusion_init (void);
221static void __exit fusion_exit (void);
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223#define CHIPREG_READ32(addr) readl_relaxed(addr)
224#define CHIPREG_READ32_dmasync(addr) readl(addr)
225#define CHIPREG_WRITE32(addr,val) writel(val, addr)
226#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
227#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
228
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600229static void
230pci_disable_io_access(struct pci_dev *pdev)
231{
232 u16 command_reg;
233
234 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
235 command_reg &= ~1;
236 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
237}
238
239static void
240pci_enable_io_access(struct pci_dev *pdev)
241{
242 u16 command_reg;
243
244 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
245 command_reg |= 1;
246 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
247}
248
James Bottomleydb47c2d2007-07-28 13:40:21 -0400249static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
250{
251 int ret = param_set_int(val, kp);
252 MPT_ADAPTER *ioc;
253
254 if (ret)
255 return ret;
256
257 list_for_each_entry(ioc, &ioc_list, list)
258 ioc->debug_level = mpt_debug_level;
259 return 0;
260}
261
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530262/**
263 * mpt_get_cb_idx - obtain cb_idx for registered driver
264 * @dclass: class driver enum
265 *
266 * Returns cb_idx, or zero means it wasn't found
267 **/
268static u8
269mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
270{
271 u8 cb_idx;
272
273 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
274 if (MptDriverClass[cb_idx] == dclass)
275 return cb_idx;
276 return 0;
277}
278
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530279/**
280 * mpt_fault_reset_work - work performed on workq after ioc fault
281 * @work: input argument, used to derive ioc
282 *
283**/
284static void
285mpt_fault_reset_work(struct work_struct *work)
286{
287 MPT_ADAPTER *ioc =
288 container_of(work, MPT_ADAPTER, fault_reset_work.work);
289 u32 ioc_raw_state;
290 int rc;
291 unsigned long flags;
292
293 if (ioc->diagPending || !ioc->active)
294 goto out;
295
296 ioc_raw_state = mpt_GetIocState(ioc, 0);
297 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
298 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700299 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530300 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700301 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530302 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
303 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700304 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530305 ioc_raw_state = mpt_GetIocState(ioc, 0);
306 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
307 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
308 "reset (%04xh)\n", ioc->name, ioc_raw_state &
309 MPI_DOORBELL_DATA_MASK);
310 }
311
312 out:
313 /*
314 * Take turns polling alternate controller
315 */
316 if (ioc->alt_ioc)
317 ioc = ioc->alt_ioc;
318
319 /* rearm the timer */
320 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
321 if (ioc->reset_work_q)
322 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
323 msecs_to_jiffies(MPT_POLLING_INTERVAL));
324 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
325}
326
327
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600328/*
329 * Process turbo (context) reply...
330 */
331static void
332mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
333{
334 MPT_FRAME_HDR *mf = NULL;
335 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530336 u16 req_idx = 0;
337 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600338
Prakash, Sathya436ace72007-07-24 15:42:08 +0530339 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600340 ioc->name, pa));
341
342 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
343 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
344 req_idx = pa & 0x0000FFFF;
345 cb_idx = (pa & 0x00FF0000) >> 16;
346 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
347 break;
348 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530349 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600350 /*
351 * Blind set of mf to NULL here was fatal
352 * after lan_reply says "freeme"
353 * Fix sort of combined with an optimization here;
354 * added explicit check for case where lan_reply
355 * was just returning 1 and doing nothing else.
356 * For this case skip the callback, but set up
357 * proper mf value first here:-)
358 */
359 if ((pa & 0x58000000) == 0x58000000) {
360 req_idx = pa & 0x0000FFFF;
361 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
362 mpt_free_msg_frame(ioc, mf);
363 mb();
364 return;
365 break;
366 }
367 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
368 break;
369 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530370 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600371 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
372 break;
373 default:
374 cb_idx = 0;
375 BUG();
376 }
377
378 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530379 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600380 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600381 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700382 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600383 goto out;
384 }
385
386 if (MptCallbacks[cb_idx](ioc, mf, mr))
387 mpt_free_msg_frame(ioc, mf);
388 out:
389 mb();
390}
391
392static void
393mpt_reply(MPT_ADAPTER *ioc, u32 pa)
394{
395 MPT_FRAME_HDR *mf;
396 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530397 u16 req_idx;
398 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600399 int freeme;
400
401 u32 reply_dma_low;
402 u16 ioc_stat;
403
404 /* non-TURBO reply! Hmmm, something may be up...
405 * Newest turbo reply mechanism; get address
406 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
407 */
408
409 /* Map DMA address of reply header to cpu address.
410 * pa is 32 bits - but the dma address may be 32 or 64 bits
411 * get offset based only only the low addresses
412 */
413
414 reply_dma_low = (pa <<= 1);
415 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
416 (reply_dma_low - ioc->reply_frames_low_dma));
417
418 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
419 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
420 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
421
Prakash, Sathya436ace72007-07-24 15:42:08 +0530422 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 -0600423 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600424 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600425
426 /* Check/log IOC log info
427 */
428 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
429 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
430 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
431 if (ioc->bus_type == FC)
432 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700433 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700434 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600435 else if (ioc->bus_type == SAS)
436 mpt_sas_log_info(ioc, log_info);
437 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600438
Eric Moorec6c727a2007-01-29 09:44:54 -0700439 if (ioc_stat & MPI_IOCSTATUS_MASK)
440 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600441
442 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530443 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600444 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600445 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700446 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600447 freeme = 0;
448 goto out;
449 }
450
451 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
452
453 out:
454 /* Flush (non-TURBO) reply with a WRITE! */
455 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
456
457 if (freeme)
458 mpt_free_msg_frame(ioc, mf);
459 mb();
460}
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800463/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
465 * @irq: irq number (not used)
466 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 *
468 * This routine is registered via the request_irq() kernel API call,
469 * and handles all interrupts generated from a specific MPT adapter
470 * (also referred to as a IO Controller or IOC).
471 * This routine must clear the interrupt from the adapter and does
472 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200473 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 *
475 * This routine handles register-level access of the adapter but
476 * dispatches (calls) a protocol-specific callback routine to handle
477 * the protocol-specific details of the MPT request completion.
478 */
479static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100480mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600482 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600483 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
484
485 if (pa == 0xFFFFFFFF)
486 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 /*
489 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600491 do {
492 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600493 mpt_reply(ioc, pa);
494 else
495 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600496 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
497 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 return IRQ_HANDLED;
500}
501
502/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800503/**
504 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 * @ioc: Pointer to MPT_ADAPTER structure
506 * @mf: Pointer to original MPT request frame
507 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
508 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800509 * MPT base driver's callback routine; all base driver
510 * "internal" request/reply processing is routed here.
511 * Currently used for EventNotification and EventAck handling.
512 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200513 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 * should be freed, or 0 if it shouldn't.
515 */
516static int
517mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
518{
519 int freereq = 1;
520 u8 func;
521
Prakash, Sathya436ace72007-07-24 15:42:08 +0530522 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
523#ifdef CONFIG_FUSION_LOGGING
524 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
525 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600526 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
527 ioc->name, mf));
528 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200530#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530533 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 ioc->name, func));
535
536 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
537 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
538 int evHandlers = 0;
539 int results;
540
541 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
542 if (results != evHandlers) {
543 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530544 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 ioc->name, evHandlers, results));
546 }
547
548 /*
549 * Hmmm... It seems that EventNotificationReply is an exception
550 * to the rule of one reply per request.
551 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200552 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200554 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530555 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200556 ioc->name, pEvReply));
557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
559#ifdef CONFIG_PROC_FS
560// LogEvent(ioc, pEvReply);
561#endif
562
563 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530564 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700566 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 CONFIGPARMS *pCfg;
568 unsigned long flags;
569
Prakash, Sathya436ace72007-07-24 15:42:08 +0530570 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 ioc->name, mf, reply));
572
573 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
574
575 if (pCfg) {
576 /* disable timer and remove from linked list */
577 del_timer(&pCfg->timer);
578
579 spin_lock_irqsave(&ioc->FreeQlock, flags);
580 list_del(&pCfg->linkage);
581 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
582
583 /*
584 * If IOC Status is SUCCESS, save the header
585 * and set the status code to GOOD.
586 */
587 pCfg->status = MPT_CONFIG_ERROR;
588 if (reply) {
589 ConfigReply_t *pReply = (ConfigReply_t *)reply;
590 u16 status;
591
592 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600593 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
594 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 pCfg->status = status;
597 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200598 if ((pReply->Header.PageType &
599 MPI_CONFIG_PAGETYPE_MASK) ==
600 MPI_CONFIG_PAGETYPE_EXTENDED) {
601 pCfg->cfghdr.ehdr->ExtPageLength =
602 le16_to_cpu(pReply->ExtPageLength);
603 pCfg->cfghdr.ehdr->ExtPageType =
604 pReply->ExtPageType;
605 }
606 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
607
608 /* If this is a regular header, save PageLength. */
609 /* LMP Do this better so not using a reserved field! */
610 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
611 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
612 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
614 }
615
616 /*
617 * Wake up the original calling thread
618 */
619 pCfg->wait_done = 1;
620 wake_up(&mpt_waitq);
621 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200622 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
623 /* we should be always getting a reply frame */
624 memcpy(ioc->persist_reply_frame, reply,
625 min(MPT_DEFAULT_FRAME_SIZE,
626 4*reply->u.reply.MsgLength));
627 del_timer(&ioc->persist_timer);
628 ioc->persist_wait_done = 1;
629 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 } else {
631 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
632 ioc->name, func);
633 }
634
635 /*
636 * Conditionally tell caller to free the original
637 * EventNotification/EventAck/unexpected request frame!
638 */
639 return freereq;
640}
641
642/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
643/**
644 * mpt_register - Register protocol-specific main callback handler.
645 * @cbfunc: callback function pointer
646 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
647 *
648 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800649 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 * protocol-specific driver must do this before it will be able to
651 * use any IOC resources, such as obtaining request frames.
652 *
653 * NOTES: The SCSI protocol driver currently calls this routine thrice
654 * in order to register separate callbacks; one for "normal" SCSI IO;
655 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
656 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530657 * Returns u8 valued "handle" in the range (and S.O.D. order)
658 * {N,...,7,6,5,...,1} if successful.
659 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
660 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530662u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
664{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530665 u8 cb_idx;
666 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668 /*
669 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
670 * (slot/handle 0 is reserved!)
671 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530672 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
673 if (MptCallbacks[cb_idx] == NULL) {
674 MptCallbacks[cb_idx] = cbfunc;
675 MptDriverClass[cb_idx] = dclass;
676 MptEvHandlers[cb_idx] = NULL;
677 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 break;
679 }
680 }
681
682 return last_drv_idx;
683}
684
685/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
686/**
687 * mpt_deregister - Deregister a protocol drivers resources.
688 * @cb_idx: previously registered callback handle
689 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800690 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 * module is unloaded.
692 */
693void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530694mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600696 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 MptCallbacks[cb_idx] = NULL;
698 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
699 MptEvHandlers[cb_idx] = NULL;
700
701 last_drv_idx++;
702 }
703}
704
705/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
706/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800707 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 * @cb_idx: previously registered (via mpt_register) callback handle
709 * @ev_cbfunc: callback function
710 *
711 * This routine can be called by one or more protocol-specific drivers
712 * if/when they choose to be notified of MPT events.
713 *
714 * Returns 0 for success.
715 */
716int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530717mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600719 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return -1;
721
722 MptEvHandlers[cb_idx] = ev_cbfunc;
723 return 0;
724}
725
726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
727/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800728 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 * @cb_idx: previously registered callback handle
730 *
731 * Each protocol-specific driver should call this routine
732 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800733 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 */
735void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530736mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600738 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return;
740
741 MptEvHandlers[cb_idx] = NULL;
742}
743
744/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
745/**
746 * mpt_reset_register - Register protocol-specific IOC reset handler.
747 * @cb_idx: previously registered (via mpt_register) callback handle
748 * @reset_func: reset function
749 *
750 * This routine can be called by one or more protocol-specific drivers
751 * if/when they choose to be notified of IOC resets.
752 *
753 * Returns 0 for success.
754 */
755int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530756mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530758 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return -1;
760
761 MptResetHandlers[cb_idx] = reset_func;
762 return 0;
763}
764
765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
766/**
767 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
768 * @cb_idx: previously registered callback handle
769 *
770 * Each protocol-specific driver should call this routine
771 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800772 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 */
774void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530775mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530777 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return;
779
780 MptResetHandlers[cb_idx] = NULL;
781}
782
783/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
784/**
785 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800786 * @dd_cbfunc: driver callbacks struct
787 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 */
789int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530790mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
792 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600793 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Eric Moore8d6d83e2007-09-14 18:47:40 -0600795 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400796 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
799
800 /* call per pci device probe entry point */
801 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600802 id = ioc->pcidev->driver ?
803 ioc->pcidev->driver->id_table : NULL;
804 if (dd_cbfunc->probe)
805 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
807
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400808 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
811/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
812/**
813 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800814 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 */
816void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530817mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
819 struct mpt_pci_driver *dd_cbfunc;
820 MPT_ADAPTER *ioc;
821
Eric Moore8d6d83e2007-09-14 18:47:40 -0600822 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 return;
824
825 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
826
827 list_for_each_entry(ioc, &ioc_list, list) {
828 if (dd_cbfunc->remove)
829 dd_cbfunc->remove(ioc->pcidev);
830 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 MptDeviceDriverHandlers[cb_idx] = NULL;
833}
834
835
836/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
837/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800838 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530839 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 * @ioc: Pointer to MPT adapter structure
841 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800842 * Obtain an MPT request frame from the pool (of 1024) that are
843 * allocated per MPT adapter.
844 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 * Returns pointer to a MPT request frame or %NULL if none are available
846 * or IOC is not active.
847 */
848MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530849mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850{
851 MPT_FRAME_HDR *mf;
852 unsigned long flags;
853 u16 req_idx; /* Request index */
854
855 /* validate handle and ioc identifier */
856
857#ifdef MFCNT
858 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600859 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
860 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861#endif
862
863 /* If interrupts are not attached, do not return a request frame */
864 if (!ioc->active)
865 return NULL;
866
867 spin_lock_irqsave(&ioc->FreeQlock, flags);
868 if (!list_empty(&ioc->FreeQ)) {
869 int req_offset;
870
871 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
872 u.frame.linkage.list);
873 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200874 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530875 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
877 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500878 req_idx = req_offset / ioc->req_sz;
879 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600881 /* Default, will be changed if necessary in SG generation */
882 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883#ifdef MFCNT
884 ioc->mfcnt++;
885#endif
886 }
887 else
888 mf = NULL;
889 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
890
891#ifdef MFCNT
892 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600893 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
894 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
895 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 mfcounter++;
897 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600898 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
899 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900#endif
901
Eric Moore29dd3602007-09-14 18:46:51 -0600902 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
903 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 return mf;
905}
906
907/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
908/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800909 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530910 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 * @ioc: Pointer to MPT adapter structure
912 * @mf: Pointer to MPT request frame
913 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800914 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 * specific MPT adapter.
916 */
917void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530918mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
920 u32 mf_dma_addr;
921 int req_offset;
922 u16 req_idx; /* Request index */
923
924 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530925 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
927 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500928 req_idx = req_offset / ioc->req_sz;
929 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
931
Prakash, Sathya436ace72007-07-24 15:42:08 +0530932 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200934 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600935 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
936 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
937 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
939}
940
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530941/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800942 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530943 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530944 * @ioc: Pointer to MPT adapter structure
945 * @mf: Pointer to MPT request frame
946 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800947 * Send a protocol-specific MPT request frame to an IOC using
948 * hi-priority request queue.
949 *
950 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530951 * specific MPT adapter.
952 **/
953void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530954mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530955{
956 u32 mf_dma_addr;
957 int req_offset;
958 u16 req_idx; /* Request index */
959
960 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530961 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530962 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
963 req_idx = req_offset / ioc->req_sz;
964 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
965 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
966
967 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
968
969 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
970 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
971 ioc->name, mf_dma_addr, req_idx));
972 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
973}
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
976/**
977 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 * @ioc: Pointer to MPT adapter structure
979 * @mf: Pointer to MPT request frame
980 *
981 * This routine places a MPT request frame back on the MPT adapter's
982 * FreeQ.
983 */
984void
985mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
986{
987 unsigned long flags;
988
989 /* Put Request back on FreeQ! */
990 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200991 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
993#ifdef MFCNT
994 ioc->mfcnt--;
995#endif
996 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
997}
998
999/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1000/**
1001 * mpt_add_sge - Place a simple SGE at address pAddr.
1002 * @pAddr: virtual address for SGE
1003 * @flagslength: SGE flags and data transfer length
1004 * @dma_addr: Physical address
1005 *
1006 * This routine places a MPT request frame back on the MPT adapter's
1007 * FreeQ.
1008 */
1009void
1010mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
1011{
1012 if (sizeof(dma_addr_t) == sizeof(u64)) {
1013 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1014 u32 tmp = dma_addr & 0xFFFFFFFF;
1015
1016 pSge->FlagsLength = cpu_to_le32(flagslength);
1017 pSge->Address.Low = cpu_to_le32(tmp);
1018 tmp = (u32) ((u64)dma_addr >> 32);
1019 pSge->Address.High = cpu_to_le32(tmp);
1020
1021 } else {
1022 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1023 pSge->FlagsLength = cpu_to_le32(flagslength);
1024 pSge->Address = cpu_to_le32(dma_addr);
1025 }
1026}
1027
1028/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1029/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001030 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301031 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 * @ioc: Pointer to MPT adapter structure
1033 * @reqBytes: Size of the request in bytes
1034 * @req: Pointer to MPT request frame
1035 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1036 *
1037 * This routine is used exclusively to send MptScsiTaskMgmt
1038 * requests since they are required to be sent via doorbell handshake.
1039 *
1040 * NOTE: It is the callers responsibility to byte-swap fields in the
1041 * request which are greater than 1 byte in size.
1042 *
1043 * Returns 0 for success, non-zero for failure.
1044 */
1045int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301046mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047{
Eric Moorecd2c6192007-01-29 09:47:47 -07001048 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 u8 *req_as_bytes;
1050 int ii;
1051
1052 /* State is known to be good upon entering
1053 * this function so issue the bus reset
1054 * request.
1055 */
1056
1057 /*
1058 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1059 * setting cb_idx/req_idx. But ONLY if this request
1060 * is in proper (pre-alloc'd) request buffer range...
1061 */
1062 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1063 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1064 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1065 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301066 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 }
1068
1069 /* Make sure there are no doorbells */
1070 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1073 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1074 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1075
1076 /* Wait for IOC doorbell int */
1077 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1078 return ii;
1079 }
1080
1081 /* Read doorbell and check for active bit */
1082 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1083 return -5;
1084
Eric Moore29dd3602007-09-14 18:46:51 -06001085 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001086 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
1088 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1089
1090 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1091 return -2;
1092 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 /* Send request via doorbell handshake */
1095 req_as_bytes = (u8 *) req;
1096 for (ii = 0; ii < reqBytes/4; ii++) {
1097 u32 word;
1098
1099 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1100 (req_as_bytes[(ii*4) + 1] << 8) |
1101 (req_as_bytes[(ii*4) + 2] << 16) |
1102 (req_as_bytes[(ii*4) + 3] << 24));
1103 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1104 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1105 r = -3;
1106 break;
1107 }
1108 }
1109
1110 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1111 r = 0;
1112 else
1113 r = -4;
1114
1115 /* Make sure there are no doorbells */
1116 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 return r;
1119}
1120
1121/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1122/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001123 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001124 * @ioc: Pointer to MPT adapter structure
1125 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001126 * @sleepFlag: Specifies whether the process can sleep
1127 *
1128 * Provides mechanism for the host driver to control the IOC's
1129 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001130 *
1131 * Access Control Value - bits[15:12]
1132 * 0h Reserved
1133 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1134 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1135 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1136 *
1137 * Returns 0 for success, non-zero for failure.
1138 */
1139
1140static int
1141mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1142{
1143 int r = 0;
1144
1145 /* return if in use */
1146 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1147 & MPI_DOORBELL_ACTIVE)
1148 return -1;
1149
1150 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1151
1152 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1153 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1154 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1155 (access_control_value<<12)));
1156
1157 /* Wait for IOC to clear Doorbell Status bit */
1158 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1159 return -2;
1160 }else
1161 return 0;
1162}
1163
1164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1165/**
1166 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001167 * @ioc: Pointer to pointer to IOC adapter
1168 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001169 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001170 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001171 * Returns 0 for success, non-zero for failure.
1172 */
1173static int
1174mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1175{
1176 char *psge;
1177 int flags_length;
1178 u32 host_page_buffer_sz=0;
1179
1180 if(!ioc->HostPageBuffer) {
1181
1182 host_page_buffer_sz =
1183 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1184
1185 if(!host_page_buffer_sz)
1186 return 0; /* fw doesn't need any host buffers */
1187
1188 /* spin till we get enough memory */
1189 while(host_page_buffer_sz > 0) {
1190
1191 if((ioc->HostPageBuffer = pci_alloc_consistent(
1192 ioc->pcidev,
1193 host_page_buffer_sz,
1194 &ioc->HostPageBuffer_dma)) != NULL) {
1195
Prakash, Sathya436ace72007-07-24 15:42:08 +05301196 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001197 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001198 ioc->name, ioc->HostPageBuffer,
1199 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001200 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001201 ioc->alloc_total += host_page_buffer_sz;
1202 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1203 break;
1204 }
1205
1206 host_page_buffer_sz -= (4*1024);
1207 }
1208 }
1209
1210 if(!ioc->HostPageBuffer) {
1211 printk(MYIOC_s_ERR_FMT
1212 "Failed to alloc memory for host_page_buffer!\n",
1213 ioc->name);
1214 return -999;
1215 }
1216
1217 psge = (char *)&ioc_init->HostPageBufferSGE;
1218 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1219 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1220 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1221 MPI_SGE_FLAGS_HOST_TO_IOC |
1222 MPI_SGE_FLAGS_END_OF_BUFFER;
1223 if (sizeof(dma_addr_t) == sizeof(u64)) {
1224 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1225 }
1226 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1227 flags_length |= ioc->HostPageBuffer_sz;
1228 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1229 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1230
1231return 0;
1232}
1233
1234/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1235/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001236 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 * @iocid: IOC unique identifier (integer)
1238 * @iocpp: Pointer to pointer to IOC adapter
1239 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001240 * Given a unique IOC identifier, set pointer to the associated MPT
1241 * adapter structure.
1242 *
1243 * Returns iocid and sets iocpp if iocid is found.
1244 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 */
1246int
1247mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1248{
1249 MPT_ADAPTER *ioc;
1250
1251 list_for_each_entry(ioc,&ioc_list,list) {
1252 if (ioc->id == iocid) {
1253 *iocpp =ioc;
1254 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 *iocpp = NULL;
1259 return -1;
1260}
1261
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301262/**
1263 * mpt_get_product_name - returns product string
1264 * @vendor: pci vendor id
1265 * @device: pci device id
1266 * @revision: pci revision id
1267 * @prod_name: string returned
1268 *
1269 * Returns product string displayed when driver loads,
1270 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1271 *
1272 **/
1273static void
1274mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1275{
1276 char *product_str = NULL;
1277
1278 if (vendor == PCI_VENDOR_ID_BROCADE) {
1279 switch (device)
1280 {
1281 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1282 switch (revision)
1283 {
1284 case 0x00:
1285 product_str = "BRE040 A0";
1286 break;
1287 case 0x01:
1288 product_str = "BRE040 A1";
1289 break;
1290 default:
1291 product_str = "BRE040";
1292 break;
1293 }
1294 break;
1295 }
1296 goto out;
1297 }
1298
1299 switch (device)
1300 {
1301 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1302 product_str = "LSIFC909 B1";
1303 break;
1304 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1305 product_str = "LSIFC919 B0";
1306 break;
1307 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1308 product_str = "LSIFC929 B0";
1309 break;
1310 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1311 if (revision < 0x80)
1312 product_str = "LSIFC919X A0";
1313 else
1314 product_str = "LSIFC919XL A1";
1315 break;
1316 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1317 if (revision < 0x80)
1318 product_str = "LSIFC929X A0";
1319 else
1320 product_str = "LSIFC929XL A1";
1321 break;
1322 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1323 product_str = "LSIFC939X A1";
1324 break;
1325 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1326 product_str = "LSIFC949X A1";
1327 break;
1328 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1329 switch (revision)
1330 {
1331 case 0x00:
1332 product_str = "LSIFC949E A0";
1333 break;
1334 case 0x01:
1335 product_str = "LSIFC949E A1";
1336 break;
1337 default:
1338 product_str = "LSIFC949E";
1339 break;
1340 }
1341 break;
1342 case MPI_MANUFACTPAGE_DEVID_53C1030:
1343 switch (revision)
1344 {
1345 case 0x00:
1346 product_str = "LSI53C1030 A0";
1347 break;
1348 case 0x01:
1349 product_str = "LSI53C1030 B0";
1350 break;
1351 case 0x03:
1352 product_str = "LSI53C1030 B1";
1353 break;
1354 case 0x07:
1355 product_str = "LSI53C1030 B2";
1356 break;
1357 case 0x08:
1358 product_str = "LSI53C1030 C0";
1359 break;
1360 case 0x80:
1361 product_str = "LSI53C1030T A0";
1362 break;
1363 case 0x83:
1364 product_str = "LSI53C1030T A2";
1365 break;
1366 case 0x87:
1367 product_str = "LSI53C1030T A3";
1368 break;
1369 case 0xc1:
1370 product_str = "LSI53C1020A A1";
1371 break;
1372 default:
1373 product_str = "LSI53C1030";
1374 break;
1375 }
1376 break;
1377 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1378 switch (revision)
1379 {
1380 case 0x03:
1381 product_str = "LSI53C1035 A2";
1382 break;
1383 case 0x04:
1384 product_str = "LSI53C1035 B0";
1385 break;
1386 default:
1387 product_str = "LSI53C1035";
1388 break;
1389 }
1390 break;
1391 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1392 switch (revision)
1393 {
1394 case 0x00:
1395 product_str = "LSISAS1064 A1";
1396 break;
1397 case 0x01:
1398 product_str = "LSISAS1064 A2";
1399 break;
1400 case 0x02:
1401 product_str = "LSISAS1064 A3";
1402 break;
1403 case 0x03:
1404 product_str = "LSISAS1064 A4";
1405 break;
1406 default:
1407 product_str = "LSISAS1064";
1408 break;
1409 }
1410 break;
1411 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1412 switch (revision)
1413 {
1414 case 0x00:
1415 product_str = "LSISAS1064E A0";
1416 break;
1417 case 0x01:
1418 product_str = "LSISAS1064E B0";
1419 break;
1420 case 0x02:
1421 product_str = "LSISAS1064E B1";
1422 break;
1423 case 0x04:
1424 product_str = "LSISAS1064E B2";
1425 break;
1426 case 0x08:
1427 product_str = "LSISAS1064E B3";
1428 break;
1429 default:
1430 product_str = "LSISAS1064E";
1431 break;
1432 }
1433 break;
1434 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1435 switch (revision)
1436 {
1437 case 0x00:
1438 product_str = "LSISAS1068 A0";
1439 break;
1440 case 0x01:
1441 product_str = "LSISAS1068 B0";
1442 break;
1443 case 0x02:
1444 product_str = "LSISAS1068 B1";
1445 break;
1446 default:
1447 product_str = "LSISAS1068";
1448 break;
1449 }
1450 break;
1451 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1452 switch (revision)
1453 {
1454 case 0x00:
1455 product_str = "LSISAS1068E A0";
1456 break;
1457 case 0x01:
1458 product_str = "LSISAS1068E B0";
1459 break;
1460 case 0x02:
1461 product_str = "LSISAS1068E B1";
1462 break;
1463 case 0x04:
1464 product_str = "LSISAS1068E B2";
1465 break;
1466 case 0x08:
1467 product_str = "LSISAS1068E B3";
1468 break;
1469 default:
1470 product_str = "LSISAS1068E";
1471 break;
1472 }
1473 break;
1474 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1475 switch (revision)
1476 {
1477 case 0x00:
1478 product_str = "LSISAS1078 A0";
1479 break;
1480 case 0x01:
1481 product_str = "LSISAS1078 B0";
1482 break;
1483 case 0x02:
1484 product_str = "LSISAS1078 C0";
1485 break;
1486 case 0x03:
1487 product_str = "LSISAS1078 C1";
1488 break;
1489 case 0x04:
1490 product_str = "LSISAS1078 C2";
1491 break;
1492 default:
1493 product_str = "LSISAS1078";
1494 break;
1495 }
1496 break;
1497 }
1498
1499 out:
1500 if (product_str)
1501 sprintf(prod_name, "%s", product_str);
1502}
1503
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301504/**
1505 * mpt_mapresources - map in memory mapped io
1506 * @ioc: Pointer to pointer to IOC adapter
1507 *
1508 **/
1509static int
1510mpt_mapresources(MPT_ADAPTER *ioc)
1511{
1512 u8 __iomem *mem;
1513 int ii;
1514 unsigned long mem_phys;
1515 unsigned long port;
1516 u32 msize;
1517 u32 psize;
1518 u8 revision;
1519 int r = -ENODEV;
1520 struct pci_dev *pdev;
1521
1522 pdev = ioc->pcidev;
1523 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1524 if (pci_enable_device_mem(pdev)) {
1525 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1526 "failed\n", ioc->name);
1527 return r;
1528 }
1529 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1530 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1531 "MEM failed\n", ioc->name);
1532 return r;
1533 }
1534
1535 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1536
Yang Hongyang6a355282009-04-06 19:01:13 -07001537 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1538 && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301539 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1540 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1541 ioc->name));
1542 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
1543 && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
1544 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1545 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1546 ioc->name));
1547 } else {
1548 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1549 ioc->name, pci_name(pdev));
1550 pci_release_selected_regions(pdev, ioc->bars);
1551 return r;
1552 }
1553
1554 mem_phys = msize = 0;
1555 port = psize = 0;
1556 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1557 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1558 if (psize)
1559 continue;
1560 /* Get I/O space! */
1561 port = pci_resource_start(pdev, ii);
1562 psize = pci_resource_len(pdev, ii);
1563 } else {
1564 if (msize)
1565 continue;
1566 /* Get memmap */
1567 mem_phys = pci_resource_start(pdev, ii);
1568 msize = pci_resource_len(pdev, ii);
1569 }
1570 }
1571 ioc->mem_size = msize;
1572
1573 mem = NULL;
1574 /* Get logical ptr for PciMem0 space */
1575 /*mem = ioremap(mem_phys, msize);*/
1576 mem = ioremap(mem_phys, msize);
1577 if (mem == NULL) {
1578 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1579 " memory!\n", ioc->name);
1580 return -EINVAL;
1581 }
1582 ioc->memmap = mem;
1583 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1584 ioc->name, mem, mem_phys));
1585
1586 ioc->mem_phys = mem_phys;
1587 ioc->chip = (SYSIF_REGS __iomem *)mem;
1588
1589 /* Save Port IO values in case we need to do downloadboot */
1590 ioc->pio_mem_phys = port;
1591 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1592
1593 return 0;
1594}
1595
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001597/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001598 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001600 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 *
1602 * This routine performs all the steps necessary to bring the IOC of
1603 * a MPT adapter to a OPERATIONAL state. This includes registering
1604 * memory regions, registering the interrupt, and allocating request
1605 * and reply memory pools.
1606 *
1607 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1608 * MPT adapter.
1609 *
1610 * Returns 0 for success, non-zero for failure.
1611 *
1612 * TODO: Add support for polled controllers
1613 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001614int
1615mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616{
1617 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301618 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 u8 revision;
1621 u8 pcixcmd;
1622 static int mpt_ids = 0;
1623#ifdef CONFIG_PROC_FS
1624 struct proc_dir_entry *dent, *ent;
1625#endif
1626
Jesper Juhl56876192007-08-10 14:50:51 -07001627 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1628 if (ioc == NULL) {
1629 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1630 return -ENOMEM;
1631 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301632
Eric Moore29dd3602007-09-14 18:46:51 -06001633 ioc->id = mpt_ids++;
1634 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001635
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301636 /*
1637 * set initial debug level
1638 * (refer to mptdebug.h)
1639 *
1640 */
1641 ioc->debug_level = mpt_debug_level;
1642 if (mpt_debug_level)
1643 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301644
Eric Moore29dd3602007-09-14 18:46:51 -06001645 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001646
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301647 ioc->pcidev = pdev;
1648 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001649 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 return r;
1651 }
1652
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 ioc->alloc_total = sizeof(MPT_ADAPTER);
1654 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1655 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001656
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 ioc->pcidev = pdev;
1658 ioc->diagPending = 0;
1659 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001660 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 /* Initialize the event logging.
1663 */
1664 ioc->eventTypes = 0; /* None */
1665 ioc->eventContext = 0;
1666 ioc->eventLogSize = 0;
1667 ioc->events = NULL;
1668
1669#ifdef MFCNT
1670 ioc->mfcnt = 0;
1671#endif
1672
1673 ioc->cached_fw = NULL;
1674
1675 /* Initilize SCSI Config Data structure
1676 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001677 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 /* Initialize the running configQ head.
1680 */
1681 INIT_LIST_HEAD(&ioc->configQ);
1682
Michael Reed05e8ec12006-01-13 14:31:54 -06001683 /* Initialize the fc rport list head.
1684 */
1685 INIT_LIST_HEAD(&ioc->fc_rports);
1686
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 /* Find lookup slot. */
1688 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001689
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301690
1691 /* Initialize workqueue */
1692 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1693 spin_lock_init(&ioc->fault_reset_work_lock);
1694
Kay Sieversaab0de22008-05-02 06:02:41 +02001695 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1696 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301697 ioc->reset_work_q =
1698 create_singlethread_workqueue(ioc->reset_work_q_name);
1699 if (!ioc->reset_work_q) {
1700 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1701 ioc->name);
1702 pci_release_selected_regions(pdev, ioc->bars);
1703 kfree(ioc);
1704 return -ENOMEM;
1705 }
1706
Eric Moore29dd3602007-09-14 18:46:51 -06001707 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1708 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301710 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1711 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1712
1713 switch (pdev->device)
1714 {
1715 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1716 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1717 ioc->errata_flag_1064 = 1;
1718 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1719 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1720 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1721 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301723 break;
1724
1725 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 /* 929X Chip Fix. Set Split transactions level
1728 * for PCIX. Set MOST bits to zero.
1729 */
1730 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1731 pcixcmd &= 0x8F;
1732 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1733 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 /* 929XL Chip Fix. Set MMRBC to 0x08.
1735 */
1736 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1737 pcixcmd |= 0x08;
1738 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301741 break;
1742
1743 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 /* 919X Chip Fix. Set Split transactions level
1745 * for PCIX. Set MOST bits to zero.
1746 */
1747 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1748 pcixcmd &= 0x8F;
1749 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001750 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301751 break;
1752
1753 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 /* 1030 Chip Fix. Disable Split transactions
1755 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1756 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (revision < C0_1030) {
1758 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1759 pcixcmd &= 0x8F;
1760 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1761 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301762
1763 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001764 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301765 break;
1766
1767 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1768 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001769 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301770
1771 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1772 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1773 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001774 ioc->bus_type = SAS;
1775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301777
Kashyap, Desaie3829682009-01-08 14:27:16 +05301778 switch (ioc->bus_type) {
1779
1780 case SAS:
1781 ioc->msi_enable = mpt_msi_enable_sas;
1782 break;
1783
1784 case SPI:
1785 ioc->msi_enable = mpt_msi_enable_spi;
1786 break;
1787
1788 case FC:
1789 ioc->msi_enable = mpt_msi_enable_fc;
1790 break;
1791
1792 default:
1793 ioc->msi_enable = 0;
1794 break;
1795 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001796 if (ioc->errata_flag_1064)
1797 pci_disable_io_access(pdev);
1798
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 spin_lock_init(&ioc->FreeQlock);
1800
1801 /* Disable all! */
1802 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1803 ioc->active = 0;
1804 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1805
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301806 /* Set IOC ptr in the pcidev's driver data. */
1807 pci_set_drvdata(ioc->pcidev, ioc);
1808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 /* Set lookup ptr. */
1810 list_add_tail(&ioc->list, &ioc_list);
1811
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001812 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 */
1814 mpt_detect_bound_ports(ioc, pdev);
1815
James Bottomleyc92f2222006-03-01 09:02:49 -06001816 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1817 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001818 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1819 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001822 if (ioc->alt_ioc)
1823 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301824 iounmap(ioc->memmap);
1825 if (r != -5)
1826 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301827
1828 destroy_workqueue(ioc->reset_work_q);
1829 ioc->reset_work_q = NULL;
1830
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 kfree(ioc);
1832 pci_set_drvdata(pdev, NULL);
1833 return r;
1834 }
1835
1836 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001837 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301838 if(MptDeviceDriverHandlers[cb_idx] &&
1839 MptDeviceDriverHandlers[cb_idx]->probe) {
1840 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 }
1842 }
1843
1844#ifdef CONFIG_PROC_FS
1845 /*
1846 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1847 */
1848 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1849 if (dent) {
1850 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1851 if (ent) {
1852 ent->read_proc = procmpt_iocinfo_read;
1853 ent->data = ioc;
1854 }
1855 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1856 if (ent) {
1857 ent->read_proc = procmpt_summary_read;
1858 ent->data = ioc;
1859 }
1860 }
1861#endif
1862
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301863 if (!ioc->alt_ioc)
1864 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1865 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1866
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 return 0;
1868}
1869
1870/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001871/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001872 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 */
1875
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001876void
1877mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878{
1879 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1880 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301881 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301882 unsigned long flags;
1883 struct workqueue_struct *wq;
1884
1885 /*
1886 * Stop polling ioc for fault condition
1887 */
1888 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
1889 wq = ioc->reset_work_q;
1890 ioc->reset_work_q = NULL;
1891 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
1892 cancel_delayed_work(&ioc->fault_reset_work);
1893 destroy_workqueue(wq);
1894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
1896 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1897 remove_proc_entry(pname, NULL);
1898 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1899 remove_proc_entry(pname, NULL);
1900 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1901 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001904 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301905 if(MptDeviceDriverHandlers[cb_idx] &&
1906 MptDeviceDriverHandlers[cb_idx]->remove) {
1907 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 }
1909 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001910
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 /* Disable interrupts! */
1912 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1913
1914 ioc->active = 0;
1915 synchronize_irq(pdev->irq);
1916
1917 /* Clear any lingering interrupt */
1918 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1919
1920 CHIPREG_READ32(&ioc->chip->IntStatus);
1921
1922 mpt_adapter_dispose(ioc);
1923
1924 pci_set_drvdata(pdev, NULL);
1925}
1926
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927/**************************************************************************
1928 * Power Management
1929 */
1930#ifdef CONFIG_PM
1931/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001932/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001933 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001934 * @pdev: Pointer to pci_dev structure
1935 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001937int
1938mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939{
1940 u32 device_state;
1941 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301943 device_state = pci_choose_state(pdev, state);
1944 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
1945 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1946 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947
1948 /* put ioc into READY_STATE */
1949 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1950 printk(MYIOC_s_ERR_FMT
1951 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1952 }
1953
1954 /* disable interrupts */
1955 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1956 ioc->active = 0;
1957
1958 /* Clear any lingering interrupt */
1959 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1960
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301961 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05001962 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301963 pci_disable_msi(ioc->pcidev);
1964 ioc->pci_irq = -1;
1965 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301967 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 return 0;
1970}
1971
1972/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001973/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001974 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001975 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001977int
1978mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979{
1980 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1981 u32 device_state = pdev->current_state;
1982 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301983 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001984
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301985 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
1986 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1987 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301989 pci_set_power_state(pdev, PCI_D0);
1990 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301992 ioc->pcidev = pdev;
1993 err = mpt_mapresources(ioc);
1994 if (err)
1995 return err;
1996
1997 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1998 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1999 CHIPREG_READ32(&ioc->chip->Doorbell));
2000
2001 /*
2002 * Errata workaround for SAS pci express:
2003 * Upon returning to the D0 state, the contents of the doorbell will be
2004 * stale data, and this will incorrectly signal to the host driver that
2005 * the firmware is ready to process mpt commands. The workaround is
2006 * to issue a diagnostic reset.
2007 */
2008 if (ioc->bus_type == SAS && (pdev->device ==
2009 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2010 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2011 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2012 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2013 ioc->name);
2014 goto out;
2015 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
2018 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302019 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2020 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2021 CAN_SLEEP);
2022 if (recovery_state != 0)
2023 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2024 "error:[%x]\n", ioc->name, recovery_state);
2025 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302027 "pci-resume: success\n", ioc->name);
2028 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302030
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031}
2032#endif
2033
James Bottomley4ff42a62006-05-17 18:06:52 -05002034static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302035mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002036{
2037 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2038 ioc->bus_type != SPI) ||
2039 (MptDriverClass[index] == MPTFC_DRIVER &&
2040 ioc->bus_type != FC) ||
2041 (MptDriverClass[index] == MPTSAS_DRIVER &&
2042 ioc->bus_type != SAS))
2043 /* make sure we only call the relevant reset handler
2044 * for the bus */
2045 return 0;
2046 return (MptResetHandlers[index])(ioc, reset_phase);
2047}
2048
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002050/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2052 * @ioc: Pointer to MPT adapter structure
2053 * @reason: Event word / reason
2054 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2055 *
2056 * This routine performs all the steps necessary to bring the IOC
2057 * to a OPERATIONAL state.
2058 *
2059 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2060 * MPT adapter.
2061 *
2062 * Returns:
2063 * 0 for success
2064 * -1 if failed to get board READY
2065 * -2 if READY but IOCFacts Failed
2066 * -3 if READY but PrimeIOCFifos Failed
2067 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302068 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302069 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 */
2071static int
2072mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2073{
2074 int hard_reset_done = 0;
2075 int alt_ioc_ready = 0;
2076 int hard;
2077 int rc=0;
2078 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302079 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 int handlers;
2081 int ret = 0;
2082 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002083 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302084 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
Eric Moore29dd3602007-09-14 18:46:51 -06002086 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2087 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
2089 /* Disable reply interrupts (also blocks FreeQ) */
2090 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2091 ioc->active = 0;
2092
2093 if (ioc->alt_ioc) {
2094 if (ioc->alt_ioc->active)
2095 reset_alt_ioc_active = 1;
2096
2097 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2098 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2099 ioc->alt_ioc->active = 0;
2100 }
2101
2102 hard = 1;
2103 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2104 hard = 0;
2105
2106 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2107 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002108 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2109 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
2111 if (reset_alt_ioc_active && ioc->alt_ioc) {
2112 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002113 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2114 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002115 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 ioc->alt_ioc->active = 1;
2117 }
2118
2119 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002120 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 }
2122 return -1;
2123 }
2124
2125 /* hard_reset_done = 0 if a soft reset was performed
2126 * and 1 if a hard reset was performed.
2127 */
2128 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2129 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2130 alt_ioc_ready = 1;
2131 else
Eric Moore29dd3602007-09-14 18:46:51 -06002132 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 }
2134
2135 for (ii=0; ii<5; ii++) {
2136 /* Get IOC facts! Allow 5 retries */
2137 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2138 break;
2139 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
2142 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002143 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2144 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 ret = -2;
2146 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2147 MptDisplayIocCapabilities(ioc);
2148 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 if (alt_ioc_ready) {
2151 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302152 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002153 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 /* Retry - alt IOC was initialized once
2155 */
2156 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2157 }
2158 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302159 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002160 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 alt_ioc_ready = 0;
2162 reset_alt_ioc_active = 0;
2163 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2164 MptDisplayIocCapabilities(ioc->alt_ioc);
2165 }
2166 }
2167
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302168 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2169 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2170 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2171 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2172 IORESOURCE_IO);
2173 if (pci_enable_device(ioc->pcidev))
2174 return -5;
2175 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2176 "mpt"))
2177 return -5;
2178 }
2179
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002180 /*
2181 * Device is reset now. It must have de-asserted the interrupt line
2182 * (if it was asserted) and it should be safe to register for the
2183 * interrupt now.
2184 */
2185 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2186 ioc->pci_irq = -1;
2187 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302188 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002189 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002190 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302191 else
2192 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002193 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002194 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002195 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002196 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002197 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302198 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002199 pci_disable_msi(ioc->pcidev);
2200 return -EBUSY;
2201 }
2202 irq_allocated = 1;
2203 ioc->pci_irq = ioc->pcidev->irq;
2204 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002205 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2206 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002207 }
2208 }
2209
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 /* Prime reply & request queues!
2211 * (mucho alloc's) Must be done prior to
2212 * init as upper addresses are needed for init.
2213 * If fails, continue with alt-ioc processing
2214 */
2215 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2216 ret = -3;
2217
2218 /* May need to check/upload firmware & data here!
2219 * If fails, continue with alt-ioc processing
2220 */
2221 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2222 ret = -4;
2223// NEW!
2224 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002225 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2226 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 alt_ioc_ready = 0;
2228 reset_alt_ioc_active = 0;
2229 }
2230
2231 if (alt_ioc_ready) {
2232 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2233 alt_ioc_ready = 0;
2234 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002235 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2236 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 }
2238 }
2239
2240 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2241 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302242 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002243 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
2245 /* Controller is not operational, cannot do upload
2246 */
2247 if (ret == 0) {
2248 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002249 if (rc == 0) {
2250 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2251 /*
2252 * Maintain only one pointer to FW memory
2253 * so there will not be two attempt to
2254 * downloadboot onboard dual function
2255 * chips (mpt_adapter_disable,
2256 * mpt_diag_reset)
2257 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302258 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002259 "mpt_upload: alt_%s has cached_fw=%p \n",
2260 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302261 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002262 }
2263 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002264 printk(MYIOC_s_WARN_FMT
2265 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302266 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 }
2269 }
2270 }
2271
2272 if (ret == 0) {
2273 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002274 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 ioc->active = 1;
2276 }
2277
2278 if (reset_alt_ioc_active && ioc->alt_ioc) {
2279 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002280 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2281 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002282 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 ioc->alt_ioc->active = 1;
2284 }
2285
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002286 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 * and EventAck handling.
2288 */
2289 if ((ret == 0) && (!ioc->facts.EventState))
2290 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2291
2292 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2293 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2294
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002295 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2297 * recursive scenario; GetLanConfigPages times out, timer expired
2298 * routine calls HardResetHandler, which calls into here again,
2299 * and we try GetLanConfigPages again...
2300 */
2301 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002302
2303 /*
2304 * Initalize link list for inactive raid volumes.
2305 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002306 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002307 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2308
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002309 if (ioc->bus_type == SAS) {
2310
2311 /* clear persistency table */
2312 if(ioc->facts.IOCExceptions &
2313 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2314 ret = mptbase_sas_persist_operation(ioc,
2315 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2316 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002317 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002318 }
2319
2320 /* Find IM volumes
2321 */
2322 mpt_findImVolumes(ioc);
2323
2324 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2326 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2327 /*
2328 * Pre-fetch the ports LAN MAC address!
2329 * (LANPage1_t stuff)
2330 */
2331 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302332 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2333 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002334 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2335 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302336
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 }
2338 } else {
2339 /* Get NVRAM and adapter maximums from SPP 0 and 2
2340 */
2341 mpt_GetScsiPortSettings(ioc, 0);
2342
2343 /* Get version and length of SDP 1
2344 */
2345 mpt_readScsiDevicePageHeaders(ioc, 0);
2346
2347 /* Find IM volumes
2348 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002349 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 mpt_findImVolumes(ioc);
2351
2352 /* Check, and possibly reset, the coalescing value
2353 */
2354 mpt_read_ioc_pg_1(ioc);
2355
2356 mpt_read_ioc_pg_4(ioc);
2357 }
2358
2359 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302360 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 }
2362
2363 /*
2364 * Call each currently registered protocol IOC reset handler
2365 * with post-reset indication.
2366 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2367 * MptResetHandlers[] registered yet.
2368 */
2369 if (hard_reset_done) {
2370 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302371 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2372 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302373 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002374 "Calling IOC post_reset handler #%d\n",
2375 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302376 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 handlers++;
2378 }
2379
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302380 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302381 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002382 "Calling IOC post_reset handler #%d\n",
2383 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302384 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 handlers++;
2386 }
2387 }
2388 /* FIXME? Examine results here? */
2389 }
2390
Eric Moore0ccdb002006-07-11 17:33:13 -06002391 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002392 if ((ret != 0) && irq_allocated) {
2393 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302394 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002395 pci_disable_msi(ioc->pcidev);
2396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 return ret;
2398}
2399
2400/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002401/**
2402 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 * @ioc: Pointer to MPT adapter structure
2404 * @pdev: Pointer to (struct pci_dev) structure
2405 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002406 * Search for PCI bus/dev_function which matches
2407 * PCI bus/dev_function (+/-1) for newly discovered 929,
2408 * 929X, 1030 or 1035.
2409 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2411 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2412 */
2413static void
2414mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2415{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002416 struct pci_dev *peer=NULL;
2417 unsigned int slot = PCI_SLOT(pdev->devfn);
2418 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 MPT_ADAPTER *ioc_srch;
2420
Prakash, Sathya436ace72007-07-24 15:42:08 +05302421 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002422 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002423 ioc->name, pci_name(pdev), pdev->bus->number,
2424 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002425
2426 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2427 if (!peer) {
2428 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2429 if (!peer)
2430 return;
2431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
2433 list_for_each_entry(ioc_srch, &ioc_list, list) {
2434 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002435 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 /* Paranoia checks */
2437 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002438 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002439 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 break;
2441 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002442 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002443 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 break;
2445 }
Eric Moore29dd3602007-09-14 18:46:51 -06002446 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002447 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 ioc_srch->alt_ioc = ioc;
2449 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 }
2451 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002452 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453}
2454
2455/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002456/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002458 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 */
2460static void
2461mpt_adapter_disable(MPT_ADAPTER *ioc)
2462{
2463 int sz;
2464 int ret;
2465
2466 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302467 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002468 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302469 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2470 ioc->cached_fw, CAN_SLEEP)) < 0) {
2471 printk(MYIOC_s_WARN_FMT
2472 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002473 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 }
2475 }
2476
2477 /* Disable adapter interrupts! */
2478 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2479 ioc->active = 0;
2480 /* Clear any lingering interrupt */
2481 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2482
2483 if (ioc->alloc != NULL) {
2484 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002485 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2486 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 pci_free_consistent(ioc->pcidev, sz,
2488 ioc->alloc, ioc->alloc_dma);
2489 ioc->reply_frames = NULL;
2490 ioc->req_frames = NULL;
2491 ioc->alloc = NULL;
2492 ioc->alloc_total -= sz;
2493 }
2494
2495 if (ioc->sense_buf_pool != NULL) {
2496 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2497 pci_free_consistent(ioc->pcidev, sz,
2498 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2499 ioc->sense_buf_pool = NULL;
2500 ioc->alloc_total -= sz;
2501 }
2502
2503 if (ioc->events != NULL){
2504 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2505 kfree(ioc->events);
2506 ioc->events = NULL;
2507 ioc->alloc_total -= sz;
2508 }
2509
Prakash, Sathya984621b2008-01-11 14:42:17 +05302510 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002512 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002513 mpt_inactive_raid_list_free(ioc);
2514 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002515 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002516 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002517 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518
2519 if (ioc->spi_data.pIocPg4 != NULL) {
2520 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302521 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 ioc->spi_data.pIocPg4,
2523 ioc->spi_data.IocPg4_dma);
2524 ioc->spi_data.pIocPg4 = NULL;
2525 ioc->alloc_total -= sz;
2526 }
2527
2528 if (ioc->ReqToChain != NULL) {
2529 kfree(ioc->ReqToChain);
2530 kfree(ioc->RequestNB);
2531 ioc->ReqToChain = NULL;
2532 }
2533
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002534 kfree(ioc->ChainToChain);
2535 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002536
2537 if (ioc->HostPageBuffer != NULL) {
2538 if((ret = mpt_host_page_access_control(ioc,
2539 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002540 printk(MYIOC_s_ERR_FMT
2541 "host page buffers free failed (%d)!\n",
2542 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002543 }
Eric Moore29dd3602007-09-14 18:46:51 -06002544 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002545 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2546 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002547 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002548 ioc->HostPageBuffer = NULL;
2549 ioc->HostPageBuffer_sz = 0;
2550 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552}
2553
2554/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002555/**
2556 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 * @ioc: Pointer to MPT adapter structure
2558 *
2559 * This routine unregisters h/w resources and frees all alloc'd memory
2560 * associated with a MPT adapter structure.
2561 */
2562static void
2563mpt_adapter_dispose(MPT_ADAPTER *ioc)
2564{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002565 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002567 if (ioc == NULL)
2568 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002570 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002572 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002574 if (ioc->pci_irq != -1) {
2575 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302576 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002577 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002578 ioc->pci_irq = -1;
2579 }
2580
2581 if (ioc->memmap != NULL) {
2582 iounmap(ioc->memmap);
2583 ioc->memmap = NULL;
2584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302586 pci_disable_device(ioc->pcidev);
2587 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2588
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002590 if (ioc->mtrr_reg > 0) {
2591 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002592 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594#endif
2595
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002596 /* Zap the adapter lookup ptr! */
2597 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002599 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002600 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2601 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002602
2603 if (ioc->alt_ioc)
2604 ioc->alt_ioc->alt_ioc = NULL;
2605
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002606 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607}
2608
2609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002610/**
2611 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 * @ioc: Pointer to MPT adapter structure
2613 */
2614static void
2615MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2616{
2617 int i = 0;
2618
2619 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302620 if (ioc->prod_name)
2621 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 printk("Capabilities={");
2623
2624 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2625 printk("Initiator");
2626 i++;
2627 }
2628
2629 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2630 printk("%sTarget", i ? "," : "");
2631 i++;
2632 }
2633
2634 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2635 printk("%sLAN", i ? "," : "");
2636 i++;
2637 }
2638
2639#if 0
2640 /*
2641 * This would probably evoke more questions than it's worth
2642 */
2643 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2644 printk("%sLogBusAddr", i ? "," : "");
2645 i++;
2646 }
2647#endif
2648
2649 printk("}\n");
2650}
2651
2652/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002653/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2655 * @ioc: Pointer to MPT_ADAPTER structure
2656 * @force: Force hard KickStart of IOC
2657 * @sleepFlag: Specifies whether the process can sleep
2658 *
2659 * Returns:
2660 * 1 - DIAG reset and READY
2661 * 0 - READY initially OR soft reset and READY
2662 * -1 - Any failure on KickStart
2663 * -2 - Msg Unit Reset Failed
2664 * -3 - IO Unit Reset Failed
2665 * -4 - IOC owned by a PEER
2666 */
2667static int
2668MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2669{
2670 u32 ioc_state;
2671 int statefault = 0;
2672 int cntdn;
2673 int hard_reset_done = 0;
2674 int r;
2675 int ii;
2676 int whoinit;
2677
2678 /* Get current [raw] IOC state */
2679 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002680 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
2682 /*
2683 * Check to see if IOC got left/stuck in doorbell handshake
2684 * grip of death. If so, hard reset the IOC.
2685 */
2686 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2687 statefault = 1;
2688 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2689 ioc->name);
2690 }
2691
2692 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002693 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 return 0;
2695
2696 /*
2697 * Check to see if IOC is in FAULT state.
2698 */
2699 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2700 statefault = 2;
2701 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002702 ioc->name);
2703 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2704 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 }
2706
2707 /*
2708 * Hmmm... Did it get left operational?
2709 */
2710 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302711 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 ioc->name));
2713
2714 /* Check WhoInit.
2715 * If PCI Peer, exit.
2716 * Else, if no fault conditions are present, issue a MessageUnitReset
2717 * Else, fall through to KickStart case
2718 */
2719 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002720 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2721 "whoinit 0x%x statefault %d force %d\n",
2722 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 if (whoinit == MPI_WHOINIT_PCI_PEER)
2724 return -4;
2725 else {
2726 if ((statefault == 0 ) && (force == 0)) {
2727 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2728 return 0;
2729 }
2730 statefault = 3;
2731 }
2732 }
2733
2734 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2735 if (hard_reset_done < 0)
2736 return -1;
2737
2738 /*
2739 * Loop here waiting for IOC to come READY.
2740 */
2741 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002742 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
2744 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2745 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2746 /*
2747 * BIOS or previous driver load left IOC in OP state.
2748 * Reset messaging FIFOs.
2749 */
2750 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2751 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2752 return -2;
2753 }
2754 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2755 /*
2756 * Something is wrong. Try to get IOC back
2757 * to a known state.
2758 */
2759 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2760 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2761 return -3;
2762 }
2763 }
2764
2765 ii++; cntdn--;
2766 if (!cntdn) {
2767 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2768 ioc->name, (int)((ii+5)/HZ));
2769 return -ETIME;
2770 }
2771
2772 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002773 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 } else {
2775 mdelay (1); /* 1 msec delay */
2776 }
2777
2778 }
2779
2780 if (statefault < 3) {
2781 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2782 ioc->name,
2783 statefault==1 ? "stuck handshake" : "IOC FAULT");
2784 }
2785
2786 return hard_reset_done;
2787}
2788
2789/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002790/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 * mpt_GetIocState - Get the current state of a MPT adapter.
2792 * @ioc: Pointer to MPT_ADAPTER structure
2793 * @cooked: Request raw or cooked IOC state
2794 *
2795 * Returns all IOC Doorbell register bits if cooked==0, else just the
2796 * Doorbell bits in MPI_IOC_STATE_MASK.
2797 */
2798u32
2799mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2800{
2801 u32 s, sc;
2802
2803 /* Get! */
2804 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 sc = s & MPI_IOC_STATE_MASK;
2806
2807 /* Save! */
2808 ioc->last_state = sc;
2809
2810 return cooked ? sc : s;
2811}
2812
2813/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002814/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 * GetIocFacts - Send IOCFacts request to MPT adapter.
2816 * @ioc: Pointer to MPT_ADAPTER structure
2817 * @sleepFlag: Specifies whether the process can sleep
2818 * @reason: If recovery, only update facts.
2819 *
2820 * Returns 0 for success, non-zero for failure.
2821 */
2822static int
2823GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2824{
2825 IOCFacts_t get_facts;
2826 IOCFactsReply_t *facts;
2827 int r;
2828 int req_sz;
2829 int reply_sz;
2830 int sz;
2831 u32 status, vv;
2832 u8 shiftFactor=1;
2833
2834 /* IOC *must* NOT be in RESET state! */
2835 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002836 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2837 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 return -44;
2839 }
2840
2841 facts = &ioc->facts;
2842
2843 /* Destination (reply area)... */
2844 reply_sz = sizeof(*facts);
2845 memset(facts, 0, reply_sz);
2846
2847 /* Request area (get_facts on the stack right now!) */
2848 req_sz = sizeof(get_facts);
2849 memset(&get_facts, 0, req_sz);
2850
2851 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2852 /* Assert: All other get_facts fields are zero! */
2853
Prakash, Sathya436ace72007-07-24 15:42:08 +05302854 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002855 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 ioc->name, req_sz, reply_sz));
2857
2858 /* No non-zero fields in the get_facts request are greater than
2859 * 1 byte in size, so we can just fire it off as is.
2860 */
2861 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2862 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2863 if (r != 0)
2864 return r;
2865
2866 /*
2867 * Now byte swap (GRRR) the necessary fields before any further
2868 * inspection of reply contents.
2869 *
2870 * But need to do some sanity checks on MsgLength (byte) field
2871 * to make sure we don't zero IOC's req_sz!
2872 */
2873 /* Did we get a valid reply? */
2874 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2875 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2876 /*
2877 * If not been here, done that, save off first WhoInit value
2878 */
2879 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2880 ioc->FirstWhoInit = facts->WhoInit;
2881 }
2882
2883 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2884 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2885 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2886 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2887 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002888 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 /* CHECKME! IOCStatus, IOCLogInfo */
2890
2891 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2892 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2893
2894 /*
2895 * FC f/w version changed between 1.1 and 1.2
2896 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2897 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2898 */
2899 if (facts->MsgVersion < 0x0102) {
2900 /*
2901 * Handle old FC f/w style, convert to new...
2902 */
2903 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2904 facts->FWVersion.Word =
2905 ((oldv<<12) & 0xFF000000) |
2906 ((oldv<<8) & 0x000FFF00);
2907 } else
2908 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2909
2910 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002911 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2912 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2913 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 facts->CurrentHostMfaHighAddr =
2915 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2916 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2917 facts->CurrentSenseBufferHighAddr =
2918 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2919 facts->CurReplyFrameSize =
2920 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002921 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
2923 /*
2924 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2925 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2926 * to 14 in MPI-1.01.0x.
2927 */
2928 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2929 facts->MsgVersion > 0x0100) {
2930 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2931 }
2932
2933 sz = facts->FWImageSize;
2934 if ( sz & 0x01 )
2935 sz += 1;
2936 if ( sz & 0x02 )
2937 sz += 2;
2938 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002939
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 if (!facts->RequestFrameSize) {
2941 /* Something is wrong! */
2942 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2943 ioc->name);
2944 return -55;
2945 }
2946
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002947 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 vv = ((63 / (sz * 4)) + 1) & 0x03;
2949 ioc->NB_for_64_byte_frame = vv;
2950 while ( sz )
2951 {
2952 shiftFactor++;
2953 sz = sz >> 1;
2954 }
2955 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302956 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002957 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2958 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002959
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2961 /*
2962 * Set values for this IOC's request & reply frame sizes,
2963 * and request & reply queue depths...
2964 */
2965 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2966 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2967 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2968 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2969
Prakash, Sathya436ace72007-07-24 15:42:08 +05302970 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302972 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 ioc->name, ioc->req_sz, ioc->req_depth));
2974
2975 /* Get port facts! */
2976 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2977 return r;
2978 }
2979 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002980 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2982 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2983 RequestFrameSize)/sizeof(u32)));
2984 return -66;
2985 }
2986
2987 return 0;
2988}
2989
2990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002991/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 * GetPortFacts - Send PortFacts request to MPT adapter.
2993 * @ioc: Pointer to MPT_ADAPTER structure
2994 * @portnum: Port number
2995 * @sleepFlag: Specifies whether the process can sleep
2996 *
2997 * Returns 0 for success, non-zero for failure.
2998 */
2999static int
3000GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3001{
3002 PortFacts_t get_pfacts;
3003 PortFactsReply_t *pfacts;
3004 int ii;
3005 int req_sz;
3006 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003007 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
3009 /* IOC *must* NOT be in RESET state! */
3010 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003011 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3012 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 return -4;
3014 }
3015
3016 pfacts = &ioc->pfacts[portnum];
3017
3018 /* Destination (reply area)... */
3019 reply_sz = sizeof(*pfacts);
3020 memset(pfacts, 0, reply_sz);
3021
3022 /* Request area (get_pfacts on the stack right now!) */
3023 req_sz = sizeof(get_pfacts);
3024 memset(&get_pfacts, 0, req_sz);
3025
3026 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3027 get_pfacts.PortNumber = portnum;
3028 /* Assert: All other get_pfacts fields are zero! */
3029
Prakash, Sathya436ace72007-07-24 15:42:08 +05303030 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 ioc->name, portnum));
3032
3033 /* No non-zero fields in the get_pfacts request are greater than
3034 * 1 byte in size, so we can just fire it off as is.
3035 */
3036 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3037 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3038 if (ii != 0)
3039 return ii;
3040
3041 /* Did we get a valid reply? */
3042
3043 /* Now byte swap the necessary fields in the response. */
3044 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3045 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3046 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3047 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3048 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3049 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3050 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3051 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3052 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3053
Eric Moore793955f2007-01-29 09:42:20 -07003054 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3055 pfacts->MaxDevices;
3056 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3057 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3058
3059 /*
3060 * Place all the devices on channels
3061 *
3062 * (for debuging)
3063 */
3064 if (mpt_channel_mapping) {
3065 ioc->devices_per_bus = 1;
3066 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3067 }
3068
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 return 0;
3070}
3071
3072/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003073/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 * SendIocInit - Send IOCInit request to MPT adapter.
3075 * @ioc: Pointer to MPT_ADAPTER structure
3076 * @sleepFlag: Specifies whether the process can sleep
3077 *
3078 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3079 *
3080 * Returns 0 for success, non-zero for failure.
3081 */
3082static int
3083SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3084{
3085 IOCInit_t ioc_init;
3086 MPIDefaultReply_t init_reply;
3087 u32 state;
3088 int r;
3089 int count;
3090 int cntdn;
3091
3092 memset(&ioc_init, 0, sizeof(ioc_init));
3093 memset(&init_reply, 0, sizeof(init_reply));
3094
3095 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3096 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3097
3098 /* If we are in a recovery mode and we uploaded the FW image,
3099 * then this pointer is not NULL. Skip the upload a second time.
3100 * Set this flag if cached_fw set for either IOC.
3101 */
3102 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3103 ioc->upload_fw = 1;
3104 else
3105 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303106 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3108
Eric Moore793955f2007-01-29 09:42:20 -07003109 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3110 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303111 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003112 ioc->name, ioc->facts.MsgVersion));
3113 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3114 // set MsgVersion and HeaderVersion host driver was built with
3115 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3116 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003118 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3119 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3120 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3121 return -99;
3122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3124
3125 if (sizeof(dma_addr_t) == sizeof(u64)) {
3126 /* Save the upper 32-bits of the request
3127 * (reply) and sense buffers.
3128 */
3129 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3130 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3131 } else {
3132 /* Force 32-bit addressing */
3133 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3134 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3135 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003136
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3138 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003139 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3140 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
Prakash, Sathya436ace72007-07-24 15:42:08 +05303142 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 ioc->name, &ioc_init));
3144
3145 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3146 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003147 if (r != 0) {
3148 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151
3152 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003153 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 */
3155
Prakash, Sathya436ace72007-07-24 15:42:08 +05303156 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003158
3159 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3160 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
3164 /* YIKES! SUPER IMPORTANT!!!
3165 * Poll IocState until _OPERATIONAL while IOC is doing
3166 * LoopInit and TargetDiscovery!
3167 */
3168 count = 0;
3169 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3170 state = mpt_GetIocState(ioc, 1);
3171 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3172 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003173 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 } else {
3175 mdelay(1);
3176 }
3177
3178 if (!cntdn) {
3179 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3180 ioc->name, (int)((count+5)/HZ));
3181 return -9;
3182 }
3183
3184 state = mpt_GetIocState(ioc, 1);
3185 count++;
3186 }
Eric Moore29dd3602007-09-14 18:46:51 -06003187 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 ioc->name, count));
3189
Eric Mooreba856d32006-07-11 17:34:01 -06003190 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 return r;
3192}
3193
3194/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003195/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 * SendPortEnable - Send PortEnable request to MPT adapter port.
3197 * @ioc: Pointer to MPT_ADAPTER structure
3198 * @portnum: Port number to enable
3199 * @sleepFlag: Specifies whether the process can sleep
3200 *
3201 * Send PortEnable to bring IOC to OPERATIONAL state.
3202 *
3203 * Returns 0 for success, non-zero for failure.
3204 */
3205static int
3206SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3207{
3208 PortEnable_t port_enable;
3209 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003210 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 int req_sz;
3212 int reply_sz;
3213
3214 /* Destination... */
3215 reply_sz = sizeof(MPIDefaultReply_t);
3216 memset(&reply_buf, 0, reply_sz);
3217
3218 req_sz = sizeof(PortEnable_t);
3219 memset(&port_enable, 0, req_sz);
3220
3221 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3222 port_enable.PortNumber = portnum;
3223/* port_enable.ChainOffset = 0; */
3224/* port_enable.MsgFlags = 0; */
3225/* port_enable.MsgContext = 0; */
3226
Prakash, Sathya436ace72007-07-24 15:42:08 +05303227 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 ioc->name, portnum, &port_enable));
3229
3230 /* RAID FW may take a long time to enable
3231 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003232 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003233 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3234 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3235 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003236 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003237 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3238 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3239 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003241 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242}
3243
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003244/**
3245 * mpt_alloc_fw_memory - allocate firmware memory
3246 * @ioc: Pointer to MPT_ADAPTER structure
3247 * @size: total FW bytes
3248 *
3249 * If memory has already been allocated, the same (cached) value
3250 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303251 *
3252 * Return 0 if successfull, or non-zero for failure
3253 **/
3254int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3256{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303257 int rc;
3258
3259 if (ioc->cached_fw) {
3260 rc = 0; /* use already allocated memory */
3261 goto out;
3262 }
3263 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3265 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303266 rc = 0;
3267 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303269 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3270 if (!ioc->cached_fw) {
3271 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3272 ioc->name);
3273 rc = -1;
3274 } else {
3275 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3276 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3277 ioc->alloc_total += size;
3278 rc = 0;
3279 }
3280 out:
3281 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303283
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003284/**
3285 * mpt_free_fw_memory - free firmware memory
3286 * @ioc: Pointer to MPT_ADAPTER structure
3287 *
3288 * If alt_img is NULL, delete from ioc structure.
3289 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303290 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291void
3292mpt_free_fw_memory(MPT_ADAPTER *ioc)
3293{
3294 int sz;
3295
Prakash, Sathya984621b2008-01-11 14:42:17 +05303296 if (!ioc->cached_fw)
3297 return;
3298
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303300 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3301 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003302 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303303 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305}
3306
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003308/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3310 * @ioc: Pointer to MPT_ADAPTER structure
3311 * @sleepFlag: Specifies whether the process can sleep
3312 *
3313 * Returns 0 for success, >0 for handshake failure
3314 * <0 for fw upload failure.
3315 *
3316 * Remark: If bound IOC and a successful FWUpload was performed
3317 * on the bound IOC, the second image is discarded
3318 * and memory is free'd. Both channels must upload to prevent
3319 * IOC from running in degraded mode.
3320 */
3321static int
3322mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3323{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 u8 reply[sizeof(FWUploadReply_t)];
3325 FWUpload_t *prequest;
3326 FWUploadReply_t *preply;
3327 FWUploadTCSGE_t *ptcsge;
3328 int sgeoffset;
3329 u32 flagsLength;
3330 int ii, sz, reply_sz;
3331 int cmdStatus;
3332
3333 /* If the image size is 0, we are done.
3334 */
3335 if ((sz = ioc->facts.FWImageSize) == 0)
3336 return 0;
3337
Prakash, Sathya984621b2008-01-11 14:42:17 +05303338 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3339 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340
Eric Moore29dd3602007-09-14 18:46:51 -06003341 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3342 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003343
Eric Moorebc6e0892007-09-29 10:16:28 -06003344 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3345 kzalloc(ioc->req_sz, GFP_KERNEL);
3346 if (!prequest) {
3347 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3348 "while allocating memory \n", ioc->name));
3349 mpt_free_fw_memory(ioc);
3350 return -ENOMEM;
3351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352
Eric Moorebc6e0892007-09-29 10:16:28 -06003353 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354
3355 reply_sz = sizeof(reply);
3356 memset(preply, 0, reply_sz);
3357
3358 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3359 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3360
3361 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3362 ptcsge->DetailsLength = 12;
3363 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3364 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003365 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366
3367 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3368
3369 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003370 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
3372 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003373 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3374 ioc->name, prequest, sgeoffset));
3375 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376
3377 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3378 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3379
Eric Moore29dd3602007-09-14 18:46:51 -06003380 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381
3382 cmdStatus = -EFAULT;
3383 if (ii == 0) {
3384 /* Handshake transfer was complete and successful.
3385 * Check the Reply Frame.
3386 */
3387 int status, transfer_sz;
3388 status = le16_to_cpu(preply->IOCStatus);
3389 if (status == MPI_IOCSTATUS_SUCCESS) {
3390 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3391 if (transfer_sz == sz)
3392 cmdStatus = 0;
3393 }
3394 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303395 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 ioc->name, cmdStatus));
3397
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003398
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 if (cmdStatus) {
3400
Prakash, Sathya436ace72007-07-24 15:42:08 +05303401 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 ioc->name));
3403 mpt_free_fw_memory(ioc);
3404 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003405 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406
3407 return cmdStatus;
3408}
3409
3410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003411/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 * mpt_downloadboot - DownloadBoot code
3413 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003414 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 * @sleepFlag: Specifies whether the process can sleep
3416 *
3417 * FwDownloadBoot requires Programmed IO access.
3418 *
3419 * Returns 0 for success
3420 * -1 FW Image size is 0
3421 * -2 No valid cached_fw Pointer
3422 * <0 for fw upload failure.
3423 */
3424static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003425mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 MpiExtImageHeader_t *pExtImage;
3428 u32 fwSize;
3429 u32 diag0val;
3430 int count;
3431 u32 *ptrFw;
3432 u32 diagRwData;
3433 u32 nextImage;
3434 u32 load_addr;
3435 u32 ioc_state=0;
3436
Prakash, Sathya436ace72007-07-24 15:42:08 +05303437 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003438 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003439
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3441 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3442 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3443 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3444 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3445 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3446
3447 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3448
3449 /* wait 1 msec */
3450 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003451 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 } else {
3453 mdelay (1);
3454 }
3455
3456 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3457 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3458
3459 for (count = 0; count < 30; count ++) {
3460 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3461 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303462 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 ioc->name, count));
3464 break;
3465 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003466 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003468 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003470 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 }
3472 }
3473
3474 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303475 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003476 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 ioc->name, diag0val));
3478 return -3;
3479 }
3480
3481 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3482 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3483 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3484 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3485 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3486 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3487
3488 /* Set the DiagRwEn and Disable ARM bits */
3489 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3490
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 fwSize = (pFwHeader->ImageSize + 3)/4;
3492 ptrFw = (u32 *) pFwHeader;
3493
3494 /* Write the LoadStartAddress to the DiagRw Address Register
3495 * using Programmed IO
3496 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003497 if (ioc->errata_flag_1064)
3498 pci_enable_io_access(ioc->pcidev);
3499
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303501 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 ioc->name, pFwHeader->LoadStartAddress));
3503
Prakash, Sathya436ace72007-07-24 15:42:08 +05303504 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 ioc->name, fwSize*4, ptrFw));
3506 while (fwSize--) {
3507 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3508 }
3509
3510 nextImage = pFwHeader->NextImageHeaderOffset;
3511 while (nextImage) {
3512 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3513
3514 load_addr = pExtImage->LoadStartAddress;
3515
3516 fwSize = (pExtImage->ImageSize + 3) >> 2;
3517 ptrFw = (u32 *)pExtImage;
3518
Prakash, Sathya436ace72007-07-24 15:42:08 +05303519 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 +02003520 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3522
3523 while (fwSize--) {
3524 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3525 }
3526 nextImage = pExtImage->NextImageHeaderOffset;
3527 }
3528
3529 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303530 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3532
3533 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303534 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3536
3537 /* Clear the internal flash bad bit - autoincrementing register,
3538 * so must do two writes.
3539 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003540 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003541 /*
3542 * 1030 and 1035 H/W errata, workaround to access
3543 * the ClearFlashBadSignatureBit
3544 */
3545 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3546 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3547 diagRwData |= 0x40000000;
3548 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3549 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3550
3551 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3552 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3553 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3554 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3555
3556 /* wait 1 msec */
3557 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003558 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003559 } else {
3560 mdelay (1);
3561 }
3562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003564 if (ioc->errata_flag_1064)
3565 pci_disable_io_access(ioc->pcidev);
3566
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303568 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003569 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003571 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303572 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 ioc->name, diag0val));
3574 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3575
3576 /* Write 0xFF to reset the sequencer */
3577 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3578
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003579 if (ioc->bus_type == SAS) {
3580 ioc_state = mpt_GetIocState(ioc, 0);
3581 if ( (GetIocFacts(ioc, sleepFlag,
3582 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303583 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003584 ioc->name, ioc_state));
3585 return -EFAULT;
3586 }
3587 }
3588
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 for (count=0; count<HZ*20; count++) {
3590 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303591 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3592 "downloadboot successful! (count=%d) IocState=%x\n",
3593 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003594 if (ioc->bus_type == SAS) {
3595 return 0;
3596 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303598 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3599 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 ioc->name));
3601 return -EFAULT;
3602 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303603 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3604 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 ioc->name));
3606 return 0;
3607 }
3608 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003609 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 } else {
3611 mdelay (10);
3612 }
3613 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303614 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3615 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 return -EFAULT;
3617}
3618
3619/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003620/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 * KickStart - Perform hard reset of MPT adapter.
3622 * @ioc: Pointer to MPT_ADAPTER structure
3623 * @force: Force hard reset
3624 * @sleepFlag: Specifies whether the process can sleep
3625 *
3626 * This routine places MPT adapter in diagnostic mode via the
3627 * WriteSequence register, and then performs a hard reset of adapter
3628 * via the Diagnostic register.
3629 *
3630 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3631 * or NO_SLEEP (interrupt thread, use mdelay)
3632 * force - 1 if doorbell active, board fault state
3633 * board operational, IOC_RECOVERY or
3634 * IOC_BRINGUP and there is an alt_ioc.
3635 * 0 else
3636 *
3637 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003638 * 1 - hard reset, READY
3639 * 0 - no reset due to History bit, READY
3640 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 * OR reset but failed to come READY
3642 * -2 - no reset, could not enter DIAG mode
3643 * -3 - reset but bad FW bit
3644 */
3645static int
3646KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3647{
3648 int hard_reset_done = 0;
3649 u32 ioc_state=0;
3650 int cnt,cntdn;
3651
Eric Moore29dd3602007-09-14 18:46:51 -06003652 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003653 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 /* Always issue a Msg Unit Reset first. This will clear some
3655 * SCSI bus hang conditions.
3656 */
3657 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3658
3659 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003660 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 } else {
3662 mdelay (1000);
3663 }
3664 }
3665
3666 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3667 if (hard_reset_done < 0)
3668 return hard_reset_done;
3669
Prakash, Sathya436ace72007-07-24 15:42:08 +05303670 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003671 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672
3673 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3674 for (cnt=0; cnt<cntdn; cnt++) {
3675 ioc_state = mpt_GetIocState(ioc, 1);
3676 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303677 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 ioc->name, cnt));
3679 return hard_reset_done;
3680 }
3681 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003682 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 } else {
3684 mdelay (10);
3685 }
3686 }
3687
Eric Moore29dd3602007-09-14 18:46:51 -06003688 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3689 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 return -1;
3691}
3692
3693/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003694/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 * mpt_diag_reset - Perform hard reset of the adapter.
3696 * @ioc: Pointer to MPT_ADAPTER structure
3697 * @ignore: Set if to honor and clear to ignore
3698 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003699 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 * else set to NO_SLEEP (use mdelay instead)
3701 *
3702 * This routine places the adapter in diagnostic mode via the
3703 * WriteSequence register and then performs a hard reset of adapter
3704 * via the Diagnostic register. Adapter should be in ready state
3705 * upon successful completion.
3706 *
3707 * Returns: 1 hard reset successful
3708 * 0 no reset performed because reset history bit set
3709 * -2 enabling diagnostic mode failed
3710 * -3 diagnostic reset failed
3711 */
3712static int
3713mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3714{
3715 u32 diag0val;
3716 u32 doorbell;
3717 int hard_reset_done = 0;
3718 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303720 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721
Eric Moorecd2c6192007-01-29 09:47:47 -07003722 /* Clear any existing interrupts */
3723 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3724
Eric Moore87cf8982006-06-27 16:09:26 -06003725 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303726 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003727 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003728 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3729 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3730 if (sleepFlag == CAN_SLEEP)
3731 msleep(1);
3732 else
3733 mdelay(1);
3734
3735 for (count = 0; count < 60; count ++) {
3736 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3737 doorbell &= MPI_IOC_STATE_MASK;
3738
Prakash, Sathya436ace72007-07-24 15:42:08 +05303739 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003740 "looking for READY STATE: doorbell=%x"
3741 " count=%d\n",
3742 ioc->name, doorbell, count));
3743 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003744 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003745 }
3746
3747 /* wait 1 sec */
3748 if (sleepFlag == CAN_SLEEP)
3749 msleep(1000);
3750 else
3751 mdelay(1000);
3752 }
3753 return -1;
3754 }
3755
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 /* Use "Diagnostic reset" method! (only thing available!) */
3757 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3758
Prakash, Sathya436ace72007-07-24 15:42:08 +05303759 if (ioc->debug_level & MPT_DEBUG) {
3760 if (ioc->alt_ioc)
3761 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3762 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765
3766 /* Do the reset if we are told to ignore the reset history
3767 * or if the reset history is 0
3768 */
3769 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3770 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3771 /* Write magic sequence to WriteSequence register
3772 * Loop until in diagnostic mode
3773 */
3774 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3775 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3776 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3777 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3778 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3779 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3780
3781 /* wait 100 msec */
3782 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003783 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 } else {
3785 mdelay (100);
3786 }
3787
3788 count++;
3789 if (count > 20) {
3790 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3791 ioc->name, diag0val);
3792 return -2;
3793
3794 }
3795
3796 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3797
Prakash, Sathya436ace72007-07-24 15:42:08 +05303798 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 ioc->name, diag0val));
3800 }
3801
Prakash, Sathya436ace72007-07-24 15:42:08 +05303802 if (ioc->debug_level & MPT_DEBUG) {
3803 if (ioc->alt_ioc)
3804 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3805 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 /*
3809 * Disable the ARM (Bug fix)
3810 *
3811 */
3812 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003813 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814
3815 /*
3816 * Now hit the reset bit in the Diagnostic register
3817 * (THE BIG HAMMER!) (Clears DRWE bit).
3818 */
3819 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3820 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303821 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 ioc->name));
3823
3824 /*
3825 * Call each currently registered protocol IOC reset handler
3826 * with pre-reset indication.
3827 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3828 * MptResetHandlers[] registered yet.
3829 */
3830 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303831 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 int r = 0;
3833
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303834 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3835 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303836 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3837 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303838 ioc->name, cb_idx));
3839 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303841 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3842 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303843 ioc->name, ioc->alt_ioc->name, cb_idx));
3844 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 }
3846 }
3847 }
3848 /* FIXME? Examine results here? */
3849 }
3850
Eric Moore0ccdb002006-07-11 17:33:13 -06003851 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303852 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003853 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303854 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3855 else
3856 cached_fw = NULL;
3857 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 /* If the DownloadBoot operation fails, the
3859 * IOC will be left unusable. This is a fatal error
3860 * case. _diag_reset will return < 0
3861 */
3862 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303863 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3865 break;
3866 }
3867
Prakash, Sathya436ace72007-07-24 15:42:08 +05303868 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303869 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 /* wait 1 sec */
3871 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003872 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 } else {
3874 mdelay (1000);
3875 }
3876 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303877 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003878 printk(MYIOC_s_WARN_FMT
3879 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 }
3881
3882 } else {
3883 /* Wait for FW to reload and for board
3884 * to go to the READY state.
3885 * Maximum wait is 60 seconds.
3886 * If fail, no error will check again
3887 * with calling program.
3888 */
3889 for (count = 0; count < 60; count ++) {
3890 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3891 doorbell &= MPI_IOC_STATE_MASK;
3892
3893 if (doorbell == MPI_IOC_STATE_READY) {
3894 break;
3895 }
3896
3897 /* wait 1 sec */
3898 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003899 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 } else {
3901 mdelay (1000);
3902 }
3903 }
3904 }
3905 }
3906
3907 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303908 if (ioc->debug_level & MPT_DEBUG) {
3909 if (ioc->alt_ioc)
3910 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3911 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3912 ioc->name, diag0val, diag1val));
3913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914
3915 /* Clear RESET_HISTORY bit! Place board in the
3916 * diagnostic mode to update the diag register.
3917 */
3918 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3919 count = 0;
3920 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3921 /* Write magic sequence to WriteSequence register
3922 * Loop until in diagnostic mode
3923 */
3924 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3925 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3926 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3927 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3928 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3929 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3930
3931 /* wait 100 msec */
3932 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003933 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 } else {
3935 mdelay (100);
3936 }
3937
3938 count++;
3939 if (count > 20) {
3940 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3941 ioc->name, diag0val);
3942 break;
3943 }
3944 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3945 }
3946 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3947 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3948 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3949 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3950 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3951 ioc->name);
3952 }
3953
3954 /* Disable Diagnostic Mode
3955 */
3956 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3957
3958 /* Check FW reload status flags.
3959 */
3960 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3961 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3962 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3963 ioc->name, diag0val);
3964 return -3;
3965 }
3966
Prakash, Sathya436ace72007-07-24 15:42:08 +05303967 if (ioc->debug_level & MPT_DEBUG) {
3968 if (ioc->alt_ioc)
3969 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3970 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303972 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973
3974 /*
3975 * Reset flag that says we've enabled event notification
3976 */
3977 ioc->facts.EventState = 0;
3978
3979 if (ioc->alt_ioc)
3980 ioc->alt_ioc->facts.EventState = 0;
3981
3982 return hard_reset_done;
3983}
3984
3985/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003986/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 * SendIocReset - Send IOCReset request to MPT adapter.
3988 * @ioc: Pointer to MPT_ADAPTER structure
3989 * @reset_type: reset type, expected values are
3990 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003991 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 *
3993 * Send IOCReset request to the MPT adapter.
3994 *
3995 * Returns 0 for success, non-zero for failure.
3996 */
3997static int
3998SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3999{
4000 int r;
4001 u32 state;
4002 int cntdn, count;
4003
Prakash, Sathya436ace72007-07-24 15:42:08 +05304004 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 ioc->name, reset_type));
4006 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4007 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4008 return r;
4009
4010 /* FW ACK'd request, wait for READY state
4011 */
4012 count = 0;
4013 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4014
4015 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4016 cntdn--;
4017 count++;
4018 if (!cntdn) {
4019 if (sleepFlag != CAN_SLEEP)
4020 count *= 10;
4021
Eric Moore29dd3602007-09-14 18:46:51 -06004022 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
4023 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 return -ETIME;
4025 }
4026
4027 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004028 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 } else {
4030 mdelay (1); /* 1 msec delay */
4031 }
4032 }
4033
4034 /* TODO!
4035 * Cleanup all event stuff for this IOC; re-issue EventNotification
4036 * request if needed.
4037 */
4038 if (ioc->facts.Function)
4039 ioc->facts.EventState = 0;
4040
4041 return 0;
4042}
4043
4044/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004045/**
4046 * initChainBuffers - Allocate memory for and initialize chain buffers
4047 * @ioc: Pointer to MPT_ADAPTER structure
4048 *
4049 * Allocates memory for and initializes chain buffers,
4050 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 */
4052static int
4053initChainBuffers(MPT_ADAPTER *ioc)
4054{
4055 u8 *mem;
4056 int sz, ii, num_chain;
4057 int scale, num_sge, numSGE;
4058
4059 /* ReqToChain size must equal the req_depth
4060 * index = req_idx
4061 */
4062 if (ioc->ReqToChain == NULL) {
4063 sz = ioc->req_depth * sizeof(int);
4064 mem = kmalloc(sz, GFP_ATOMIC);
4065 if (mem == NULL)
4066 return -1;
4067
4068 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304069 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 ioc->name, mem, sz));
4071 mem = kmalloc(sz, GFP_ATOMIC);
4072 if (mem == NULL)
4073 return -1;
4074
4075 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304076 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 ioc->name, mem, sz));
4078 }
4079 for (ii = 0; ii < ioc->req_depth; ii++) {
4080 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4081 }
4082
4083 /* ChainToChain size must equal the total number
4084 * of chain buffers to be allocated.
4085 * index = chain_idx
4086 *
4087 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004088 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 *
4090 * num_sge = num sge in request frame + last chain buffer
4091 * scale = num sge per chain buffer if no chain element
4092 */
4093 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
4094 if (sizeof(dma_addr_t) == sizeof(u64))
4095 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4096 else
4097 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4098
4099 if (sizeof(dma_addr_t) == sizeof(u64)) {
4100 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4101 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4102 } else {
4103 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4104 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4105 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304106 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 ioc->name, num_sge, numSGE));
4108
4109 if ( numSGE > MPT_SCSI_SG_DEPTH )
4110 numSGE = MPT_SCSI_SG_DEPTH;
4111
4112 num_chain = 1;
4113 while (numSGE - num_sge > 0) {
4114 num_chain++;
4115 num_sge += (scale - 1);
4116 }
4117 num_chain++;
4118
Prakash, Sathya436ace72007-07-24 15:42:08 +05304119 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 ioc->name, numSGE, num_sge, num_chain));
4121
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004122 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 num_chain *= MPT_SCSI_CAN_QUEUE;
4124 else
4125 num_chain *= MPT_FC_CAN_QUEUE;
4126
4127 ioc->num_chain = num_chain;
4128
4129 sz = num_chain * sizeof(int);
4130 if (ioc->ChainToChain == NULL) {
4131 mem = kmalloc(sz, GFP_ATOMIC);
4132 if (mem == NULL)
4133 return -1;
4134
4135 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304136 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 ioc->name, mem, sz));
4138 } else {
4139 mem = (u8 *) ioc->ChainToChain;
4140 }
4141 memset(mem, 0xFF, sz);
4142 return num_chain;
4143}
4144
4145/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004146/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4148 * @ioc: Pointer to MPT_ADAPTER structure
4149 *
4150 * This routine allocates memory for the MPT reply and request frame
4151 * pools (if necessary), and primes the IOC reply FIFO with
4152 * reply frames.
4153 *
4154 * Returns 0 for success, non-zero for failure.
4155 */
4156static int
4157PrimeIocFifos(MPT_ADAPTER *ioc)
4158{
4159 MPT_FRAME_HDR *mf;
4160 unsigned long flags;
4161 dma_addr_t alloc_dma;
4162 u8 *mem;
4163 int i, reply_sz, sz, total_size, num_chain;
4164
4165 /* Prime reply FIFO... */
4166
4167 if (ioc->reply_frames == NULL) {
4168 if ( (num_chain = initChainBuffers(ioc)) < 0)
4169 return -1;
4170
4171 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304172 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304174 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 ioc->name, reply_sz, reply_sz));
4176
4177 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304178 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304180 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 ioc->name, sz, sz));
4182 total_size += sz;
4183
4184 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304185 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304187 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 ioc->name, sz, sz, num_chain));
4189
4190 total_size += sz;
4191 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4192 if (mem == NULL) {
4193 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4194 ioc->name);
4195 goto out_fail;
4196 }
4197
Prakash, Sathya436ace72007-07-24 15:42:08 +05304198 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4200
4201 memset(mem, 0, total_size);
4202 ioc->alloc_total += total_size;
4203 ioc->alloc = mem;
4204 ioc->alloc_dma = alloc_dma;
4205 ioc->alloc_sz = total_size;
4206 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4207 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4208
Prakash, Sathya436ace72007-07-24 15:42:08 +05304209 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004210 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4211
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 alloc_dma += reply_sz;
4213 mem += reply_sz;
4214
4215 /* Request FIFO - WE manage this! */
4216
4217 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4218 ioc->req_frames_dma = alloc_dma;
4219
Prakash, Sathya436ace72007-07-24 15:42:08 +05304220 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 ioc->name, mem, (void *)(ulong)alloc_dma));
4222
4223 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4224
4225#if defined(CONFIG_MTRR) && 0
4226 /*
4227 * Enable Write Combining MTRR for IOC's memory region.
4228 * (at least as much as we can; "size and base must be
4229 * multiples of 4 kiB"
4230 */
4231 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4232 sz,
4233 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304234 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 ioc->name, ioc->req_frames_dma, sz));
4236#endif
4237
4238 for (i = 0; i < ioc->req_depth; i++) {
4239 alloc_dma += ioc->req_sz;
4240 mem += ioc->req_sz;
4241 }
4242
4243 ioc->ChainBuffer = mem;
4244 ioc->ChainBufferDMA = alloc_dma;
4245
Prakash, Sathya436ace72007-07-24 15:42:08 +05304246 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4248
4249 /* Initialize the free chain Q.
4250 */
4251
4252 INIT_LIST_HEAD(&ioc->FreeChainQ);
4253
4254 /* Post the chain buffers to the FreeChainQ.
4255 */
4256 mem = (u8 *)ioc->ChainBuffer;
4257 for (i=0; i < num_chain; i++) {
4258 mf = (MPT_FRAME_HDR *) mem;
4259 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4260 mem += ioc->req_sz;
4261 }
4262
4263 /* Initialize Request frames linked list
4264 */
4265 alloc_dma = ioc->req_frames_dma;
4266 mem = (u8 *) ioc->req_frames;
4267
4268 spin_lock_irqsave(&ioc->FreeQlock, flags);
4269 INIT_LIST_HEAD(&ioc->FreeQ);
4270 for (i = 0; i < ioc->req_depth; i++) {
4271 mf = (MPT_FRAME_HDR *) mem;
4272
4273 /* Queue REQUESTs *internally*! */
4274 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4275
4276 mem += ioc->req_sz;
4277 }
4278 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4279
4280 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4281 ioc->sense_buf_pool =
4282 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4283 if (ioc->sense_buf_pool == NULL) {
4284 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4285 ioc->name);
4286 goto out_fail;
4287 }
4288
4289 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4290 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304291 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4293
4294 }
4295
4296 /* Post Reply frames to FIFO
4297 */
4298 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304299 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4301
4302 for (i = 0; i < ioc->reply_depth; i++) {
4303 /* Write each address to the IOC! */
4304 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4305 alloc_dma += ioc->reply_sz;
4306 }
4307
4308 return 0;
4309
4310out_fail:
4311 if (ioc->alloc != NULL) {
4312 sz = ioc->alloc_sz;
4313 pci_free_consistent(ioc->pcidev,
4314 sz,
4315 ioc->alloc, ioc->alloc_dma);
4316 ioc->reply_frames = NULL;
4317 ioc->req_frames = NULL;
4318 ioc->alloc_total -= sz;
4319 }
4320 if (ioc->sense_buf_pool != NULL) {
4321 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4322 pci_free_consistent(ioc->pcidev,
4323 sz,
4324 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4325 ioc->sense_buf_pool = NULL;
4326 }
4327 return -1;
4328}
4329
4330/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4331/**
4332 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4333 * from IOC via doorbell handshake method.
4334 * @ioc: Pointer to MPT_ADAPTER structure
4335 * @reqBytes: Size of the request in bytes
4336 * @req: Pointer to MPT request frame
4337 * @replyBytes: Expected size of the reply in bytes
4338 * @u16reply: Pointer to area where reply should be written
4339 * @maxwait: Max wait time for a reply (in seconds)
4340 * @sleepFlag: Specifies whether the process can sleep
4341 *
4342 * NOTES: It is the callers responsibility to byte-swap fields in the
4343 * request which are greater than 1 byte in size. It is also the
4344 * callers responsibility to byte-swap response fields which are
4345 * greater than 1 byte in size.
4346 *
4347 * Returns 0 for success, non-zero for failure.
4348 */
4349static int
4350mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004351 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352{
4353 MPIDefaultReply_t *mptReply;
4354 int failcnt = 0;
4355 int t;
4356
4357 /*
4358 * Get ready to cache a handshake reply
4359 */
4360 ioc->hs_reply_idx = 0;
4361 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4362 mptReply->MsgLength = 0;
4363
4364 /*
4365 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4366 * then tell IOC that we want to handshake a request of N words.
4367 * (WRITE u32val to Doorbell reg).
4368 */
4369 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4370 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4371 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4372 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4373
4374 /*
4375 * Wait for IOC's doorbell handshake int
4376 */
4377 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4378 failcnt++;
4379
Prakash, Sathya436ace72007-07-24 15:42:08 +05304380 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4382
4383 /* Read doorbell and check for active bit */
4384 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4385 return -1;
4386
4387 /*
4388 * Clear doorbell int (WRITE 0 to IntStatus reg),
4389 * then wait for IOC to ACKnowledge that it's ready for
4390 * our handshake request.
4391 */
4392 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4393 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4394 failcnt++;
4395
4396 if (!failcnt) {
4397 int ii;
4398 u8 *req_as_bytes = (u8 *) req;
4399
4400 /*
4401 * Stuff request words via doorbell handshake,
4402 * with ACK from IOC for each.
4403 */
4404 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4405 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4406 (req_as_bytes[(ii*4) + 1] << 8) |
4407 (req_as_bytes[(ii*4) + 2] << 16) |
4408 (req_as_bytes[(ii*4) + 3] << 24));
4409
4410 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4411 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4412 failcnt++;
4413 }
4414
Prakash, Sathya436ace72007-07-24 15:42:08 +05304415 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004416 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417
Prakash, Sathya436ace72007-07-24 15:42:08 +05304418 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4420
4421 /*
4422 * Wait for completion of doorbell handshake reply from the IOC
4423 */
4424 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4425 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004426
Prakash, Sathya436ace72007-07-24 15:42:08 +05304427 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4429
4430 /*
4431 * Copy out the cached reply...
4432 */
4433 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4434 u16reply[ii] = ioc->hs_reply[ii];
4435 } else {
4436 return -99;
4437 }
4438
4439 return -failcnt;
4440}
4441
4442/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004443/**
4444 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 * @ioc: Pointer to MPT_ADAPTER structure
4446 * @howlong: How long to wait (in seconds)
4447 * @sleepFlag: Specifies whether the process can sleep
4448 *
4449 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004450 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4451 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 *
4453 * Returns a negative value on failure, else wait loop count.
4454 */
4455static int
4456WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4457{
4458 int cntdn;
4459 int count = 0;
4460 u32 intstat=0;
4461
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004462 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463
4464 if (sleepFlag == CAN_SLEEP) {
4465 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004466 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4468 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4469 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 count++;
4471 }
4472 } else {
4473 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004474 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4476 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4477 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 count++;
4479 }
4480 }
4481
4482 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304483 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 ioc->name, count));
4485 return count;
4486 }
4487
4488 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4489 ioc->name, count, intstat);
4490 return -1;
4491}
4492
4493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004494/**
4495 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 * @ioc: Pointer to MPT_ADAPTER structure
4497 * @howlong: How long to wait (in seconds)
4498 * @sleepFlag: Specifies whether the process can sleep
4499 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004500 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4501 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 *
4503 * Returns a negative value on failure, else wait loop count.
4504 */
4505static int
4506WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4507{
4508 int cntdn;
4509 int count = 0;
4510 u32 intstat=0;
4511
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004512 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 if (sleepFlag == CAN_SLEEP) {
4514 while (--cntdn) {
4515 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4516 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4517 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004518 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 count++;
4520 }
4521 } else {
4522 while (--cntdn) {
4523 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4524 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4525 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004526 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 count++;
4528 }
4529 }
4530
4531 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304532 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 ioc->name, count, howlong));
4534 return count;
4535 }
4536
4537 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4538 ioc->name, count, intstat);
4539 return -1;
4540}
4541
4542/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004543/**
4544 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 * @ioc: Pointer to MPT_ADAPTER structure
4546 * @howlong: How long to wait (in seconds)
4547 * @sleepFlag: Specifies whether the process can sleep
4548 *
4549 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4550 * Reply is cached to IOC private area large enough to hold a maximum
4551 * of 128 bytes of reply data.
4552 *
4553 * Returns a negative value on failure, else size of reply in WORDS.
4554 */
4555static int
4556WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4557{
4558 int u16cnt = 0;
4559 int failcnt = 0;
4560 int t;
4561 u16 *hs_reply = ioc->hs_reply;
4562 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4563 u16 hword;
4564
4565 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4566
4567 /*
4568 * Get first two u16's so we can look at IOC's intended reply MsgLength
4569 */
4570 u16cnt=0;
4571 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4572 failcnt++;
4573 } else {
4574 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4575 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4576 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4577 failcnt++;
4578 else {
4579 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4580 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4581 }
4582 }
4583
Prakash, Sathya436ace72007-07-24 15:42:08 +05304584 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004585 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4587
4588 /*
4589 * If no error (and IOC said MsgLength is > 0), piece together
4590 * reply 16 bits at a time.
4591 */
4592 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4593 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4594 failcnt++;
4595 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4596 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004597 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 hs_reply[u16cnt] = hword;
4599 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4600 }
4601
4602 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4603 failcnt++;
4604 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4605
4606 if (failcnt) {
4607 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4608 ioc->name);
4609 return -failcnt;
4610 }
4611#if 0
4612 else if (u16cnt != (2 * mptReply->MsgLength)) {
4613 return -101;
4614 }
4615 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4616 return -102;
4617 }
4618#endif
4619
Prakash, Sathya436ace72007-07-24 15:42:08 +05304620 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004621 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622
Prakash, Sathya436ace72007-07-24 15:42:08 +05304623 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 ioc->name, t, u16cnt/2));
4625 return u16cnt/2;
4626}
4627
4628/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004629/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 * GetLanConfigPages - Fetch LANConfig pages.
4631 * @ioc: Pointer to MPT_ADAPTER structure
4632 *
4633 * Return: 0 for success
4634 * -ENOMEM if no memory available
4635 * -EPERM if not allowed due to ISR context
4636 * -EAGAIN if no msg frames currently available
4637 * -EFAULT for non-successful reply or no reply (timeout)
4638 */
4639static int
4640GetLanConfigPages(MPT_ADAPTER *ioc)
4641{
4642 ConfigPageHeader_t hdr;
4643 CONFIGPARMS cfg;
4644 LANPage0_t *ppage0_alloc;
4645 dma_addr_t page0_dma;
4646 LANPage1_t *ppage1_alloc;
4647 dma_addr_t page1_dma;
4648 int rc = 0;
4649 int data_sz;
4650 int copy_sz;
4651
4652 /* Get LAN Page 0 header */
4653 hdr.PageVersion = 0;
4654 hdr.PageLength = 0;
4655 hdr.PageNumber = 0;
4656 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004657 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 cfg.physAddr = -1;
4659 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4660 cfg.dir = 0;
4661 cfg.pageAddr = 0;
4662 cfg.timeout = 0;
4663
4664 if ((rc = mpt_config(ioc, &cfg)) != 0)
4665 return rc;
4666
4667 if (hdr.PageLength > 0) {
4668 data_sz = hdr.PageLength * 4;
4669 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4670 rc = -ENOMEM;
4671 if (ppage0_alloc) {
4672 memset((u8 *)ppage0_alloc, 0, data_sz);
4673 cfg.physAddr = page0_dma;
4674 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4675
4676 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4677 /* save the data */
4678 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4679 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4680
4681 }
4682
4683 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4684
4685 /* FIXME!
4686 * Normalize endianness of structure data,
4687 * by byte-swapping all > 1 byte fields!
4688 */
4689
4690 }
4691
4692 if (rc)
4693 return rc;
4694 }
4695
4696 /* Get LAN Page 1 header */
4697 hdr.PageVersion = 0;
4698 hdr.PageLength = 0;
4699 hdr.PageNumber = 1;
4700 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004701 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 cfg.physAddr = -1;
4703 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4704 cfg.dir = 0;
4705 cfg.pageAddr = 0;
4706
4707 if ((rc = mpt_config(ioc, &cfg)) != 0)
4708 return rc;
4709
4710 if (hdr.PageLength == 0)
4711 return 0;
4712
4713 data_sz = hdr.PageLength * 4;
4714 rc = -ENOMEM;
4715 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4716 if (ppage1_alloc) {
4717 memset((u8 *)ppage1_alloc, 0, data_sz);
4718 cfg.physAddr = page1_dma;
4719 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4720
4721 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4722 /* save the data */
4723 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4724 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4725 }
4726
4727 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4728
4729 /* FIXME!
4730 * Normalize endianness of structure data,
4731 * by byte-swapping all > 1 byte fields!
4732 */
4733
4734 }
4735
4736 return rc;
4737}
4738
4739/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004740/**
4741 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004742 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004743 * @persist_opcode: see below
4744 *
4745 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4746 * devices not currently present.
4747 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4748 *
4749 * NOTE: Don't use not this function during interrupt time.
4750 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004751 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004752 */
4753
4754/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4755int
4756mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4757{
4758 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4759 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4760 MPT_FRAME_HDR *mf = NULL;
4761 MPIHeader_t *mpi_hdr;
4762
4763
4764 /* insure garbage is not sent to fw */
4765 switch(persist_opcode) {
4766
4767 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4768 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4769 break;
4770
4771 default:
4772 return -1;
4773 break;
4774 }
4775
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004776 printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004777
4778 /* Get a MF for this command.
4779 */
4780 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004781 printk("%s: no msg frames!\n",__func__);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004782 return -1;
4783 }
4784
4785 mpi_hdr = (MPIHeader_t *) mf;
4786 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4787 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4788 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4789 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4790 sasIoUnitCntrReq->Operation = persist_opcode;
4791
4792 init_timer(&ioc->persist_timer);
4793 ioc->persist_timer.data = (unsigned long) ioc;
4794 ioc->persist_timer.function = mpt_timer_expired;
4795 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4796 ioc->persist_wait_done=0;
4797 add_timer(&ioc->persist_timer);
4798 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4799 wait_event(mpt_waitq, ioc->persist_wait_done);
4800
4801 sasIoUnitCntrReply =
4802 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4803 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4804 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004805 __func__,
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004806 sasIoUnitCntrReply->IOCStatus,
4807 sasIoUnitCntrReply->IOCLogInfo);
4808 return -1;
4809 }
4810
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004811 printk("%s: success\n",__func__);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004812 return 0;
4813}
4814
4815/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004816
4817static void
4818mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4819 MpiEventDataRaid_t * pRaidEventData)
4820{
4821 int volume;
4822 int reason;
4823 int disk;
4824 int status;
4825 int flags;
4826 int state;
4827
4828 volume = pRaidEventData->VolumeID;
4829 reason = pRaidEventData->ReasonCode;
4830 disk = pRaidEventData->PhysDiskNum;
4831 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4832 flags = (status >> 0) & 0xff;
4833 state = (status >> 8) & 0xff;
4834
4835 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4836 return;
4837 }
4838
4839 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4840 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4841 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004842 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4843 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004844 } else {
4845 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4846 ioc->name, volume);
4847 }
4848
4849 switch(reason) {
4850 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4851 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4852 ioc->name);
4853 break;
4854
4855 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4856
4857 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4858 ioc->name);
4859 break;
4860
4861 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4862 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4863 ioc->name);
4864 break;
4865
4866 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4867 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4868 ioc->name,
4869 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4870 ? "optimal"
4871 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4872 ? "degraded"
4873 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4874 ? "failed"
4875 : "state unknown",
4876 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4877 ? ", enabled" : "",
4878 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4879 ? ", quiesced" : "",
4880 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4881 ? ", resync in progress" : "" );
4882 break;
4883
4884 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4885 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4886 ioc->name, disk);
4887 break;
4888
4889 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4890 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4891 ioc->name);
4892 break;
4893
4894 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4895 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4896 ioc->name);
4897 break;
4898
4899 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4900 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4901 ioc->name);
4902 break;
4903
4904 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4905 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4906 ioc->name,
4907 state == MPI_PHYSDISK0_STATUS_ONLINE
4908 ? "online"
4909 : state == MPI_PHYSDISK0_STATUS_MISSING
4910 ? "missing"
4911 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4912 ? "not compatible"
4913 : state == MPI_PHYSDISK0_STATUS_FAILED
4914 ? "failed"
4915 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4916 ? "initializing"
4917 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4918 ? "offline requested"
4919 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4920 ? "failed requested"
4921 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4922 ? "offline"
4923 : "state unknown",
4924 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4925 ? ", out of sync" : "",
4926 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4927 ? ", quiesced" : "" );
4928 break;
4929
4930 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4931 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4932 ioc->name, disk);
4933 break;
4934
4935 case MPI_EVENT_RAID_RC_SMART_DATA:
4936 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4937 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4938 break;
4939
4940 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4941 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4942 ioc->name, disk);
4943 break;
4944 }
4945}
4946
4947/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004948/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4950 * @ioc: Pointer to MPT_ADAPTER structure
4951 *
4952 * Returns: 0 for success
4953 * -ENOMEM if no memory available
4954 * -EPERM if not allowed due to ISR context
4955 * -EAGAIN if no msg frames currently available
4956 * -EFAULT for non-successful reply or no reply (timeout)
4957 */
4958static int
4959GetIoUnitPage2(MPT_ADAPTER *ioc)
4960{
4961 ConfigPageHeader_t hdr;
4962 CONFIGPARMS cfg;
4963 IOUnitPage2_t *ppage_alloc;
4964 dma_addr_t page_dma;
4965 int data_sz;
4966 int rc;
4967
4968 /* Get the page header */
4969 hdr.PageVersion = 0;
4970 hdr.PageLength = 0;
4971 hdr.PageNumber = 2;
4972 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004973 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 cfg.physAddr = -1;
4975 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4976 cfg.dir = 0;
4977 cfg.pageAddr = 0;
4978 cfg.timeout = 0;
4979
4980 if ((rc = mpt_config(ioc, &cfg)) != 0)
4981 return rc;
4982
4983 if (hdr.PageLength == 0)
4984 return 0;
4985
4986 /* Read the config page */
4987 data_sz = hdr.PageLength * 4;
4988 rc = -ENOMEM;
4989 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4990 if (ppage_alloc) {
4991 memset((u8 *)ppage_alloc, 0, data_sz);
4992 cfg.physAddr = page_dma;
4993 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4994
4995 /* If Good, save data */
4996 if ((rc = mpt_config(ioc, &cfg)) == 0)
4997 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4998
4999 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5000 }
5001
5002 return rc;
5003}
5004
5005/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005006/**
5007 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 * @ioc: Pointer to a Adapter Strucutre
5009 * @portnum: IOC port number
5010 *
5011 * Return: -EFAULT if read of config page header fails
5012 * or if no nvram
5013 * If read of SCSI Port Page 0 fails,
5014 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5015 * Adapter settings: async, narrow
5016 * Return 1
5017 * If read of SCSI Port Page 2 fails,
5018 * Adapter settings valid
5019 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5020 * Return 1
5021 * Else
5022 * Both valid
5023 * Return 0
5024 * CHECK - what type of locking mechanisms should be used????
5025 */
5026static int
5027mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5028{
5029 u8 *pbuf;
5030 dma_addr_t buf_dma;
5031 CONFIGPARMS cfg;
5032 ConfigPageHeader_t header;
5033 int ii;
5034 int data, rc = 0;
5035
5036 /* Allocate memory
5037 */
5038 if (!ioc->spi_data.nvram) {
5039 int sz;
5040 u8 *mem;
5041 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5042 mem = kmalloc(sz, GFP_ATOMIC);
5043 if (mem == NULL)
5044 return -EFAULT;
5045
5046 ioc->spi_data.nvram = (int *) mem;
5047
Prakash, Sathya436ace72007-07-24 15:42:08 +05305048 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 ioc->name, ioc->spi_data.nvram, sz));
5050 }
5051
5052 /* Invalidate NVRAM information
5053 */
5054 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5055 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5056 }
5057
5058 /* Read SPP0 header, allocate memory, then read page.
5059 */
5060 header.PageVersion = 0;
5061 header.PageLength = 0;
5062 header.PageNumber = 0;
5063 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005064 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 cfg.physAddr = -1;
5066 cfg.pageAddr = portnum;
5067 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5068 cfg.dir = 0;
5069 cfg.timeout = 0; /* use default */
5070 if (mpt_config(ioc, &cfg) != 0)
5071 return -EFAULT;
5072
5073 if (header.PageLength > 0) {
5074 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5075 if (pbuf) {
5076 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5077 cfg.physAddr = buf_dma;
5078 if (mpt_config(ioc, &cfg) != 0) {
5079 ioc->spi_data.maxBusWidth = MPT_NARROW;
5080 ioc->spi_data.maxSyncOffset = 0;
5081 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5082 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5083 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305084 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5085 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005086 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 } else {
5088 /* Save the Port Page 0 data
5089 */
5090 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5091 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5092 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5093
5094 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5095 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005096 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5097 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 ioc->name, pPP0->Capabilities));
5099 }
5100 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5101 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5102 if (data) {
5103 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5104 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5105 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305106 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5107 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005108 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 } else {
5110 ioc->spi_data.maxSyncOffset = 0;
5111 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5112 }
5113
5114 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5115
5116 /* Update the minSyncFactor based on bus type.
5117 */
5118 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5119 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5120
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005121 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305123 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5124 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005125 ioc->name, ioc->spi_data.minSyncFactor));
5126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 }
5128 }
5129 if (pbuf) {
5130 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5131 }
5132 }
5133 }
5134
5135 /* SCSI Port Page 2 - Read the header then the page.
5136 */
5137 header.PageVersion = 0;
5138 header.PageLength = 0;
5139 header.PageNumber = 2;
5140 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005141 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 cfg.physAddr = -1;
5143 cfg.pageAddr = portnum;
5144 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5145 cfg.dir = 0;
5146 if (mpt_config(ioc, &cfg) != 0)
5147 return -EFAULT;
5148
5149 if (header.PageLength > 0) {
5150 /* Allocate memory and read SCSI Port Page 2
5151 */
5152 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5153 if (pbuf) {
5154 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5155 cfg.physAddr = buf_dma;
5156 if (mpt_config(ioc, &cfg) != 0) {
5157 /* Nvram data is left with INVALID mark
5158 */
5159 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005160 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5161
5162 /* This is an ATTO adapter, read Page2 accordingly
5163 */
5164 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5165 ATTODeviceInfo_t *pdevice = NULL;
5166 u16 ATTOFlags;
5167
5168 /* Save the Port Page 2 data
5169 * (reformat into a 32bit quantity)
5170 */
5171 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5172 pdevice = &pPP2->DeviceSettings[ii];
5173 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5174 data = 0;
5175
5176 /* Translate ATTO device flags to LSI format
5177 */
5178 if (ATTOFlags & ATTOFLAG_DISC)
5179 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5180 if (ATTOFlags & ATTOFLAG_ID_ENB)
5181 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5182 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5183 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5184 if (ATTOFlags & ATTOFLAG_TAGGED)
5185 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5186 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5187 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5188
5189 data = (data << 16) | (pdevice->Period << 8) | 10;
5190 ioc->spi_data.nvram[ii] = data;
5191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 } else {
5193 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5194 MpiDeviceInfo_t *pdevice = NULL;
5195
Moore, Ericd8e925d2006-01-16 18:53:06 -07005196 /*
5197 * Save "Set to Avoid SCSI Bus Resets" flag
5198 */
5199 ioc->spi_data.bus_reset =
5200 (le32_to_cpu(pPP2->PortFlags) &
5201 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5202 0 : 1 ;
5203
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 /* Save the Port Page 2 data
5205 * (reformat into a 32bit quantity)
5206 */
5207 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5208 ioc->spi_data.PortFlags = data;
5209 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5210 pdevice = &pPP2->DeviceSettings[ii];
5211 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5212 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5213 ioc->spi_data.nvram[ii] = data;
5214 }
5215 }
5216
5217 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5218 }
5219 }
5220
5221 /* Update Adapter limits with those from NVRAM
5222 * Comment: Don't need to do this. Target performance
5223 * parameters will never exceed the adapters limits.
5224 */
5225
5226 return rc;
5227}
5228
5229/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005230/**
5231 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 * @ioc: Pointer to a Adapter Strucutre
5233 * @portnum: IOC port number
5234 *
5235 * Return: -EFAULT if read of config page header fails
5236 * or 0 if success.
5237 */
5238static int
5239mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5240{
5241 CONFIGPARMS cfg;
5242 ConfigPageHeader_t header;
5243
5244 /* Read the SCSI Device Page 1 header
5245 */
5246 header.PageVersion = 0;
5247 header.PageLength = 0;
5248 header.PageNumber = 1;
5249 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005250 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 cfg.physAddr = -1;
5252 cfg.pageAddr = portnum;
5253 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5254 cfg.dir = 0;
5255 cfg.timeout = 0;
5256 if (mpt_config(ioc, &cfg) != 0)
5257 return -EFAULT;
5258
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005259 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5260 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261
5262 header.PageVersion = 0;
5263 header.PageLength = 0;
5264 header.PageNumber = 0;
5265 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5266 if (mpt_config(ioc, &cfg) != 0)
5267 return -EFAULT;
5268
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005269 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5270 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271
Prakash, Sathya436ace72007-07-24 15:42:08 +05305272 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5274
Prakash, Sathya436ace72007-07-24 15:42:08 +05305275 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5277 return 0;
5278}
5279
Eric Mooreb506ade2007-01-29 09:45:37 -07005280/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005281 * mpt_inactive_raid_list_free - This clears this link list.
5282 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005283 **/
5284static void
5285mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5286{
5287 struct inactive_raid_component_info *component_info, *pNext;
5288
5289 if (list_empty(&ioc->raid_data.inactive_list))
5290 return;
5291
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005292 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005293 list_for_each_entry_safe(component_info, pNext,
5294 &ioc->raid_data.inactive_list, list) {
5295 list_del(&component_info->list);
5296 kfree(component_info);
5297 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005298 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005299}
5300
5301/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005302 * 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 -07005303 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005304 * @ioc : pointer to per adapter structure
5305 * @channel : volume channel
5306 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005307 **/
5308static void
5309mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5310{
5311 CONFIGPARMS cfg;
5312 ConfigPageHeader_t hdr;
5313 dma_addr_t dma_handle;
5314 pRaidVolumePage0_t buffer = NULL;
5315 int i;
5316 RaidPhysDiskPage0_t phys_disk;
5317 struct inactive_raid_component_info *component_info;
5318 int handle_inactive_volumes;
5319
5320 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5321 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5322 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5323 cfg.pageAddr = (channel << 8) + id;
5324 cfg.cfghdr.hdr = &hdr;
5325 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5326
5327 if (mpt_config(ioc, &cfg) != 0)
5328 goto out;
5329
5330 if (!hdr.PageLength)
5331 goto out;
5332
5333 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5334 &dma_handle);
5335
5336 if (!buffer)
5337 goto out;
5338
5339 cfg.physAddr = dma_handle;
5340 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5341
5342 if (mpt_config(ioc, &cfg) != 0)
5343 goto out;
5344
5345 if (!buffer->NumPhysDisks)
5346 goto out;
5347
5348 handle_inactive_volumes =
5349 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5350 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5351 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5352 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5353
5354 if (!handle_inactive_volumes)
5355 goto out;
5356
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005357 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005358 for (i = 0; i < buffer->NumPhysDisks; i++) {
5359 if(mpt_raid_phys_disk_pg0(ioc,
5360 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5361 continue;
5362
5363 if ((component_info = kmalloc(sizeof (*component_info),
5364 GFP_KERNEL)) == NULL)
5365 continue;
5366
5367 component_info->volumeID = id;
5368 component_info->volumeBus = channel;
5369 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5370 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5371 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5372 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5373
5374 list_add_tail(&component_info->list,
5375 &ioc->raid_data.inactive_list);
5376 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005377 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005378
5379 out:
5380 if (buffer)
5381 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5382 dma_handle);
5383}
5384
5385/**
5386 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5387 * @ioc: Pointer to a Adapter Structure
5388 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5389 * @phys_disk: requested payload data returned
5390 *
5391 * Return:
5392 * 0 on success
5393 * -EFAULT if read of config page header fails or data pointer not NULL
5394 * -ENOMEM if pci_alloc failed
5395 **/
5396int
5397mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5398{
5399 CONFIGPARMS cfg;
5400 ConfigPageHeader_t hdr;
5401 dma_addr_t dma_handle;
5402 pRaidPhysDiskPage0_t buffer = NULL;
5403 int rc;
5404
5405 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5406 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5407
5408 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5409 cfg.cfghdr.hdr = &hdr;
5410 cfg.physAddr = -1;
5411 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5412
5413 if (mpt_config(ioc, &cfg) != 0) {
5414 rc = -EFAULT;
5415 goto out;
5416 }
5417
5418 if (!hdr.PageLength) {
5419 rc = -EFAULT;
5420 goto out;
5421 }
5422
5423 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5424 &dma_handle);
5425
5426 if (!buffer) {
5427 rc = -ENOMEM;
5428 goto out;
5429 }
5430
5431 cfg.physAddr = dma_handle;
5432 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5433 cfg.pageAddr = phys_disk_num;
5434
5435 if (mpt_config(ioc, &cfg) != 0) {
5436 rc = -EFAULT;
5437 goto out;
5438 }
5439
5440 rc = 0;
5441 memcpy(phys_disk, buffer, sizeof(*buffer));
5442 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5443
5444 out:
5445
5446 if (buffer)
5447 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5448 dma_handle);
5449
5450 return rc;
5451}
5452
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453/**
5454 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5455 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 *
5457 * Return:
5458 * 0 on success
5459 * -EFAULT if read of config page header fails or data pointer not NULL
5460 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005461 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462int
5463mpt_findImVolumes(MPT_ADAPTER *ioc)
5464{
5465 IOCPage2_t *pIoc2;
5466 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 dma_addr_t ioc2_dma;
5468 CONFIGPARMS cfg;
5469 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 int rc = 0;
5471 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005472 int i;
5473
5474 if (!ioc->ir_firmware)
5475 return 0;
5476
5477 /* Free the old page
5478 */
5479 kfree(ioc->raid_data.pIocPg2);
5480 ioc->raid_data.pIocPg2 = NULL;
5481 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482
5483 /* Read IOCP2 header then the page.
5484 */
5485 header.PageVersion = 0;
5486 header.PageLength = 0;
5487 header.PageNumber = 2;
5488 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005489 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 cfg.physAddr = -1;
5491 cfg.pageAddr = 0;
5492 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5493 cfg.dir = 0;
5494 cfg.timeout = 0;
5495 if (mpt_config(ioc, &cfg) != 0)
5496 return -EFAULT;
5497
5498 if (header.PageLength == 0)
5499 return -EFAULT;
5500
5501 iocpage2sz = header.PageLength * 4;
5502 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5503 if (!pIoc2)
5504 return -ENOMEM;
5505
5506 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5507 cfg.physAddr = ioc2_dma;
5508 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005509 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510
Eric Mooreb506ade2007-01-29 09:45:37 -07005511 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5512 if (!mem)
5513 goto out;
5514
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005516 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517
Eric Mooreb506ade2007-01-29 09:45:37 -07005518 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519
Eric Mooreb506ade2007-01-29 09:45:37 -07005520 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5521 mpt_inactive_raid_volumes(ioc,
5522 pIoc2->RaidVolume[i].VolumeBus,
5523 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524
Eric Mooreb506ade2007-01-29 09:45:37 -07005525 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5527
5528 return rc;
5529}
5530
Moore, Ericc972c702006-03-14 09:14:06 -07005531static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5533{
5534 IOCPage3_t *pIoc3;
5535 u8 *mem;
5536 CONFIGPARMS cfg;
5537 ConfigPageHeader_t header;
5538 dma_addr_t ioc3_dma;
5539 int iocpage3sz = 0;
5540
5541 /* Free the old page
5542 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005543 kfree(ioc->raid_data.pIocPg3);
5544 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545
5546 /* There is at least one physical disk.
5547 * Read and save IOC Page 3
5548 */
5549 header.PageVersion = 0;
5550 header.PageLength = 0;
5551 header.PageNumber = 3;
5552 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005553 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 cfg.physAddr = -1;
5555 cfg.pageAddr = 0;
5556 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5557 cfg.dir = 0;
5558 cfg.timeout = 0;
5559 if (mpt_config(ioc, &cfg) != 0)
5560 return 0;
5561
5562 if (header.PageLength == 0)
5563 return 0;
5564
5565 /* Read Header good, alloc memory
5566 */
5567 iocpage3sz = header.PageLength * 4;
5568 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5569 if (!pIoc3)
5570 return 0;
5571
5572 /* Read the Page and save the data
5573 * into malloc'd memory.
5574 */
5575 cfg.physAddr = ioc3_dma;
5576 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5577 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005578 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 if (mem) {
5580 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005581 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 }
5583 }
5584
5585 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5586
5587 return 0;
5588}
5589
5590static void
5591mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5592{
5593 IOCPage4_t *pIoc4;
5594 CONFIGPARMS cfg;
5595 ConfigPageHeader_t header;
5596 dma_addr_t ioc4_dma;
5597 int iocpage4sz;
5598
5599 /* Read and save IOC Page 4
5600 */
5601 header.PageVersion = 0;
5602 header.PageLength = 0;
5603 header.PageNumber = 4;
5604 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005605 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 cfg.physAddr = -1;
5607 cfg.pageAddr = 0;
5608 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5609 cfg.dir = 0;
5610 cfg.timeout = 0;
5611 if (mpt_config(ioc, &cfg) != 0)
5612 return;
5613
5614 if (header.PageLength == 0)
5615 return;
5616
5617 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5618 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5619 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5620 if (!pIoc4)
5621 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005622 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 } else {
5624 ioc4_dma = ioc->spi_data.IocPg4_dma;
5625 iocpage4sz = ioc->spi_data.IocPg4Sz;
5626 }
5627
5628 /* Read the Page into dma memory.
5629 */
5630 cfg.physAddr = ioc4_dma;
5631 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5632 if (mpt_config(ioc, &cfg) == 0) {
5633 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5634 ioc->spi_data.IocPg4_dma = ioc4_dma;
5635 ioc->spi_data.IocPg4Sz = iocpage4sz;
5636 } else {
5637 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5638 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005639 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 }
5641}
5642
5643static void
5644mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5645{
5646 IOCPage1_t *pIoc1;
5647 CONFIGPARMS cfg;
5648 ConfigPageHeader_t header;
5649 dma_addr_t ioc1_dma;
5650 int iocpage1sz = 0;
5651 u32 tmp;
5652
5653 /* Check the Coalescing Timeout in IOC Page 1
5654 */
5655 header.PageVersion = 0;
5656 header.PageLength = 0;
5657 header.PageNumber = 1;
5658 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005659 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 cfg.physAddr = -1;
5661 cfg.pageAddr = 0;
5662 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5663 cfg.dir = 0;
5664 cfg.timeout = 0;
5665 if (mpt_config(ioc, &cfg) != 0)
5666 return;
5667
5668 if (header.PageLength == 0)
5669 return;
5670
5671 /* Read Header good, alloc memory
5672 */
5673 iocpage1sz = header.PageLength * 4;
5674 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5675 if (!pIoc1)
5676 return;
5677
5678 /* Read the Page and check coalescing timeout
5679 */
5680 cfg.physAddr = ioc1_dma;
5681 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5682 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305683
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5685 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5686 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5687
Prakash, Sathya436ace72007-07-24 15:42:08 +05305688 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 ioc->name, tmp));
5690
5691 if (tmp > MPT_COALESCING_TIMEOUT) {
5692 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5693
5694 /* Write NVRAM and current
5695 */
5696 cfg.dir = 1;
5697 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5698 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305699 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 ioc->name, MPT_COALESCING_TIMEOUT));
5701
5702 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5703 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305704 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5705 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 ioc->name, MPT_COALESCING_TIMEOUT));
5707 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305708 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5709 "Reset NVRAM Coalescing Timeout Failed\n",
5710 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711 }
5712
5713 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305714 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5715 "Reset of Current Coalescing Timeout Failed!\n",
5716 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717 }
5718 }
5719
5720 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305721 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722 }
5723 }
5724
5725 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5726
5727 return;
5728}
5729
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305730static void
5731mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5732{
5733 CONFIGPARMS cfg;
5734 ConfigPageHeader_t hdr;
5735 dma_addr_t buf_dma;
5736 ManufacturingPage0_t *pbuf = NULL;
5737
5738 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5739 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5740
5741 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5742 cfg.cfghdr.hdr = &hdr;
5743 cfg.physAddr = -1;
5744 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5745 cfg.timeout = 10;
5746
5747 if (mpt_config(ioc, &cfg) != 0)
5748 goto out;
5749
5750 if (!cfg.cfghdr.hdr->PageLength)
5751 goto out;
5752
5753 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5754 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5755 if (!pbuf)
5756 goto out;
5757
5758 cfg.physAddr = buf_dma;
5759
5760 if (mpt_config(ioc, &cfg) != 0)
5761 goto out;
5762
5763 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5764 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5765 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5766
5767 out:
5768
5769 if (pbuf)
5770 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5771}
5772
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005774/**
5775 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 * @ioc: Pointer to MPT_ADAPTER structure
5777 * @EvSwitch: Event switch flags
5778 */
5779static int
5780SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5781{
5782 EventNotification_t *evnp;
5783
5784 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5785 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305786 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787 ioc->name));
5788 return 0;
5789 }
5790 memset(evnp, 0, sizeof(*evnp));
5791
Prakash, Sathya436ace72007-07-24 15:42:08 +05305792 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793
5794 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5795 evnp->ChainOffset = 0;
5796 evnp->MsgFlags = 0;
5797 evnp->Switch = EvSwitch;
5798
5799 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5800
5801 return 0;
5802}
5803
5804/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5805/**
5806 * SendEventAck - Send EventAck request to MPT adapter.
5807 * @ioc: Pointer to MPT_ADAPTER structure
5808 * @evnp: Pointer to original EventNotification request
5809 */
5810static int
5811SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5812{
5813 EventAck_t *pAck;
5814
5815 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305816 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005817 ioc->name,__func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818 return -1;
5819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820
Prakash, Sathya436ace72007-07-24 15:42:08 +05305821 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822
5823 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5824 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005825 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005827 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828 pAck->Event = evnp->Event;
5829 pAck->EventContext = evnp->EventContext;
5830
5831 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5832
5833 return 0;
5834}
5835
5836/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5837/**
5838 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005839 * @ioc: Pointer to an adapter structure
5840 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841 * action, page address, direction, physical address
5842 * and pointer to a configuration page header
5843 * Page header is updated.
5844 *
5845 * Returns 0 for success
5846 * -EPERM if not allowed due to ISR context
5847 * -EAGAIN if no msg frames currently available
5848 * -EFAULT for non-successful reply or no reply (timeout)
5849 */
5850int
5851mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5852{
5853 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005854 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005855 MPT_FRAME_HDR *mf;
5856 unsigned long flags;
5857 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005858 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859 int in_isr;
5860
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005861 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862 * to be in ISR context, because that is fatal!
5863 */
5864 in_isr = in_interrupt();
5865 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305866 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 ioc->name));
5868 return -EPERM;
5869 }
5870
5871 /* Get and Populate a free Frame
5872 */
5873 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305874 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 ioc->name));
5876 return -EAGAIN;
5877 }
5878 pReq = (Config_t *)mf;
5879 pReq->Action = pCfg->action;
5880 pReq->Reserved = 0;
5881 pReq->ChainOffset = 0;
5882 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005883
5884 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 pReq->ExtPageLength = 0;
5886 pReq->ExtPageType = 0;
5887 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005888
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889 for (ii=0; ii < 8; ii++)
5890 pReq->Reserved2[ii] = 0;
5891
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005892 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5893 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5894 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5895 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5896
5897 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5898 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5899 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5900 pReq->ExtPageType = pExtHdr->ExtPageType;
5901 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5902
5903 /* Page Length must be treated as a reserved field for the extended header. */
5904 pReq->Header.PageLength = 0;
5905 }
5906
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5908
5909 /* Add a SGE to the config request.
5910 */
5911 if (pCfg->dir)
5912 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5913 else
5914 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5915
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005916 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5917 flagsLength |= pExtHdr->ExtPageLength * 4;
5918
Prakash, Sathya436ace72007-07-24 15:42:08 +05305919 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005920 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5921 }
5922 else {
5923 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5924
Prakash, Sathya436ace72007-07-24 15:42:08 +05305925 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005926 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928
5929 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5930
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 /* Append pCfg pointer to end of mf
5932 */
5933 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5934
5935 /* Initalize the timer
5936 */
5937 init_timer(&pCfg->timer);
5938 pCfg->timer.data = (unsigned long) ioc;
5939 pCfg->timer.function = mpt_timer_expired;
5940 pCfg->wait_done = 0;
5941
5942 /* Set the timer; ensure 10 second minimum */
5943 if (pCfg->timeout < 10)
5944 pCfg->timer.expires = jiffies + HZ*10;
5945 else
5946 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5947
5948 /* Add to end of Q, set timer and then issue this command */
5949 spin_lock_irqsave(&ioc->FreeQlock, flags);
5950 list_add_tail(&pCfg->linkage, &ioc->configQ);
5951 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5952
5953 add_timer(&pCfg->timer);
5954 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5955 wait_event(mpt_waitq, pCfg->wait_done);
5956
5957 /* mf has been freed - do not access */
5958
5959 rc = pCfg->status;
5960
5961 return rc;
5962}
5963
5964/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005965/**
5966 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 * Used only internal config functionality.
5968 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5969 */
5970static void
5971mpt_timer_expired(unsigned long data)
5972{
5973 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5974
Prakash, Sathya436ace72007-07-24 15:42:08 +05305975 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976
5977 /* Perform a FW reload */
5978 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5979 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5980
5981 /* No more processing.
5982 * Hard reset clean-up will wake up
5983 * process and free all resources.
5984 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305985 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
5987 return;
5988}
5989
5990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005991/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 * mpt_ioc_reset - Base cleanup for hard reset
5993 * @ioc: Pointer to the adapter structure
5994 * @reset_phase: Indicates pre- or post-reset functionality
5995 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005996 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997 */
5998static int
5999mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6000{
6001 CONFIGPARMS *pCfg;
6002 unsigned long flags;
6003
Eric Moore29dd3602007-09-14 18:46:51 -06006004 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6005 ": IOC %s_reset routed to MPT base driver!\n",
6006 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
6007 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008
6009 if (reset_phase == MPT_IOC_SETUP_RESET) {
6010 ;
6011 } else if (reset_phase == MPT_IOC_PRE_RESET) {
6012 /* If the internal config Q is not empty -
6013 * delete timer. MF resources will be freed when
6014 * the FIFO's are primed.
6015 */
6016 spin_lock_irqsave(&ioc->FreeQlock, flags);
6017 list_for_each_entry(pCfg, &ioc->configQ, linkage)
6018 del_timer(&pCfg->timer);
6019 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6020
6021 } else {
6022 CONFIGPARMS *pNext;
6023
6024 /* Search the configQ for internal commands.
6025 * Flush the Q, and wake up all suspended threads.
6026 */
6027 spin_lock_irqsave(&ioc->FreeQlock, flags);
6028 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
6029 list_del(&pCfg->linkage);
6030
6031 pCfg->status = MPT_CONFIG_ERROR;
6032 pCfg->wait_done = 1;
6033 wake_up(&mpt_waitq);
6034 }
6035 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6036 }
6037
6038 return 1; /* currently means nothing really */
6039}
6040
6041
6042#ifdef CONFIG_PROC_FS /* { */
6043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6044/*
6045 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6046 */
6047/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006048/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6050 *
6051 * Returns 0 for success, non-zero for failure.
6052 */
6053static int
6054procmpt_create(void)
6055{
6056 struct proc_dir_entry *ent;
6057
6058 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6059 if (mpt_proc_root_dir == NULL)
6060 return -ENOTDIR;
6061
6062 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6063 if (ent)
6064 ent->read_proc = procmpt_summary_read;
6065
6066 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6067 if (ent)
6068 ent->read_proc = procmpt_version_read;
6069
6070 return 0;
6071}
6072
6073/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006074/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6076 *
6077 * Returns 0 for success, non-zero for failure.
6078 */
6079static void
6080procmpt_destroy(void)
6081{
6082 remove_proc_entry("version", mpt_proc_root_dir);
6083 remove_proc_entry("summary", mpt_proc_root_dir);
6084 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6085}
6086
6087/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006088/**
6089 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090 * @buf: Pointer to area to write information
6091 * @start: Pointer to start pointer
6092 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006093 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 * @eof: Pointer to EOF integer
6095 * @data: Pointer
6096 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006097 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098 * Returns number of characters written to process performing the read.
6099 */
6100static int
6101procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6102{
6103 MPT_ADAPTER *ioc;
6104 char *out = buf;
6105 int len;
6106
6107 if (data) {
6108 int more = 0;
6109
6110 ioc = data;
6111 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6112
6113 out += more;
6114 } else {
6115 list_for_each_entry(ioc, &ioc_list, list) {
6116 int more = 0;
6117
6118 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6119
6120 out += more;
6121 if ((out-buf) >= request)
6122 break;
6123 }
6124 }
6125
6126 len = out - buf;
6127
6128 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6129}
6130
6131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006132/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133 * procmpt_version_read - Handle read request from /proc/mpt/version.
6134 * @buf: Pointer to area to write information
6135 * @start: Pointer to start pointer
6136 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006137 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006138 * @eof: Pointer to EOF integer
6139 * @data: Pointer
6140 *
6141 * Returns number of characters written to process performing the read.
6142 */
6143static int
6144procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6145{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306146 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006147 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148 char *drvname;
6149 int len;
6150
6151 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6152 len += sprintf(buf+len, " Fusion MPT base driver\n");
6153
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006154 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006155 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306157 if (MptCallbacks[cb_idx]) {
6158 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006159 case MPTSPI_DRIVER:
6160 if (!scsi++) drvname = "SPI host";
6161 break;
6162 case MPTFC_DRIVER:
6163 if (!fc++) drvname = "FC host";
6164 break;
6165 case MPTSAS_DRIVER:
6166 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006167 break;
6168 case MPTLAN_DRIVER:
6169 if (!lan++) drvname = "LAN";
6170 break;
6171 case MPTSTM_DRIVER:
6172 if (!targ++) drvname = "SCSI target";
6173 break;
6174 case MPTCTL_DRIVER:
6175 if (!ctl++) drvname = "ioctl";
6176 break;
6177 }
6178
6179 if (drvname)
6180 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6181 }
6182 }
6183
6184 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6185}
6186
6187/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006188/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6190 * @buf: Pointer to area to write information
6191 * @start: Pointer to start pointer
6192 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006193 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006194 * @eof: Pointer to EOF integer
6195 * @data: Pointer
6196 *
6197 * Returns number of characters written to process performing the read.
6198 */
6199static int
6200procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6201{
6202 MPT_ADAPTER *ioc = data;
6203 int len;
6204 char expVer[32];
6205 int sz;
6206 int p;
6207
6208 mpt_get_fw_exp_ver(expVer, ioc);
6209
6210 len = sprintf(buf, "%s:", ioc->name);
6211 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6212 len += sprintf(buf+len, " (f/w download boot flag set)");
6213// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6214// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6215
6216 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6217 ioc->facts.ProductID,
6218 ioc->prod_name);
6219 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6220 if (ioc->facts.FWImageSize)
6221 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6222 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6223 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6224 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6225
6226 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6227 ioc->facts.CurrentHostMfaHighAddr);
6228 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6229 ioc->facts.CurrentSenseBufferHighAddr);
6230
6231 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6232 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6233
6234 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6235 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6236 /*
6237 * Rounding UP to nearest 4-kB boundary here...
6238 */
6239 sz = (ioc->req_sz * ioc->req_depth) + 128;
6240 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6241 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6242 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6243 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6244 4*ioc->facts.RequestFrameSize,
6245 ioc->facts.GlobalCredits);
6246
6247 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6248 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6249 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6250 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6251 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6252 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6253 ioc->facts.CurReplyFrameSize,
6254 ioc->facts.ReplyQueueDepth);
6255
6256 len += sprintf(buf+len, " MaxDevices = %d\n",
6257 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6258 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6259
6260 /* per-port info */
6261 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6262 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6263 p+1,
6264 ioc->facts.NumberOfPorts);
6265 if (ioc->bus_type == FC) {
6266 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6267 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6268 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6269 a[5], a[4], a[3], a[2], a[1], a[0]);
6270 }
6271 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6272 ioc->fc_port_page0[p].WWNN.High,
6273 ioc->fc_port_page0[p].WWNN.Low,
6274 ioc->fc_port_page0[p].WWPN.High,
6275 ioc->fc_port_page0[p].WWPN.Low);
6276 }
6277 }
6278
6279 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6280}
6281
6282#endif /* CONFIG_PROC_FS } */
6283
6284/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6285static void
6286mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6287{
6288 buf[0] ='\0';
6289 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6290 sprintf(buf, " (Exp %02d%02d)",
6291 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6292 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6293
6294 /* insider hack! */
6295 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6296 strcat(buf, " [MDBG]");
6297 }
6298}
6299
6300/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6301/**
6302 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6303 * @ioc: Pointer to MPT_ADAPTER structure
6304 * @buffer: Pointer to buffer where IOC summary info should be written
6305 * @size: Pointer to number of bytes we wrote (set by this routine)
6306 * @len: Offset at which to start writing in buffer
6307 * @showlan: Display LAN stuff?
6308 *
6309 * This routine writes (english readable) ASCII text, which represents
6310 * a summary of IOC information, to a buffer.
6311 */
6312void
6313mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6314{
6315 char expVer[32];
6316 int y;
6317
6318 mpt_get_fw_exp_ver(expVer, ioc);
6319
6320 /*
6321 * Shorter summary of attached ioc's...
6322 */
6323 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6324 ioc->name,
6325 ioc->prod_name,
6326 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6327 ioc->facts.FWVersion.Word,
6328 expVer,
6329 ioc->facts.NumberOfPorts,
6330 ioc->req_depth);
6331
6332 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6333 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6334 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6335 a[5], a[4], a[3], a[2], a[1], a[0]);
6336 }
6337
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339
6340 if (!ioc->active)
6341 y += sprintf(buffer+len+y, " (disabled)");
6342
6343 y += sprintf(buffer+len+y, "\n");
6344
6345 *size = y;
6346}
6347
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306348
6349/**
6350 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6351 * the kernel
6352 * @ioc: Pointer to MPT_ADAPTER structure
6353 *
6354 **/
6355void
6356mpt_halt_firmware(MPT_ADAPTER *ioc)
6357{
6358 u32 ioc_raw_state;
6359
6360 ioc_raw_state = mpt_GetIocState(ioc, 0);
6361
6362 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6363 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6364 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6365 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6366 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6367 } else {
6368 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6369 panic("%s: Firmware is halted due to command timeout\n",
6370 ioc->name);
6371 }
6372}
6373EXPORT_SYMBOL(mpt_halt_firmware);
6374
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6376/*
6377 * Reset Handling
6378 */
6379/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6380/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006381 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 * @ioc: Pointer to MPT_ADAPTER structure
6383 * @sleepFlag: Indicates if sleep or schedule must be called.
6384 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006385 * Issues SCSI Task Management call based on input arg values.
6386 * If TaskMgmt fails, returns associated SCSI request.
6387 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6389 * or a non-interrupt thread. In the former, must not call schedule().
6390 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006391 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392 * FW reload/initialization failed.
6393 *
6394 * Returns 0 for SUCCESS or -1 if FAILED.
6395 */
6396int
6397mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6398{
6399 int rc;
6400 unsigned long flags;
6401
Prakash, Sathya436ace72007-07-24 15:42:08 +05306402 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403#ifdef MFCNT
6404 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6405 printk("MF count 0x%x !\n", ioc->mfcnt);
6406#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306407 if (mpt_fwfault_debug)
6408 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409
6410 /* Reset the adapter. Prevent more than 1 call to
6411 * mpt_do_ioc_recovery at any instant in time.
6412 */
6413 spin_lock_irqsave(&ioc->diagLock, flags);
6414 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6415 spin_unlock_irqrestore(&ioc->diagLock, flags);
6416 return 0;
6417 } else {
6418 ioc->diagPending = 1;
6419 }
6420 spin_unlock_irqrestore(&ioc->diagLock, flags);
6421
6422 /* FIXME: If do_ioc_recovery fails, repeat....
6423 */
6424
6425 /* The SCSI driver needs to adjust timeouts on all current
6426 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006427 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428 * For all other protocol drivers, this is a no-op.
6429 */
6430 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306431 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006432 int r = 0;
6433
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306434 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6435 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306436 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306437 ioc->name, cb_idx));
6438 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006439 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306440 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306441 ioc->name, ioc->alt_ioc->name, cb_idx));
6442 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006443 }
6444 }
6445 }
6446 }
6447
6448 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006449 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450 }
6451 ioc->reload_fw = 0;
6452 if (ioc->alt_ioc)
6453 ioc->alt_ioc->reload_fw = 0;
6454
6455 spin_lock_irqsave(&ioc->diagLock, flags);
6456 ioc->diagPending = 0;
6457 if (ioc->alt_ioc)
6458 ioc->alt_ioc->diagPending = 0;
6459 spin_unlock_irqrestore(&ioc->diagLock, flags);
6460
Prakash, Sathya436ace72007-07-24 15:42:08 +05306461 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006462
6463 return rc;
6464}
6465
6466/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006467static void
6468EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006469{
Eric Moore509e5e52006-04-26 13:22:37 -06006470 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471
6472 switch(event) {
6473 case MPI_EVENT_NONE:
6474 ds = "None";
6475 break;
6476 case MPI_EVENT_LOG_DATA:
6477 ds = "Log Data";
6478 break;
6479 case MPI_EVENT_STATE_CHANGE:
6480 ds = "State Change";
6481 break;
6482 case MPI_EVENT_UNIT_ATTENTION:
6483 ds = "Unit Attention";
6484 break;
6485 case MPI_EVENT_IOC_BUS_RESET:
6486 ds = "IOC Bus Reset";
6487 break;
6488 case MPI_EVENT_EXT_BUS_RESET:
6489 ds = "External Bus Reset";
6490 break;
6491 case MPI_EVENT_RESCAN:
6492 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006493 break;
6494 case MPI_EVENT_LINK_STATUS_CHANGE:
6495 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6496 ds = "Link Status(FAILURE) Change";
6497 else
6498 ds = "Link Status(ACTIVE) Change";
6499 break;
6500 case MPI_EVENT_LOOP_STATE_CHANGE:
6501 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6502 ds = "Loop State(LIP) Change";
6503 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006504 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006505 else
Eric Moore509e5e52006-04-26 13:22:37 -06006506 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006507 break;
6508 case MPI_EVENT_LOGOUT:
6509 ds = "Logout";
6510 break;
6511 case MPI_EVENT_EVENT_CHANGE:
6512 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006513 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006514 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006515 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516 break;
6517 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006518 {
6519 u8 ReasonCode = (u8)(evData0 >> 16);
6520 switch (ReasonCode) {
6521 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6522 ds = "Integrated Raid: Volume Created";
6523 break;
6524 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6525 ds = "Integrated Raid: Volume Deleted";
6526 break;
6527 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6528 ds = "Integrated Raid: Volume Settings Changed";
6529 break;
6530 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6531 ds = "Integrated Raid: Volume Status Changed";
6532 break;
6533 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6534 ds = "Integrated Raid: Volume Physdisk Changed";
6535 break;
6536 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6537 ds = "Integrated Raid: Physdisk Created";
6538 break;
6539 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6540 ds = "Integrated Raid: Physdisk Deleted";
6541 break;
6542 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6543 ds = "Integrated Raid: Physdisk Settings Changed";
6544 break;
6545 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6546 ds = "Integrated Raid: Physdisk Status Changed";
6547 break;
6548 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6549 ds = "Integrated Raid: Domain Validation Needed";
6550 break;
6551 case MPI_EVENT_RAID_RC_SMART_DATA :
6552 ds = "Integrated Raid; Smart Data";
6553 break;
6554 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6555 ds = "Integrated Raid: Replace Action Started";
6556 break;
6557 default:
6558 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006559 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006560 }
6561 break;
6562 }
6563 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6564 ds = "SCSI Device Status Change";
6565 break;
6566 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6567 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006568 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006569 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006570 u8 ReasonCode = (u8)(evData0 >> 16);
6571 switch (ReasonCode) {
6572 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006573 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006574 "SAS Device Status Change: Added: "
6575 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006576 break;
6577 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006578 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006579 "SAS Device Status Change: Deleted: "
6580 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006581 break;
6582 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006583 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006584 "SAS Device Status Change: SMART Data: "
6585 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006586 break;
6587 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006588 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006589 "SAS Device Status Change: No Persistancy: "
6590 "id=%d channel=%d", id, channel);
6591 break;
6592 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6593 snprintf(evStr, EVENT_DESCR_STR_SZ,
6594 "SAS Device Status Change: Unsupported Device "
6595 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006596 break;
6597 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6598 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006599 "SAS Device Status Change: Internal Device "
6600 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006601 break;
6602 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6603 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006604 "SAS Device Status Change: Internal Task "
6605 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006606 break;
6607 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6608 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006609 "SAS Device Status Change: Internal Abort "
6610 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006611 break;
6612 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6613 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006614 "SAS Device Status Change: Internal Clear "
6615 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006616 break;
6617 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6618 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006619 "SAS Device Status Change: Internal Query "
6620 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006621 break;
6622 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006623 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006624 "SAS Device Status Change: Unknown: "
6625 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006626 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006627 }
6628 break;
6629 }
6630 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6631 ds = "Bus Timer Expired";
6632 break;
6633 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006634 {
6635 u16 curr_depth = (u16)(evData0 >> 16);
6636 u8 channel = (u8)(evData0 >> 8);
6637 u8 id = (u8)(evData0);
6638
6639 snprintf(evStr, EVENT_DESCR_STR_SZ,
6640 "Queue Full: channel=%d id=%d depth=%d",
6641 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006642 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006643 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006644 case MPI_EVENT_SAS_SES:
6645 ds = "SAS SES Event";
6646 break;
6647 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6648 ds = "Persistent Table Full";
6649 break;
6650 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006651 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006652 u8 LinkRates = (u8)(evData0 >> 8);
6653 u8 PhyNumber = (u8)(evData0);
6654 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6655 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6656 switch (LinkRates) {
6657 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006658 snprintf(evStr, EVENT_DESCR_STR_SZ,
6659 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006660 " Rate Unknown",PhyNumber);
6661 break;
6662 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006663 snprintf(evStr, EVENT_DESCR_STR_SZ,
6664 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006665 " Phy Disabled",PhyNumber);
6666 break;
6667 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006668 snprintf(evStr, EVENT_DESCR_STR_SZ,
6669 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006670 " Failed Speed Nego",PhyNumber);
6671 break;
6672 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006673 snprintf(evStr, EVENT_DESCR_STR_SZ,
6674 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006675 " Sata OOB Completed",PhyNumber);
6676 break;
6677 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006678 snprintf(evStr, EVENT_DESCR_STR_SZ,
6679 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006680 " Rate 1.5 Gbps",PhyNumber);
6681 break;
6682 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006683 snprintf(evStr, EVENT_DESCR_STR_SZ,
6684 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006685 " Rate 3.0 Gpbs",PhyNumber);
6686 break;
6687 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006688 snprintf(evStr, EVENT_DESCR_STR_SZ,
6689 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006690 break;
6691 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006692 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006693 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006694 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6695 ds = "SAS Discovery Error";
6696 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006697 case MPI_EVENT_IR_RESYNC_UPDATE:
6698 {
6699 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006700 snprintf(evStr, EVENT_DESCR_STR_SZ,
6701 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006702 break;
6703 }
6704 case MPI_EVENT_IR2:
6705 {
6706 u8 ReasonCode = (u8)(evData0 >> 16);
6707 switch (ReasonCode) {
6708 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6709 ds = "IR2: LD State Changed";
6710 break;
6711 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6712 ds = "IR2: PD State Changed";
6713 break;
6714 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6715 ds = "IR2: Bad Block Table Full";
6716 break;
6717 case MPI_EVENT_IR2_RC_PD_INSERTED:
6718 ds = "IR2: PD Inserted";
6719 break;
6720 case MPI_EVENT_IR2_RC_PD_REMOVED:
6721 ds = "IR2: PD Removed";
6722 break;
6723 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6724 ds = "IR2: Foreign CFG Detected";
6725 break;
6726 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6727 ds = "IR2: Rebuild Medium Error";
6728 break;
6729 default:
6730 ds = "IR2";
6731 break;
6732 }
6733 break;
6734 }
6735 case MPI_EVENT_SAS_DISCOVERY:
6736 {
6737 if (evData0)
6738 ds = "SAS Discovery: Start";
6739 else
6740 ds = "SAS Discovery: Stop";
6741 break;
6742 }
6743 case MPI_EVENT_LOG_ENTRY_ADDED:
6744 ds = "SAS Log Entry Added";
6745 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006746
Eric Moorec6c727a2007-01-29 09:44:54 -07006747 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6748 {
6749 u8 phy_num = (u8)(evData0);
6750 u8 port_num = (u8)(evData0 >> 8);
6751 u8 port_width = (u8)(evData0 >> 16);
6752 u8 primative = (u8)(evData0 >> 24);
6753 snprintf(evStr, EVENT_DESCR_STR_SZ,
6754 "SAS Broadcase Primative: phy=%d port=%d "
6755 "width=%d primative=0x%02x",
6756 phy_num, port_num, port_width, primative);
6757 break;
6758 }
6759
6760 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6761 {
6762 u8 reason = (u8)(evData0);
6763 u8 port_num = (u8)(evData0 >> 8);
6764 u16 handle = le16_to_cpu(evData0 >> 16);
6765
6766 snprintf(evStr, EVENT_DESCR_STR_SZ,
6767 "SAS Initiator Device Status Change: reason=0x%02x "
6768 "port=%d handle=0x%04x",
6769 reason, port_num, handle);
6770 break;
6771 }
6772
6773 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6774 {
6775 u8 max_init = (u8)(evData0);
6776 u8 current_init = (u8)(evData0 >> 8);
6777
6778 snprintf(evStr, EVENT_DESCR_STR_SZ,
6779 "SAS Initiator Device Table Overflow: max initiators=%02d "
6780 "current initators=%02d",
6781 max_init, current_init);
6782 break;
6783 }
6784 case MPI_EVENT_SAS_SMP_ERROR:
6785 {
6786 u8 status = (u8)(evData0);
6787 u8 port_num = (u8)(evData0 >> 8);
6788 u8 result = (u8)(evData0 >> 16);
6789
6790 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6791 snprintf(evStr, EVENT_DESCR_STR_SZ,
6792 "SAS SMP Error: port=%d result=0x%02x",
6793 port_num, result);
6794 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6795 snprintf(evStr, EVENT_DESCR_STR_SZ,
6796 "SAS SMP Error: port=%d : CRC Error",
6797 port_num);
6798 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6799 snprintf(evStr, EVENT_DESCR_STR_SZ,
6800 "SAS SMP Error: port=%d : Timeout",
6801 port_num);
6802 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6803 snprintf(evStr, EVENT_DESCR_STR_SZ,
6804 "SAS SMP Error: port=%d : No Destination",
6805 port_num);
6806 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6807 snprintf(evStr, EVENT_DESCR_STR_SZ,
6808 "SAS SMP Error: port=%d : Bad Destination",
6809 port_num);
6810 else
6811 snprintf(evStr, EVENT_DESCR_STR_SZ,
6812 "SAS SMP Error: port=%d : status=0x%02x",
6813 port_num, status);
6814 break;
6815 }
6816
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817 /*
6818 * MPT base "custom" events may be added here...
6819 */
6820 default:
6821 ds = "Unknown";
6822 break;
6823 }
Eric Moore509e5e52006-04-26 13:22:37 -06006824 if (ds)
6825 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006826}
6827
6828/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006829/**
6830 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831 * @ioc: Pointer to MPT_ADAPTER structure
6832 * @pEventReply: Pointer to EventNotification reply frame
6833 * @evHandlers: Pointer to integer, number of event handlers
6834 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006835 * Routes a received EventNotificationReply to all currently registered
6836 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006837 * Returns sum of event handlers return values.
6838 */
6839static int
6840ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6841{
6842 u16 evDataLen;
6843 u32 evData0 = 0;
6844// u32 evCtx;
6845 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306846 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006847 int r = 0;
6848 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006849 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850 u8 event;
6851
6852 /*
6853 * Do platform normalization of values
6854 */
6855 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6856// evCtx = le32_to_cpu(pEventReply->EventContext);
6857 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6858 if (evDataLen) {
6859 evData0 = le32_to_cpu(pEventReply->Data[0]);
6860 }
6861
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006862 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306863 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006864 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006865 event,
6866 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006867
Prakash, Sathya436ace72007-07-24 15:42:08 +05306868#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006869 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6870 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006871 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306872 devtverboseprintk(ioc, printk(" %08x",
6873 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006874 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006875#endif
6876
6877 /*
6878 * Do general / base driver event processing
6879 */
6880 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006881 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6882 if (evDataLen) {
6883 u8 evState = evData0 & 0xFF;
6884
6885 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6886
6887 /* Update EventState field in cached IocFacts */
6888 if (ioc->facts.Function) {
6889 ioc->facts.EventState = evState;
6890 }
6891 }
6892 break;
Moore, Ericece50912006-01-16 18:53:19 -07006893 case MPI_EVENT_INTEGRATED_RAID:
6894 mptbase_raid_process_event_data(ioc,
6895 (MpiEventDataRaid_t *)pEventReply->Data);
6896 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006897 default:
6898 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006899 }
6900
6901 /*
6902 * Should this event be logged? Events are written sequentially.
6903 * When buffer is full, start again at the top.
6904 */
6905 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6906 int idx;
6907
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006908 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006909
6910 ioc->events[idx].event = event;
6911 ioc->events[idx].eventContext = ioc->eventContext;
6912
6913 for (ii = 0; ii < 2; ii++) {
6914 if (ii < evDataLen)
6915 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6916 else
6917 ioc->events[idx].data[ii] = 0;
6918 }
6919
6920 ioc->eventContext++;
6921 }
6922
6923
6924 /*
6925 * Call each currently registered protocol event handler.
6926 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006927 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306928 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306929 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306930 ioc->name, cb_idx));
6931 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006932 handlers++;
6933 }
6934 }
6935 /* FIXME? Examine results here? */
6936
6937 /*
6938 * If needed, send (a single) EventAck.
6939 */
6940 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306941 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006942 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306944 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006945 ioc->name, ii));
6946 }
6947 }
6948
6949 *evHandlers = handlers;
6950 return r;
6951}
6952
6953/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006954/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006955 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6956 * @ioc: Pointer to MPT_ADAPTER structure
6957 * @log_info: U32 LogInfo reply word from the IOC
6958 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006959 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006960 */
6961static void
6962mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6963{
Eric Moore7c431e52007-06-13 16:34:36 -06006964 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006965
Eric Moore7c431e52007-06-13 16:34:36 -06006966 switch (log_info & 0xFF000000) {
6967 case MPI_IOCLOGINFO_FC_INIT_BASE:
6968 desc = "FCP Initiator";
6969 break;
6970 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6971 desc = "FCP Target";
6972 break;
6973 case MPI_IOCLOGINFO_FC_LAN_BASE:
6974 desc = "LAN";
6975 break;
6976 case MPI_IOCLOGINFO_FC_MSG_BASE:
6977 desc = "MPI Message Layer";
6978 break;
6979 case MPI_IOCLOGINFO_FC_LINK_BASE:
6980 desc = "FC Link";
6981 break;
6982 case MPI_IOCLOGINFO_FC_CTX_BASE:
6983 desc = "Context Manager";
6984 break;
6985 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6986 desc = "Invalid Field Offset";
6987 break;
6988 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6989 desc = "State Change Info";
6990 break;
6991 }
6992
6993 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6994 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006995}
6996
6997/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006998/**
Moore, Eric335a9412006-01-17 17:06:23 -07006999 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007000 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007001 * @log_info: U32 LogInfo word from the IOC
7002 *
7003 * Refer to lsi/sp_log.h.
7004 */
7005static void
Moore, Eric335a9412006-01-17 17:06:23 -07007006mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007{
7008 u32 info = log_info & 0x00FF0000;
7009 char *desc = "unknown";
7010
7011 switch (info) {
7012 case 0x00010000:
7013 desc = "bug! MID not found";
7014 if (ioc->reload_fw == 0)
7015 ioc->reload_fw++;
7016 break;
7017
7018 case 0x00020000:
7019 desc = "Parity Error";
7020 break;
7021
7022 case 0x00030000:
7023 desc = "ASYNC Outbound Overrun";
7024 break;
7025
7026 case 0x00040000:
7027 desc = "SYNC Offset Error";
7028 break;
7029
7030 case 0x00050000:
7031 desc = "BM Change";
7032 break;
7033
7034 case 0x00060000:
7035 desc = "Msg In Overflow";
7036 break;
7037
7038 case 0x00070000:
7039 desc = "DMA Error";
7040 break;
7041
7042 case 0x00080000:
7043 desc = "Outbound DMA Overrun";
7044 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007045
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046 case 0x00090000:
7047 desc = "Task Management";
7048 break;
7049
7050 case 0x000A0000:
7051 desc = "Device Problem";
7052 break;
7053
7054 case 0x000B0000:
7055 desc = "Invalid Phase Change";
7056 break;
7057
7058 case 0x000C0000:
7059 desc = "Untagged Table Size";
7060 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007061
Linus Torvalds1da177e2005-04-16 15:20:36 -07007062 }
7063
7064 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7065}
7066
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007067/* strings for sas loginfo */
7068 static char *originator_str[] = {
7069 "IOP", /* 00h */
7070 "PL", /* 01h */
7071 "IR" /* 02h */
7072 };
7073 static char *iop_code_str[] = {
7074 NULL, /* 00h */
7075 "Invalid SAS Address", /* 01h */
7076 NULL, /* 02h */
7077 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007078 "Diag Message Error", /* 04h */
7079 "Task Terminated", /* 05h */
7080 "Enclosure Management", /* 06h */
7081 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007082 };
7083 static char *pl_code_str[] = {
7084 NULL, /* 00h */
7085 "Open Failure", /* 01h */
7086 "Invalid Scatter Gather List", /* 02h */
7087 "Wrong Relative Offset or Frame Length", /* 03h */
7088 "Frame Transfer Error", /* 04h */
7089 "Transmit Frame Connected Low", /* 05h */
7090 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7091 "SATA Read Log Receive Data Error", /* 07h */
7092 "SATA NCQ Fail All Commands After Error", /* 08h */
7093 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7094 "Receive Frame Invalid Message", /* 0Ah */
7095 "Receive Context Message Valid Error", /* 0Bh */
7096 "Receive Frame Current Frame Error", /* 0Ch */
7097 "SATA Link Down", /* 0Dh */
7098 "Discovery SATA Init W IOS", /* 0Eh */
7099 "Config Invalid Page", /* 0Fh */
7100 "Discovery SATA Init Timeout", /* 10h */
7101 "Reset", /* 11h */
7102 "Abort", /* 12h */
7103 "IO Not Yet Executed", /* 13h */
7104 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007105 "Persistent Reservation Out Not Affiliation "
7106 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007107 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007108 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007109 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007110 NULL, /* 19h */
7111 NULL, /* 1Ah */
7112 NULL, /* 1Bh */
7113 NULL, /* 1Ch */
7114 NULL, /* 1Dh */
7115 NULL, /* 1Eh */
7116 NULL, /* 1Fh */
7117 "Enclosure Management" /* 20h */
7118 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007119 static char *ir_code_str[] = {
7120 "Raid Action Error", /* 00h */
7121 NULL, /* 00h */
7122 NULL, /* 01h */
7123 NULL, /* 02h */
7124 NULL, /* 03h */
7125 NULL, /* 04h */
7126 NULL, /* 05h */
7127 NULL, /* 06h */
7128 NULL /* 07h */
7129 };
7130 static char *raid_sub_code_str[] = {
7131 NULL, /* 00h */
7132 "Volume Creation Failed: Data Passed too "
7133 "Large", /* 01h */
7134 "Volume Creation Failed: Duplicate Volumes "
7135 "Attempted", /* 02h */
7136 "Volume Creation Failed: Max Number "
7137 "Supported Volumes Exceeded", /* 03h */
7138 "Volume Creation Failed: DMA Error", /* 04h */
7139 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7140 "Volume Creation Failed: Error Reading "
7141 "MFG Page 4", /* 06h */
7142 "Volume Creation Failed: Creating Internal "
7143 "Structures", /* 07h */
7144 NULL, /* 08h */
7145 NULL, /* 09h */
7146 NULL, /* 0Ah */
7147 NULL, /* 0Bh */
7148 NULL, /* 0Ch */
7149 NULL, /* 0Dh */
7150 NULL, /* 0Eh */
7151 NULL, /* 0Fh */
7152 "Activation failed: Already Active Volume", /* 10h */
7153 "Activation failed: Unsupported Volume Type", /* 11h */
7154 "Activation failed: Too Many Active Volumes", /* 12h */
7155 "Activation failed: Volume ID in Use", /* 13h */
7156 "Activation failed: Reported Failure", /* 14h */
7157 "Activation failed: Importing a Volume", /* 15h */
7158 NULL, /* 16h */
7159 NULL, /* 17h */
7160 NULL, /* 18h */
7161 NULL, /* 19h */
7162 NULL, /* 1Ah */
7163 NULL, /* 1Bh */
7164 NULL, /* 1Ch */
7165 NULL, /* 1Dh */
7166 NULL, /* 1Eh */
7167 NULL, /* 1Fh */
7168 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7169 "Phys Disk failed: Data Passed too Large", /* 21h */
7170 "Phys Disk failed: DMA Error", /* 22h */
7171 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7172 "Phys Disk failed: Creating Phys Disk Config "
7173 "Page", /* 24h */
7174 NULL, /* 25h */
7175 NULL, /* 26h */
7176 NULL, /* 27h */
7177 NULL, /* 28h */
7178 NULL, /* 29h */
7179 NULL, /* 2Ah */
7180 NULL, /* 2Bh */
7181 NULL, /* 2Ch */
7182 NULL, /* 2Dh */
7183 NULL, /* 2Eh */
7184 NULL, /* 2Fh */
7185 "Compatibility Error: IR Disabled", /* 30h */
7186 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7187 "Compatibility Error: Device not Direct Access "
7188 "Device ", /* 32h */
7189 "Compatibility Error: Removable Device Found", /* 33h */
7190 "Compatibility Error: Device SCSI Version not "
7191 "2 or Higher", /* 34h */
7192 "Compatibility Error: SATA Device, 48 BIT LBA "
7193 "not Supported", /* 35h */
7194 "Compatibility Error: Device doesn't have "
7195 "512 Byte Block Sizes", /* 36h */
7196 "Compatibility Error: Volume Type Check Failed", /* 37h */
7197 "Compatibility Error: Volume Type is "
7198 "Unsupported by FW", /* 38h */
7199 "Compatibility Error: Disk Drive too Small for "
7200 "use in Volume", /* 39h */
7201 "Compatibility Error: Phys Disk for Create "
7202 "Volume not Found", /* 3Ah */
7203 "Compatibility Error: Too Many or too Few "
7204 "Disks for Volume Type", /* 3Bh */
7205 "Compatibility Error: Disk stripe Sizes "
7206 "Must be 64KB", /* 3Ch */
7207 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7208 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007209
7210/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007211/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007212 * mpt_sas_log_info - Log information returned from SAS IOC.
7213 * @ioc: Pointer to MPT_ADAPTER structure
7214 * @log_info: U32 LogInfo reply word from the IOC
7215 *
7216 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007217 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007218static void
7219mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7220{
7221union loginfo_type {
7222 u32 loginfo;
7223 struct {
7224 u32 subcode:16;
7225 u32 code:8;
7226 u32 originator:4;
7227 u32 bus_type:4;
7228 }dw;
7229};
7230 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007231 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007232 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007233 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007234
7235 sas_loginfo.loginfo = log_info;
7236 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007237 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007238 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007239
7240 originator_desc = originator_str[sas_loginfo.dw.originator];
7241
7242 switch (sas_loginfo.dw.originator) {
7243
7244 case 0: /* IOP */
7245 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007246 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007247 code_desc = iop_code_str[sas_loginfo.dw.code];
7248 break;
7249 case 1: /* PL */
7250 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007251 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007252 code_desc = pl_code_str[sas_loginfo.dw.code];
7253 break;
7254 case 2: /* IR */
7255 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007256 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007257 break;
7258 code_desc = ir_code_str[sas_loginfo.dw.code];
7259 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007260 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007261 break;
7262 if (sas_loginfo.dw.code == 0)
7263 sub_code_desc =
7264 raid_sub_code_str[sas_loginfo.dw.subcode];
7265 break;
7266 default:
7267 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007268 }
7269
Eric Moorec6c727a2007-01-29 09:44:54 -07007270 if (sub_code_desc != NULL)
7271 printk(MYIOC_s_INFO_FMT
7272 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7273 " SubCode={%s}\n",
7274 ioc->name, log_info, originator_desc, code_desc,
7275 sub_code_desc);
7276 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007277 printk(MYIOC_s_INFO_FMT
7278 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7279 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007280 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007281 sas_loginfo.dw.subcode);
7282 else
7283 printk(MYIOC_s_INFO_FMT
7284 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7285 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007286 ioc->name, log_info, originator_desc,
7287 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007288}
7289
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007291/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007292 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7293 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007294 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007295 * @mf: Pointer to MPT request frame
7296 *
7297 * Refer to lsi/mpi.h.
7298 **/
7299static void
7300mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7301{
7302 Config_t *pReq = (Config_t *)mf;
7303 char extend_desc[EVENT_DESCR_STR_SZ];
7304 char *desc = NULL;
7305 u32 form;
7306 u8 page_type;
7307
7308 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7309 page_type = pReq->ExtPageType;
7310 else
7311 page_type = pReq->Header.PageType;
7312
7313 /*
7314 * ignore invalid page messages for GET_NEXT_HANDLE
7315 */
7316 form = le32_to_cpu(pReq->PageAddress);
7317 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7318 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7319 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7320 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7321 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7322 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7323 return;
7324 }
7325 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7326 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7327 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7328 return;
7329 }
7330
7331 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7332 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7333 page_type, pReq->Header.PageNumber, pReq->Action, form);
7334
7335 switch (ioc_status) {
7336
7337 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7338 desc = "Config Page Invalid Action";
7339 break;
7340
7341 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7342 desc = "Config Page Invalid Type";
7343 break;
7344
7345 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7346 desc = "Config Page Invalid Page";
7347 break;
7348
7349 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7350 desc = "Config Page Invalid Data";
7351 break;
7352
7353 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7354 desc = "Config Page No Defaults";
7355 break;
7356
7357 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7358 desc = "Config Page Can't Commit";
7359 break;
7360 }
7361
7362 if (!desc)
7363 return;
7364
Eric Moore29dd3602007-09-14 18:46:51 -06007365 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7366 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007367}
7368
7369/**
7370 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007371 * @ioc: Pointer to MPT_ADAPTER structure
7372 * @ioc_status: U32 IOCStatus word from IOC
7373 * @mf: Pointer to MPT request frame
7374 *
7375 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007376 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007378mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007379{
7380 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007381 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007382
7383 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007384
7385/****************************************************************************/
7386/* Common IOCStatus values for all replies */
7387/****************************************************************************/
7388
Linus Torvalds1da177e2005-04-16 15:20:36 -07007389 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7390 desc = "Invalid Function";
7391 break;
7392
7393 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7394 desc = "Busy";
7395 break;
7396
7397 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7398 desc = "Invalid SGL";
7399 break;
7400
7401 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7402 desc = "Internal Error";
7403 break;
7404
7405 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7406 desc = "Reserved";
7407 break;
7408
7409 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7410 desc = "Insufficient Resources";
7411 break;
7412
7413 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7414 desc = "Invalid Field";
7415 break;
7416
7417 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7418 desc = "Invalid State";
7419 break;
7420
Eric Moorec6c727a2007-01-29 09:44:54 -07007421/****************************************************************************/
7422/* Config IOCStatus values */
7423/****************************************************************************/
7424
Linus Torvalds1da177e2005-04-16 15:20:36 -07007425 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7426 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7427 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7428 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7429 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7430 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007431 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007432 break;
7433
Eric Moorec6c727a2007-01-29 09:44:54 -07007434/****************************************************************************/
7435/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7436/* */
7437/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7438/* */
7439/****************************************************************************/
7440
Linus Torvalds1da177e2005-04-16 15:20:36 -07007441 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007442 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007443 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7444 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7445 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7446 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007447 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007448 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007449 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007450 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007451 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007452 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007453 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007454 break;
7455
Eric Moorec6c727a2007-01-29 09:44:54 -07007456/****************************************************************************/
7457/* SCSI Target values */
7458/****************************************************************************/
7459
7460 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7461 desc = "Target: Priority IO";
7462 break;
7463
7464 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7465 desc = "Target: Invalid Port";
7466 break;
7467
7468 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7469 desc = "Target Invalid IO Index:";
7470 break;
7471
7472 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7473 desc = "Target: Aborted";
7474 break;
7475
7476 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7477 desc = "Target: No Conn Retryable";
7478 break;
7479
7480 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7481 desc = "Target: No Connection";
7482 break;
7483
7484 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7485 desc = "Target: Transfer Count Mismatch";
7486 break;
7487
7488 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7489 desc = "Target: STS Data not Sent";
7490 break;
7491
7492 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7493 desc = "Target: Data Offset Error";
7494 break;
7495
7496 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7497 desc = "Target: Too Much Write Data";
7498 break;
7499
7500 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7501 desc = "Target: IU Too Short";
7502 break;
7503
7504 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7505 desc = "Target: ACK NAK Timeout";
7506 break;
7507
7508 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7509 desc = "Target: Nak Received";
7510 break;
7511
7512/****************************************************************************/
7513/* Fibre Channel Direct Access values */
7514/****************************************************************************/
7515
7516 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7517 desc = "FC: Aborted";
7518 break;
7519
7520 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7521 desc = "FC: RX ID Invalid";
7522 break;
7523
7524 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7525 desc = "FC: DID Invalid";
7526 break;
7527
7528 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7529 desc = "FC: Node Logged Out";
7530 break;
7531
7532 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7533 desc = "FC: Exchange Canceled";
7534 break;
7535
7536/****************************************************************************/
7537/* LAN values */
7538/****************************************************************************/
7539
7540 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7541 desc = "LAN: Device not Found";
7542 break;
7543
7544 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7545 desc = "LAN: Device Failure";
7546 break;
7547
7548 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7549 desc = "LAN: Transmit Error";
7550 break;
7551
7552 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7553 desc = "LAN: Transmit Aborted";
7554 break;
7555
7556 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7557 desc = "LAN: Receive Error";
7558 break;
7559
7560 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7561 desc = "LAN: Receive Aborted";
7562 break;
7563
7564 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7565 desc = "LAN: Partial Packet";
7566 break;
7567
7568 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7569 desc = "LAN: Canceled";
7570 break;
7571
7572/****************************************************************************/
7573/* Serial Attached SCSI values */
7574/****************************************************************************/
7575
7576 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7577 desc = "SAS: SMP Request Failed";
7578 break;
7579
7580 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7581 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007582 break;
7583
7584 default:
7585 desc = "Others";
7586 break;
7587 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007588
7589 if (!desc)
7590 return;
7591
Eric Moore29dd3602007-09-14 18:46:51 -06007592 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7593 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007594}
7595
7596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007597EXPORT_SYMBOL(mpt_attach);
7598EXPORT_SYMBOL(mpt_detach);
7599#ifdef CONFIG_PM
7600EXPORT_SYMBOL(mpt_resume);
7601EXPORT_SYMBOL(mpt_suspend);
7602#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007604EXPORT_SYMBOL(mpt_register);
7605EXPORT_SYMBOL(mpt_deregister);
7606EXPORT_SYMBOL(mpt_event_register);
7607EXPORT_SYMBOL(mpt_event_deregister);
7608EXPORT_SYMBOL(mpt_reset_register);
7609EXPORT_SYMBOL(mpt_reset_deregister);
7610EXPORT_SYMBOL(mpt_device_driver_register);
7611EXPORT_SYMBOL(mpt_device_driver_deregister);
7612EXPORT_SYMBOL(mpt_get_msg_frame);
7613EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307614EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007615EXPORT_SYMBOL(mpt_free_msg_frame);
7616EXPORT_SYMBOL(mpt_add_sge);
7617EXPORT_SYMBOL(mpt_send_handshake_request);
7618EXPORT_SYMBOL(mpt_verify_adapter);
7619EXPORT_SYMBOL(mpt_GetIocState);
7620EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007621EXPORT_SYMBOL(mpt_HardResetHandler);
7622EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007624EXPORT_SYMBOL(mpt_alloc_fw_memory);
7625EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007626EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007627EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007628
Linus Torvalds1da177e2005-04-16 15:20:36 -07007629/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007630/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007631 * fusion_init - Fusion MPT base driver initialization routine.
7632 *
7633 * Returns 0 for success, non-zero for failure.
7634 */
7635static int __init
7636fusion_init(void)
7637{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307638 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007639
7640 show_mptmod_ver(my_NAME, my_VERSION);
7641 printk(KERN_INFO COPYRIGHT "\n");
7642
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307643 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7644 MptCallbacks[cb_idx] = NULL;
7645 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7646 MptEvHandlers[cb_idx] = NULL;
7647 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007648 }
7649
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007650 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651 * EventNotification handling.
7652 */
7653 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7654
7655 /* Register for hard reset handling callbacks.
7656 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307657 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007658
7659#ifdef CONFIG_PROC_FS
7660 (void) procmpt_create();
7661#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007662 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007663}
7664
7665/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007666/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667 * fusion_exit - Perform driver unload cleanup.
7668 *
7669 * This routine frees all resources associated with each MPT adapter
7670 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7671 */
7672static void __exit
7673fusion_exit(void)
7674{
7675
Linus Torvalds1da177e2005-04-16 15:20:36 -07007676 mpt_reset_deregister(mpt_base_index);
7677
7678#ifdef CONFIG_PROC_FS
7679 procmpt_destroy();
7680#endif
7681}
7682
Linus Torvalds1da177e2005-04-16 15:20:36 -07007683module_init(fusion_init);
7684module_exit(fusion_exit);