blob: 787a12648dbc236d1bcf1d36625be51c764cdadc [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;
94module_param(mpt_msi_enable_sas, int, 1);
95MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
96 controllers (default=1)");
97
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
Prakash, Sathya436ace72007-07-24 15:42:08 +0530110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#ifdef MFCNT
112static int mfcounter = 0;
113#define PRINT_MF_COUNT 20000
114#endif
115
116/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
117/*
118 * Public data...
119 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Adrian Bunk15424922008-04-22 00:31:51 +0300121static struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123#define WHOINIT_UNKNOWN 0xAA
124
125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
126/*
127 * Private data...
128 */
129 /* Adapter link list */
130LIST_HEAD(ioc_list);
131 /* Callback lookup table */
132static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
133 /* Protocol driver class lookup table */
134static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
135 /* Event handler lookup table */
136static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
137 /* Reset handler lookup table */
138static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
139static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
142
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530143/*
144 * Driver Callback Index's
145 */
146static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
147static u8 last_drv_idx;
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
150/*
151 * Forward protos...
152 */
David Howells7d12e782006-10-05 14:55:46 +0100153static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
155static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
156 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
157 int sleepFlag);
158static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
159static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
160static void mpt_adapter_disable(MPT_ADAPTER *ioc);
161static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
162
163static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
164static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
166static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
167static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
168static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
169static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200170static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
172static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
173static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
174static int PrimeIocFifos(MPT_ADAPTER *ioc);
175static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
176static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
177static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
178static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200180int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
182static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
183static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
184static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
185static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530186static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
188static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200189static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
190static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
192#ifdef CONFIG_PROC_FS
193static int procmpt_summary_read(char *buf, char **start, off_t offset,
194 int request, int *eof, void *data);
195static int procmpt_version_read(char *buf, char **start, off_t offset,
196 int request, int *eof, void *data);
197static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
198 int request, int *eof, void *data);
199#endif
200static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
201
202//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
203static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700204static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700206static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600207static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700208static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700209static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
211/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212static int __init fusion_init (void);
213static void __exit fusion_exit (void);
214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215#define CHIPREG_READ32(addr) readl_relaxed(addr)
216#define CHIPREG_READ32_dmasync(addr) readl(addr)
217#define CHIPREG_WRITE32(addr,val) writel(val, addr)
218#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
219#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
220
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600221static void
222pci_disable_io_access(struct pci_dev *pdev)
223{
224 u16 command_reg;
225
226 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
227 command_reg &= ~1;
228 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
229}
230
231static void
232pci_enable_io_access(struct pci_dev *pdev)
233{
234 u16 command_reg;
235
236 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
237 command_reg |= 1;
238 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
239}
240
James Bottomleydb47c2d2007-07-28 13:40:21 -0400241static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
242{
243 int ret = param_set_int(val, kp);
244 MPT_ADAPTER *ioc;
245
246 if (ret)
247 return ret;
248
249 list_for_each_entry(ioc, &ioc_list, list)
250 ioc->debug_level = mpt_debug_level;
251 return 0;
252}
253
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530254/**
255 * mpt_get_cb_idx - obtain cb_idx for registered driver
256 * @dclass: class driver enum
257 *
258 * Returns cb_idx, or zero means it wasn't found
259 **/
260static u8
261mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
262{
263 u8 cb_idx;
264
265 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
266 if (MptDriverClass[cb_idx] == dclass)
267 return cb_idx;
268 return 0;
269}
270
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530271/**
272 * mpt_fault_reset_work - work performed on workq after ioc fault
273 * @work: input argument, used to derive ioc
274 *
275**/
276static void
277mpt_fault_reset_work(struct work_struct *work)
278{
279 MPT_ADAPTER *ioc =
280 container_of(work, MPT_ADAPTER, fault_reset_work.work);
281 u32 ioc_raw_state;
282 int rc;
283 unsigned long flags;
284
285 if (ioc->diagPending || !ioc->active)
286 goto out;
287
288 ioc_raw_state = mpt_GetIocState(ioc, 0);
289 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
290 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700291 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530292 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700293 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530294 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
295 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700296 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530297 ioc_raw_state = mpt_GetIocState(ioc, 0);
298 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
299 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
300 "reset (%04xh)\n", ioc->name, ioc_raw_state &
301 MPI_DOORBELL_DATA_MASK);
302 }
303
304 out:
305 /*
306 * Take turns polling alternate controller
307 */
308 if (ioc->alt_ioc)
309 ioc = ioc->alt_ioc;
310
311 /* rearm the timer */
312 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
313 if (ioc->reset_work_q)
314 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
315 msecs_to_jiffies(MPT_POLLING_INTERVAL));
316 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
317}
318
319
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600320/*
321 * Process turbo (context) reply...
322 */
323static void
324mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
325{
326 MPT_FRAME_HDR *mf = NULL;
327 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530328 u16 req_idx = 0;
329 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600330
Prakash, Sathya436ace72007-07-24 15:42:08 +0530331 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600332 ioc->name, pa));
333
334 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
335 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
336 req_idx = pa & 0x0000FFFF;
337 cb_idx = (pa & 0x00FF0000) >> 16;
338 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
339 break;
340 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530341 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600342 /*
343 * Blind set of mf to NULL here was fatal
344 * after lan_reply says "freeme"
345 * Fix sort of combined with an optimization here;
346 * added explicit check for case where lan_reply
347 * was just returning 1 and doing nothing else.
348 * For this case skip the callback, but set up
349 * proper mf value first here:-)
350 */
351 if ((pa & 0x58000000) == 0x58000000) {
352 req_idx = pa & 0x0000FFFF;
353 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
354 mpt_free_msg_frame(ioc, mf);
355 mb();
356 return;
357 break;
358 }
359 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
360 break;
361 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530362 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600363 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
364 break;
365 default:
366 cb_idx = 0;
367 BUG();
368 }
369
370 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530371 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600372 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600373 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700374 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600375 goto out;
376 }
377
378 if (MptCallbacks[cb_idx](ioc, mf, mr))
379 mpt_free_msg_frame(ioc, mf);
380 out:
381 mb();
382}
383
384static void
385mpt_reply(MPT_ADAPTER *ioc, u32 pa)
386{
387 MPT_FRAME_HDR *mf;
388 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530389 u16 req_idx;
390 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600391 int freeme;
392
393 u32 reply_dma_low;
394 u16 ioc_stat;
395
396 /* non-TURBO reply! Hmmm, something may be up...
397 * Newest turbo reply mechanism; get address
398 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
399 */
400
401 /* Map DMA address of reply header to cpu address.
402 * pa is 32 bits - but the dma address may be 32 or 64 bits
403 * get offset based only only the low addresses
404 */
405
406 reply_dma_low = (pa <<= 1);
407 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
408 (reply_dma_low - ioc->reply_frames_low_dma));
409
410 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
411 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
412 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
413
Prakash, Sathya436ace72007-07-24 15:42:08 +0530414 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 -0600415 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600416 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600417
418 /* Check/log IOC log info
419 */
420 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
421 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
422 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
423 if (ioc->bus_type == FC)
424 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700425 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700426 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600427 else if (ioc->bus_type == SAS)
428 mpt_sas_log_info(ioc, log_info);
429 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600430
Eric Moorec6c727a2007-01-29 09:44:54 -0700431 if (ioc_stat & MPI_IOCSTATUS_MASK)
432 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600433
434 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530435 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600436 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600437 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700438 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600439 freeme = 0;
440 goto out;
441 }
442
443 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
444
445 out:
446 /* Flush (non-TURBO) reply with a WRITE! */
447 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
448
449 if (freeme)
450 mpt_free_msg_frame(ioc, mf);
451 mb();
452}
453
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800455/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
457 * @irq: irq number (not used)
458 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 *
460 * This routine is registered via the request_irq() kernel API call,
461 * and handles all interrupts generated from a specific MPT adapter
462 * (also referred to as a IO Controller or IOC).
463 * This routine must clear the interrupt from the adapter and does
464 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200465 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 *
467 * This routine handles register-level access of the adapter but
468 * dispatches (calls) a protocol-specific callback routine to handle
469 * the protocol-specific details of the MPT request completion.
470 */
471static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100472mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600474 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600475 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
476
477 if (pa == 0xFFFFFFFF)
478 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480 /*
481 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600483 do {
484 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600485 mpt_reply(ioc, pa);
486 else
487 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600488 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
489 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 return IRQ_HANDLED;
492}
493
494/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800495/**
496 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 * @ioc: Pointer to MPT_ADAPTER structure
498 * @mf: Pointer to original MPT request frame
499 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
500 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800501 * MPT base driver's callback routine; all base driver
502 * "internal" request/reply processing is routed here.
503 * Currently used for EventNotification and EventAck handling.
504 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200505 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 * should be freed, or 0 if it shouldn't.
507 */
508static int
509mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
510{
511 int freereq = 1;
512 u8 func;
513
Prakash, Sathya436ace72007-07-24 15:42:08 +0530514 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
515#ifdef CONFIG_FUSION_LOGGING
516 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
517 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600518 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
519 ioc->name, mf));
520 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200522#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530525 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 ioc->name, func));
527
528 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
529 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
530 int evHandlers = 0;
531 int results;
532
533 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
534 if (results != evHandlers) {
535 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530536 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 ioc->name, evHandlers, results));
538 }
539
540 /*
541 * Hmmm... It seems that EventNotificationReply is an exception
542 * to the rule of one reply per request.
543 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200544 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200546 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530547 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200548 ioc->name, pEvReply));
549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551#ifdef CONFIG_PROC_FS
552// LogEvent(ioc, pEvReply);
553#endif
554
555 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530556 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700558 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 CONFIGPARMS *pCfg;
560 unsigned long flags;
561
Prakash, Sathya436ace72007-07-24 15:42:08 +0530562 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 ioc->name, mf, reply));
564
565 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
566
567 if (pCfg) {
568 /* disable timer and remove from linked list */
569 del_timer(&pCfg->timer);
570
571 spin_lock_irqsave(&ioc->FreeQlock, flags);
572 list_del(&pCfg->linkage);
573 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
574
575 /*
576 * If IOC Status is SUCCESS, save the header
577 * and set the status code to GOOD.
578 */
579 pCfg->status = MPT_CONFIG_ERROR;
580 if (reply) {
581 ConfigReply_t *pReply = (ConfigReply_t *)reply;
582 u16 status;
583
584 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600585 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
586 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 pCfg->status = status;
589 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200590 if ((pReply->Header.PageType &
591 MPI_CONFIG_PAGETYPE_MASK) ==
592 MPI_CONFIG_PAGETYPE_EXTENDED) {
593 pCfg->cfghdr.ehdr->ExtPageLength =
594 le16_to_cpu(pReply->ExtPageLength);
595 pCfg->cfghdr.ehdr->ExtPageType =
596 pReply->ExtPageType;
597 }
598 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
599
600 /* If this is a regular header, save PageLength. */
601 /* LMP Do this better so not using a reserved field! */
602 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
603 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
604 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
606 }
607
608 /*
609 * Wake up the original calling thread
610 */
611 pCfg->wait_done = 1;
612 wake_up(&mpt_waitq);
613 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200614 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
615 /* we should be always getting a reply frame */
616 memcpy(ioc->persist_reply_frame, reply,
617 min(MPT_DEFAULT_FRAME_SIZE,
618 4*reply->u.reply.MsgLength));
619 del_timer(&ioc->persist_timer);
620 ioc->persist_wait_done = 1;
621 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 } else {
623 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
624 ioc->name, func);
625 }
626
627 /*
628 * Conditionally tell caller to free the original
629 * EventNotification/EventAck/unexpected request frame!
630 */
631 return freereq;
632}
633
634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
635/**
636 * mpt_register - Register protocol-specific main callback handler.
637 * @cbfunc: callback function pointer
638 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
639 *
640 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800641 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 * protocol-specific driver must do this before it will be able to
643 * use any IOC resources, such as obtaining request frames.
644 *
645 * NOTES: The SCSI protocol driver currently calls this routine thrice
646 * in order to register separate callbacks; one for "normal" SCSI IO;
647 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
648 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530649 * Returns u8 valued "handle" in the range (and S.O.D. order)
650 * {N,...,7,6,5,...,1} if successful.
651 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
652 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530654u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
656{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530657 u8 cb_idx;
658 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660 /*
661 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
662 * (slot/handle 0 is reserved!)
663 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530664 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
665 if (MptCallbacks[cb_idx] == NULL) {
666 MptCallbacks[cb_idx] = cbfunc;
667 MptDriverClass[cb_idx] = dclass;
668 MptEvHandlers[cb_idx] = NULL;
669 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 break;
671 }
672 }
673
674 return last_drv_idx;
675}
676
677/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
678/**
679 * mpt_deregister - Deregister a protocol drivers resources.
680 * @cb_idx: previously registered callback handle
681 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800682 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 * module is unloaded.
684 */
685void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530686mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600688 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 MptCallbacks[cb_idx] = NULL;
690 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
691 MptEvHandlers[cb_idx] = NULL;
692
693 last_drv_idx++;
694 }
695}
696
697/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
698/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800699 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 * @cb_idx: previously registered (via mpt_register) callback handle
701 * @ev_cbfunc: callback function
702 *
703 * This routine can be called by one or more protocol-specific drivers
704 * if/when they choose to be notified of MPT events.
705 *
706 * Returns 0 for success.
707 */
708int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530709mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600711 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 return -1;
713
714 MptEvHandlers[cb_idx] = ev_cbfunc;
715 return 0;
716}
717
718/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
719/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800720 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 * @cb_idx: previously registered callback handle
722 *
723 * Each protocol-specific driver should call this routine
724 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800725 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 */
727void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530728mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600730 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 return;
732
733 MptEvHandlers[cb_idx] = NULL;
734}
735
736/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
737/**
738 * mpt_reset_register - Register protocol-specific IOC reset handler.
739 * @cb_idx: previously registered (via mpt_register) callback handle
740 * @reset_func: reset function
741 *
742 * This routine can be called by one or more protocol-specific drivers
743 * if/when they choose to be notified of IOC resets.
744 *
745 * Returns 0 for success.
746 */
747int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530748mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530750 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 return -1;
752
753 MptResetHandlers[cb_idx] = reset_func;
754 return 0;
755}
756
757/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
758/**
759 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
760 * @cb_idx: previously registered callback handle
761 *
762 * Each protocol-specific driver should call this routine
763 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800764 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 */
766void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530767mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530769 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return;
771
772 MptResetHandlers[cb_idx] = NULL;
773}
774
775/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
776/**
777 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800778 * @dd_cbfunc: driver callbacks struct
779 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 */
781int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530782mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783{
784 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600785 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Eric Moore8d6d83e2007-09-14 18:47:40 -0600787 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400788 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
791
792 /* call per pci device probe entry point */
793 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600794 id = ioc->pcidev->driver ?
795 ioc->pcidev->driver->id_table : NULL;
796 if (dd_cbfunc->probe)
797 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 }
799
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400800 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801}
802
803/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
804/**
805 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800806 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 */
808void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530809mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810{
811 struct mpt_pci_driver *dd_cbfunc;
812 MPT_ADAPTER *ioc;
813
Eric Moore8d6d83e2007-09-14 18:47:40 -0600814 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 return;
816
817 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
818
819 list_for_each_entry(ioc, &ioc_list, list) {
820 if (dd_cbfunc->remove)
821 dd_cbfunc->remove(ioc->pcidev);
822 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 MptDeviceDriverHandlers[cb_idx] = NULL;
825}
826
827
828/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
829/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800830 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530831 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 * @ioc: Pointer to MPT adapter structure
833 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800834 * Obtain an MPT request frame from the pool (of 1024) that are
835 * allocated per MPT adapter.
836 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 * Returns pointer to a MPT request frame or %NULL if none are available
838 * or IOC is not active.
839 */
840MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530841mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 MPT_FRAME_HDR *mf;
844 unsigned long flags;
845 u16 req_idx; /* Request index */
846
847 /* validate handle and ioc identifier */
848
849#ifdef MFCNT
850 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600851 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
852 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853#endif
854
855 /* If interrupts are not attached, do not return a request frame */
856 if (!ioc->active)
857 return NULL;
858
859 spin_lock_irqsave(&ioc->FreeQlock, flags);
860 if (!list_empty(&ioc->FreeQ)) {
861 int req_offset;
862
863 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
864 u.frame.linkage.list);
865 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200866 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530867 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
869 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500870 req_idx = req_offset / ioc->req_sz;
871 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600873 /* Default, will be changed if necessary in SG generation */
874 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875#ifdef MFCNT
876 ioc->mfcnt++;
877#endif
878 }
879 else
880 mf = NULL;
881 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
882
883#ifdef MFCNT
884 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600885 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
886 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
887 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 mfcounter++;
889 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600890 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
891 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892#endif
893
Eric Moore29dd3602007-09-14 18:46:51 -0600894 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
895 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 return mf;
897}
898
899/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
900/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800901 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530902 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 * @ioc: Pointer to MPT adapter structure
904 * @mf: Pointer to MPT request frame
905 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800906 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 * specific MPT adapter.
908 */
909void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530910mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 u32 mf_dma_addr;
913 int req_offset;
914 u16 req_idx; /* Request index */
915
916 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530917 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
919 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500920 req_idx = req_offset / ioc->req_sz;
921 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
923
Prakash, Sathya436ace72007-07-24 15:42:08 +0530924 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200926 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600927 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
928 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
929 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
931}
932
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530933/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800934 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530935 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530936 * @ioc: Pointer to MPT adapter structure
937 * @mf: Pointer to MPT request frame
938 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800939 * Send a protocol-specific MPT request frame to an IOC using
940 * hi-priority request queue.
941 *
942 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530943 * specific MPT adapter.
944 **/
945void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530946mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530947{
948 u32 mf_dma_addr;
949 int req_offset;
950 u16 req_idx; /* Request index */
951
952 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530953 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530954 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
955 req_idx = req_offset / ioc->req_sz;
956 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
957 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
958
959 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
960
961 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
962 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
963 ioc->name, mf_dma_addr, req_idx));
964 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
965}
966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
968/**
969 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 * @ioc: Pointer to MPT adapter structure
971 * @mf: Pointer to MPT request frame
972 *
973 * This routine places a MPT request frame back on the MPT adapter's
974 * FreeQ.
975 */
976void
977mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
978{
979 unsigned long flags;
980
981 /* Put Request back on FreeQ! */
982 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200983 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
985#ifdef MFCNT
986 ioc->mfcnt--;
987#endif
988 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
989}
990
991/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
992/**
993 * mpt_add_sge - Place a simple SGE at address pAddr.
994 * @pAddr: virtual address for SGE
995 * @flagslength: SGE flags and data transfer length
996 * @dma_addr: Physical address
997 *
998 * This routine places a MPT request frame back on the MPT adapter's
999 * FreeQ.
1000 */
1001void
1002mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
1003{
1004 if (sizeof(dma_addr_t) == sizeof(u64)) {
1005 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1006 u32 tmp = dma_addr & 0xFFFFFFFF;
1007
1008 pSge->FlagsLength = cpu_to_le32(flagslength);
1009 pSge->Address.Low = cpu_to_le32(tmp);
1010 tmp = (u32) ((u64)dma_addr >> 32);
1011 pSge->Address.High = cpu_to_le32(tmp);
1012
1013 } else {
1014 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1015 pSge->FlagsLength = cpu_to_le32(flagslength);
1016 pSge->Address = cpu_to_le32(dma_addr);
1017 }
1018}
1019
1020/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1021/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001022 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301023 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 * @ioc: Pointer to MPT adapter structure
1025 * @reqBytes: Size of the request in bytes
1026 * @req: Pointer to MPT request frame
1027 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1028 *
1029 * This routine is used exclusively to send MptScsiTaskMgmt
1030 * requests since they are required to be sent via doorbell handshake.
1031 *
1032 * NOTE: It is the callers responsibility to byte-swap fields in the
1033 * request which are greater than 1 byte in size.
1034 *
1035 * Returns 0 for success, non-zero for failure.
1036 */
1037int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301038mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039{
Eric Moorecd2c6192007-01-29 09:47:47 -07001040 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 u8 *req_as_bytes;
1042 int ii;
1043
1044 /* State is known to be good upon entering
1045 * this function so issue the bus reset
1046 * request.
1047 */
1048
1049 /*
1050 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1051 * setting cb_idx/req_idx. But ONLY if this request
1052 * is in proper (pre-alloc'd) request buffer range...
1053 */
1054 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1055 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1056 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1057 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301058 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
1060
1061 /* Make sure there are no doorbells */
1062 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001063
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1065 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1066 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1067
1068 /* Wait for IOC doorbell int */
1069 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1070 return ii;
1071 }
1072
1073 /* Read doorbell and check for active bit */
1074 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1075 return -5;
1076
Eric Moore29dd3602007-09-14 18:46:51 -06001077 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001078 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1081
1082 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1083 return -2;
1084 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001085
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 /* Send request via doorbell handshake */
1087 req_as_bytes = (u8 *) req;
1088 for (ii = 0; ii < reqBytes/4; ii++) {
1089 u32 word;
1090
1091 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1092 (req_as_bytes[(ii*4) + 1] << 8) |
1093 (req_as_bytes[(ii*4) + 2] << 16) |
1094 (req_as_bytes[(ii*4) + 3] << 24));
1095 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1096 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1097 r = -3;
1098 break;
1099 }
1100 }
1101
1102 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1103 r = 0;
1104 else
1105 r = -4;
1106
1107 /* Make sure there are no doorbells */
1108 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return r;
1111}
1112
1113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1114/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001115 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001116 * @ioc: Pointer to MPT adapter structure
1117 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001118 * @sleepFlag: Specifies whether the process can sleep
1119 *
1120 * Provides mechanism for the host driver to control the IOC's
1121 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001122 *
1123 * Access Control Value - bits[15:12]
1124 * 0h Reserved
1125 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1126 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1127 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1128 *
1129 * Returns 0 for success, non-zero for failure.
1130 */
1131
1132static int
1133mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1134{
1135 int r = 0;
1136
1137 /* return if in use */
1138 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1139 & MPI_DOORBELL_ACTIVE)
1140 return -1;
1141
1142 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1143
1144 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1145 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1146 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1147 (access_control_value<<12)));
1148
1149 /* Wait for IOC to clear Doorbell Status bit */
1150 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1151 return -2;
1152 }else
1153 return 0;
1154}
1155
1156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1157/**
1158 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001159 * @ioc: Pointer to pointer to IOC adapter
1160 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001161 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001162 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001163 * Returns 0 for success, non-zero for failure.
1164 */
1165static int
1166mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1167{
1168 char *psge;
1169 int flags_length;
1170 u32 host_page_buffer_sz=0;
1171
1172 if(!ioc->HostPageBuffer) {
1173
1174 host_page_buffer_sz =
1175 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1176
1177 if(!host_page_buffer_sz)
1178 return 0; /* fw doesn't need any host buffers */
1179
1180 /* spin till we get enough memory */
1181 while(host_page_buffer_sz > 0) {
1182
1183 if((ioc->HostPageBuffer = pci_alloc_consistent(
1184 ioc->pcidev,
1185 host_page_buffer_sz,
1186 &ioc->HostPageBuffer_dma)) != NULL) {
1187
Prakash, Sathya436ace72007-07-24 15:42:08 +05301188 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001189 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001190 ioc->name, ioc->HostPageBuffer,
1191 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001192 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001193 ioc->alloc_total += host_page_buffer_sz;
1194 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1195 break;
1196 }
1197
1198 host_page_buffer_sz -= (4*1024);
1199 }
1200 }
1201
1202 if(!ioc->HostPageBuffer) {
1203 printk(MYIOC_s_ERR_FMT
1204 "Failed to alloc memory for host_page_buffer!\n",
1205 ioc->name);
1206 return -999;
1207 }
1208
1209 psge = (char *)&ioc_init->HostPageBufferSGE;
1210 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1211 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1212 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1213 MPI_SGE_FLAGS_HOST_TO_IOC |
1214 MPI_SGE_FLAGS_END_OF_BUFFER;
1215 if (sizeof(dma_addr_t) == sizeof(u64)) {
1216 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1217 }
1218 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1219 flags_length |= ioc->HostPageBuffer_sz;
1220 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1221 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1222
1223return 0;
1224}
1225
1226/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1227/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001228 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 * @iocid: IOC unique identifier (integer)
1230 * @iocpp: Pointer to pointer to IOC adapter
1231 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001232 * Given a unique IOC identifier, set pointer to the associated MPT
1233 * adapter structure.
1234 *
1235 * Returns iocid and sets iocpp if iocid is found.
1236 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 */
1238int
1239mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1240{
1241 MPT_ADAPTER *ioc;
1242
1243 list_for_each_entry(ioc,&ioc_list,list) {
1244 if (ioc->id == iocid) {
1245 *iocpp =ioc;
1246 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001249
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 *iocpp = NULL;
1251 return -1;
1252}
1253
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301254/**
1255 * mpt_get_product_name - returns product string
1256 * @vendor: pci vendor id
1257 * @device: pci device id
1258 * @revision: pci revision id
1259 * @prod_name: string returned
1260 *
1261 * Returns product string displayed when driver loads,
1262 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1263 *
1264 **/
1265static void
1266mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1267{
1268 char *product_str = NULL;
1269
1270 if (vendor == PCI_VENDOR_ID_BROCADE) {
1271 switch (device)
1272 {
1273 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1274 switch (revision)
1275 {
1276 case 0x00:
1277 product_str = "BRE040 A0";
1278 break;
1279 case 0x01:
1280 product_str = "BRE040 A1";
1281 break;
1282 default:
1283 product_str = "BRE040";
1284 break;
1285 }
1286 break;
1287 }
1288 goto out;
1289 }
1290
1291 switch (device)
1292 {
1293 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1294 product_str = "LSIFC909 B1";
1295 break;
1296 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1297 product_str = "LSIFC919 B0";
1298 break;
1299 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1300 product_str = "LSIFC929 B0";
1301 break;
1302 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1303 if (revision < 0x80)
1304 product_str = "LSIFC919X A0";
1305 else
1306 product_str = "LSIFC919XL A1";
1307 break;
1308 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1309 if (revision < 0x80)
1310 product_str = "LSIFC929X A0";
1311 else
1312 product_str = "LSIFC929XL A1";
1313 break;
1314 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1315 product_str = "LSIFC939X A1";
1316 break;
1317 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1318 product_str = "LSIFC949X A1";
1319 break;
1320 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1321 switch (revision)
1322 {
1323 case 0x00:
1324 product_str = "LSIFC949E A0";
1325 break;
1326 case 0x01:
1327 product_str = "LSIFC949E A1";
1328 break;
1329 default:
1330 product_str = "LSIFC949E";
1331 break;
1332 }
1333 break;
1334 case MPI_MANUFACTPAGE_DEVID_53C1030:
1335 switch (revision)
1336 {
1337 case 0x00:
1338 product_str = "LSI53C1030 A0";
1339 break;
1340 case 0x01:
1341 product_str = "LSI53C1030 B0";
1342 break;
1343 case 0x03:
1344 product_str = "LSI53C1030 B1";
1345 break;
1346 case 0x07:
1347 product_str = "LSI53C1030 B2";
1348 break;
1349 case 0x08:
1350 product_str = "LSI53C1030 C0";
1351 break;
1352 case 0x80:
1353 product_str = "LSI53C1030T A0";
1354 break;
1355 case 0x83:
1356 product_str = "LSI53C1030T A2";
1357 break;
1358 case 0x87:
1359 product_str = "LSI53C1030T A3";
1360 break;
1361 case 0xc1:
1362 product_str = "LSI53C1020A A1";
1363 break;
1364 default:
1365 product_str = "LSI53C1030";
1366 break;
1367 }
1368 break;
1369 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1370 switch (revision)
1371 {
1372 case 0x03:
1373 product_str = "LSI53C1035 A2";
1374 break;
1375 case 0x04:
1376 product_str = "LSI53C1035 B0";
1377 break;
1378 default:
1379 product_str = "LSI53C1035";
1380 break;
1381 }
1382 break;
1383 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1384 switch (revision)
1385 {
1386 case 0x00:
1387 product_str = "LSISAS1064 A1";
1388 break;
1389 case 0x01:
1390 product_str = "LSISAS1064 A2";
1391 break;
1392 case 0x02:
1393 product_str = "LSISAS1064 A3";
1394 break;
1395 case 0x03:
1396 product_str = "LSISAS1064 A4";
1397 break;
1398 default:
1399 product_str = "LSISAS1064";
1400 break;
1401 }
1402 break;
1403 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1404 switch (revision)
1405 {
1406 case 0x00:
1407 product_str = "LSISAS1064E A0";
1408 break;
1409 case 0x01:
1410 product_str = "LSISAS1064E B0";
1411 break;
1412 case 0x02:
1413 product_str = "LSISAS1064E B1";
1414 break;
1415 case 0x04:
1416 product_str = "LSISAS1064E B2";
1417 break;
1418 case 0x08:
1419 product_str = "LSISAS1064E B3";
1420 break;
1421 default:
1422 product_str = "LSISAS1064E";
1423 break;
1424 }
1425 break;
1426 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1427 switch (revision)
1428 {
1429 case 0x00:
1430 product_str = "LSISAS1068 A0";
1431 break;
1432 case 0x01:
1433 product_str = "LSISAS1068 B0";
1434 break;
1435 case 0x02:
1436 product_str = "LSISAS1068 B1";
1437 break;
1438 default:
1439 product_str = "LSISAS1068";
1440 break;
1441 }
1442 break;
1443 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1444 switch (revision)
1445 {
1446 case 0x00:
1447 product_str = "LSISAS1068E A0";
1448 break;
1449 case 0x01:
1450 product_str = "LSISAS1068E B0";
1451 break;
1452 case 0x02:
1453 product_str = "LSISAS1068E B1";
1454 break;
1455 case 0x04:
1456 product_str = "LSISAS1068E B2";
1457 break;
1458 case 0x08:
1459 product_str = "LSISAS1068E B3";
1460 break;
1461 default:
1462 product_str = "LSISAS1068E";
1463 break;
1464 }
1465 break;
1466 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1467 switch (revision)
1468 {
1469 case 0x00:
1470 product_str = "LSISAS1078 A0";
1471 break;
1472 case 0x01:
1473 product_str = "LSISAS1078 B0";
1474 break;
1475 case 0x02:
1476 product_str = "LSISAS1078 C0";
1477 break;
1478 case 0x03:
1479 product_str = "LSISAS1078 C1";
1480 break;
1481 case 0x04:
1482 product_str = "LSISAS1078 C2";
1483 break;
1484 default:
1485 product_str = "LSISAS1078";
1486 break;
1487 }
1488 break;
1489 }
1490
1491 out:
1492 if (product_str)
1493 sprintf(prod_name, "%s", product_str);
1494}
1495
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301496/**
1497 * mpt_mapresources - map in memory mapped io
1498 * @ioc: Pointer to pointer to IOC adapter
1499 *
1500 **/
1501static int
1502mpt_mapresources(MPT_ADAPTER *ioc)
1503{
1504 u8 __iomem *mem;
1505 int ii;
1506 unsigned long mem_phys;
1507 unsigned long port;
1508 u32 msize;
1509 u32 psize;
1510 u8 revision;
1511 int r = -ENODEV;
1512 struct pci_dev *pdev;
1513
1514 pdev = ioc->pcidev;
1515 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1516 if (pci_enable_device_mem(pdev)) {
1517 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1518 "failed\n", ioc->name);
1519 return r;
1520 }
1521 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1522 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1523 "MEM failed\n", ioc->name);
1524 return r;
1525 }
1526
1527 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1528
1529 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
1530 && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
1531 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1532 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1533 ioc->name));
1534 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
1535 && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
1536 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1537 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1538 ioc->name));
1539 } else {
1540 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1541 ioc->name, pci_name(pdev));
1542 pci_release_selected_regions(pdev, ioc->bars);
1543 return r;
1544 }
1545
1546 mem_phys = msize = 0;
1547 port = psize = 0;
1548 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1549 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1550 if (psize)
1551 continue;
1552 /* Get I/O space! */
1553 port = pci_resource_start(pdev, ii);
1554 psize = pci_resource_len(pdev, ii);
1555 } else {
1556 if (msize)
1557 continue;
1558 /* Get memmap */
1559 mem_phys = pci_resource_start(pdev, ii);
1560 msize = pci_resource_len(pdev, ii);
1561 }
1562 }
1563 ioc->mem_size = msize;
1564
1565 mem = NULL;
1566 /* Get logical ptr for PciMem0 space */
1567 /*mem = ioremap(mem_phys, msize);*/
1568 mem = ioremap(mem_phys, msize);
1569 if (mem == NULL) {
1570 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1571 " memory!\n", ioc->name);
1572 return -EINVAL;
1573 }
1574 ioc->memmap = mem;
1575 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1576 ioc->name, mem, mem_phys));
1577
1578 ioc->mem_phys = mem_phys;
1579 ioc->chip = (SYSIF_REGS __iomem *)mem;
1580
1581 /* Save Port IO values in case we need to do downloadboot */
1582 ioc->pio_mem_phys = port;
1583 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1584
1585 return 0;
1586}
1587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001589/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001590 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001592 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 *
1594 * This routine performs all the steps necessary to bring the IOC of
1595 * a MPT adapter to a OPERATIONAL state. This includes registering
1596 * memory regions, registering the interrupt, and allocating request
1597 * and reply memory pools.
1598 *
1599 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1600 * MPT adapter.
1601 *
1602 * Returns 0 for success, non-zero for failure.
1603 *
1604 * TODO: Add support for polled controllers
1605 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001606int
1607mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608{
1609 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301610 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 u8 revision;
1613 u8 pcixcmd;
1614 static int mpt_ids = 0;
1615#ifdef CONFIG_PROC_FS
1616 struct proc_dir_entry *dent, *ent;
1617#endif
1618
Jesper Juhl56876192007-08-10 14:50:51 -07001619 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1620 if (ioc == NULL) {
1621 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1622 return -ENOMEM;
1623 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301624
Eric Moore29dd3602007-09-14 18:46:51 -06001625 ioc->id = mpt_ids++;
1626 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001627
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301628 /*
1629 * set initial debug level
1630 * (refer to mptdebug.h)
1631 *
1632 */
1633 ioc->debug_level = mpt_debug_level;
1634 if (mpt_debug_level)
1635 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301636
Eric Moore29dd3602007-09-14 18:46:51 -06001637 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001638
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301639 ioc->pcidev = pdev;
1640 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001641 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 return r;
1643 }
1644
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 ioc->alloc_total = sizeof(MPT_ADAPTER);
1646 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1647 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 ioc->pcidev = pdev;
1650 ioc->diagPending = 0;
1651 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001652 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 /* Initialize the event logging.
1655 */
1656 ioc->eventTypes = 0; /* None */
1657 ioc->eventContext = 0;
1658 ioc->eventLogSize = 0;
1659 ioc->events = NULL;
1660
1661#ifdef MFCNT
1662 ioc->mfcnt = 0;
1663#endif
1664
1665 ioc->cached_fw = NULL;
1666
1667 /* Initilize SCSI Config Data structure
1668 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001669 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 /* Initialize the running configQ head.
1672 */
1673 INIT_LIST_HEAD(&ioc->configQ);
1674
Michael Reed05e8ec12006-01-13 14:31:54 -06001675 /* Initialize the fc rport list head.
1676 */
1677 INIT_LIST_HEAD(&ioc->fc_rports);
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 /* Find lookup slot. */
1680 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001681
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301682
1683 /* Initialize workqueue */
1684 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1685 spin_lock_init(&ioc->fault_reset_work_lock);
1686
Kay Sieversaab0de22008-05-02 06:02:41 +02001687 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1688 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301689 ioc->reset_work_q =
1690 create_singlethread_workqueue(ioc->reset_work_q_name);
1691 if (!ioc->reset_work_q) {
1692 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1693 ioc->name);
1694 pci_release_selected_regions(pdev, ioc->bars);
1695 kfree(ioc);
1696 return -ENOMEM;
1697 }
1698
Eric Moore29dd3602007-09-14 18:46:51 -06001699 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1700 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301702 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1703 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1704
1705 switch (pdev->device)
1706 {
1707 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1708 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1709 ioc->errata_flag_1064 = 1;
1710 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1711 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1712 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1713 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301715 break;
1716
1717 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 /* 929X Chip Fix. Set Split transactions level
1720 * for PCIX. Set MOST bits to zero.
1721 */
1722 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1723 pcixcmd &= 0x8F;
1724 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1725 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 /* 929XL Chip Fix. Set MMRBC to 0x08.
1727 */
1728 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1729 pcixcmd |= 0x08;
1730 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301733 break;
1734
1735 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 /* 919X Chip Fix. Set Split transactions level
1737 * for PCIX. Set MOST bits to zero.
1738 */
1739 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1740 pcixcmd &= 0x8F;
1741 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001742 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301743 break;
1744
1745 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 /* 1030 Chip Fix. Disable Split transactions
1747 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1748 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 if (revision < C0_1030) {
1750 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1751 pcixcmd &= 0x8F;
1752 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1753 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301754
1755 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001756 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301757 break;
1758
1759 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1760 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001761 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301762
1763 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1764 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1765 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001766 ioc->bus_type = SAS;
1767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301769
Kashyap, Desaie3829682009-01-08 14:27:16 +05301770 switch (ioc->bus_type) {
1771
1772 case SAS:
1773 ioc->msi_enable = mpt_msi_enable_sas;
1774 break;
1775
1776 case SPI:
1777 ioc->msi_enable = mpt_msi_enable_spi;
1778 break;
1779
1780 case FC:
1781 ioc->msi_enable = mpt_msi_enable_fc;
1782 break;
1783
1784 default:
1785 ioc->msi_enable = 0;
1786 break;
1787 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001788 if (ioc->errata_flag_1064)
1789 pci_disable_io_access(pdev);
1790
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 spin_lock_init(&ioc->FreeQlock);
1792
1793 /* Disable all! */
1794 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1795 ioc->active = 0;
1796 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1797
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301798 /* Set IOC ptr in the pcidev's driver data. */
1799 pci_set_drvdata(ioc->pcidev, ioc);
1800
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 /* Set lookup ptr. */
1802 list_add_tail(&ioc->list, &ioc_list);
1803
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001804 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 */
1806 mpt_detect_bound_ports(ioc, pdev);
1807
James Bottomleyc92f2222006-03-01 09:02:49 -06001808 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1809 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001810 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1811 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001812
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001814 if (ioc->alt_ioc)
1815 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301816 iounmap(ioc->memmap);
1817 if (r != -5)
1818 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301819
1820 destroy_workqueue(ioc->reset_work_q);
1821 ioc->reset_work_q = NULL;
1822
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 kfree(ioc);
1824 pci_set_drvdata(pdev, NULL);
1825 return r;
1826 }
1827
1828 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001829 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301830 if(MptDeviceDriverHandlers[cb_idx] &&
1831 MptDeviceDriverHandlers[cb_idx]->probe) {
1832 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 }
1834 }
1835
1836#ifdef CONFIG_PROC_FS
1837 /*
1838 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1839 */
1840 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1841 if (dent) {
1842 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1843 if (ent) {
1844 ent->read_proc = procmpt_iocinfo_read;
1845 ent->data = ioc;
1846 }
1847 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1848 if (ent) {
1849 ent->read_proc = procmpt_summary_read;
1850 ent->data = ioc;
1851 }
1852 }
1853#endif
1854
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301855 if (!ioc->alt_ioc)
1856 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1857 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 return 0;
1860}
1861
1862/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001863/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001864 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 */
1867
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001868void
1869mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870{
1871 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1872 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301873 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301874 unsigned long flags;
1875 struct workqueue_struct *wq;
1876
1877 /*
1878 * Stop polling ioc for fault condition
1879 */
1880 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
1881 wq = ioc->reset_work_q;
1882 ioc->reset_work_q = NULL;
1883 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
1884 cancel_delayed_work(&ioc->fault_reset_work);
1885 destroy_workqueue(wq);
1886
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
1888 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1889 remove_proc_entry(pname, NULL);
1890 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1891 remove_proc_entry(pname, NULL);
1892 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1893 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001896 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301897 if(MptDeviceDriverHandlers[cb_idx] &&
1898 MptDeviceDriverHandlers[cb_idx]->remove) {
1899 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 }
1901 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 /* Disable interrupts! */
1904 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1905
1906 ioc->active = 0;
1907 synchronize_irq(pdev->irq);
1908
1909 /* Clear any lingering interrupt */
1910 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1911
1912 CHIPREG_READ32(&ioc->chip->IntStatus);
1913
1914 mpt_adapter_dispose(ioc);
1915
1916 pci_set_drvdata(pdev, NULL);
1917}
1918
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919/**************************************************************************
1920 * Power Management
1921 */
1922#ifdef CONFIG_PM
1923/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001924/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001925 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001926 * @pdev: Pointer to pci_dev structure
1927 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001929int
1930mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931{
1932 u32 device_state;
1933 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301935 device_state = pci_choose_state(pdev, state);
1936 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
1937 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1938 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
1940 /* put ioc into READY_STATE */
1941 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1942 printk(MYIOC_s_ERR_FMT
1943 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1944 }
1945
1946 /* disable interrupts */
1947 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1948 ioc->active = 0;
1949
1950 /* Clear any lingering interrupt */
1951 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1952
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301953 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05001954 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301955 pci_disable_msi(ioc->pcidev);
1956 ioc->pci_irq = -1;
1957 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301959 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 return 0;
1962}
1963
1964/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001965/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001966 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001967 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001969int
1970mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971{
1972 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1973 u32 device_state = pdev->current_state;
1974 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301975 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001976
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301977 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
1978 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1979 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301981 pci_set_power_state(pdev, PCI_D0);
1982 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301984 ioc->pcidev = pdev;
1985 err = mpt_mapresources(ioc);
1986 if (err)
1987 return err;
1988
1989 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1990 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1991 CHIPREG_READ32(&ioc->chip->Doorbell));
1992
1993 /*
1994 * Errata workaround for SAS pci express:
1995 * Upon returning to the D0 state, the contents of the doorbell will be
1996 * stale data, and this will incorrectly signal to the host driver that
1997 * the firmware is ready to process mpt commands. The workaround is
1998 * to issue a diagnostic reset.
1999 */
2000 if (ioc->bus_type == SAS && (pdev->device ==
2001 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2002 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2003 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2004 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2005 ioc->name);
2006 goto out;
2007 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009
2010 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302011 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2012 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2013 CAN_SLEEP);
2014 if (recovery_state != 0)
2015 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2016 "error:[%x]\n", ioc->name, recovery_state);
2017 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302019 "pci-resume: success\n", ioc->name);
2020 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302022
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023}
2024#endif
2025
James Bottomley4ff42a62006-05-17 18:06:52 -05002026static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302027mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002028{
2029 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2030 ioc->bus_type != SPI) ||
2031 (MptDriverClass[index] == MPTFC_DRIVER &&
2032 ioc->bus_type != FC) ||
2033 (MptDriverClass[index] == MPTSAS_DRIVER &&
2034 ioc->bus_type != SAS))
2035 /* make sure we only call the relevant reset handler
2036 * for the bus */
2037 return 0;
2038 return (MptResetHandlers[index])(ioc, reset_phase);
2039}
2040
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002042/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2044 * @ioc: Pointer to MPT adapter structure
2045 * @reason: Event word / reason
2046 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2047 *
2048 * This routine performs all the steps necessary to bring the IOC
2049 * to a OPERATIONAL state.
2050 *
2051 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2052 * MPT adapter.
2053 *
2054 * Returns:
2055 * 0 for success
2056 * -1 if failed to get board READY
2057 * -2 if READY but IOCFacts Failed
2058 * -3 if READY but PrimeIOCFifos Failed
2059 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302060 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302061 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 */
2063static int
2064mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2065{
2066 int hard_reset_done = 0;
2067 int alt_ioc_ready = 0;
2068 int hard;
2069 int rc=0;
2070 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302071 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 int handlers;
2073 int ret = 0;
2074 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002075 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302076 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Eric Moore29dd3602007-09-14 18:46:51 -06002078 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2079 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
2081 /* Disable reply interrupts (also blocks FreeQ) */
2082 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2083 ioc->active = 0;
2084
2085 if (ioc->alt_ioc) {
2086 if (ioc->alt_ioc->active)
2087 reset_alt_ioc_active = 1;
2088
2089 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2090 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2091 ioc->alt_ioc->active = 0;
2092 }
2093
2094 hard = 1;
2095 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2096 hard = 0;
2097
2098 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2099 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002100 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2101 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
2103 if (reset_alt_ioc_active && ioc->alt_ioc) {
2104 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002105 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2106 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002107 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 ioc->alt_ioc->active = 1;
2109 }
2110
2111 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002112 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 }
2114 return -1;
2115 }
2116
2117 /* hard_reset_done = 0 if a soft reset was performed
2118 * and 1 if a hard reset was performed.
2119 */
2120 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2121 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2122 alt_ioc_ready = 1;
2123 else
Eric Moore29dd3602007-09-14 18:46:51 -06002124 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 }
2126
2127 for (ii=0; ii<5; ii++) {
2128 /* Get IOC facts! Allow 5 retries */
2129 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2130 break;
2131 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
2134 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002135 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2136 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 ret = -2;
2138 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2139 MptDisplayIocCapabilities(ioc);
2140 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002141
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 if (alt_ioc_ready) {
2143 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302144 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002145 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 /* Retry - alt IOC was initialized once
2147 */
2148 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2149 }
2150 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302151 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002152 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 alt_ioc_ready = 0;
2154 reset_alt_ioc_active = 0;
2155 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2156 MptDisplayIocCapabilities(ioc->alt_ioc);
2157 }
2158 }
2159
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302160 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2161 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2162 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2163 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2164 IORESOURCE_IO);
2165 if (pci_enable_device(ioc->pcidev))
2166 return -5;
2167 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2168 "mpt"))
2169 return -5;
2170 }
2171
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002172 /*
2173 * Device is reset now. It must have de-asserted the interrupt line
2174 * (if it was asserted) and it should be safe to register for the
2175 * interrupt now.
2176 */
2177 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2178 ioc->pci_irq = -1;
2179 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302180 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002181 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002182 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302183 else
2184 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002185 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002186 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002187 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002188 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002189 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302190 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002191 pci_disable_msi(ioc->pcidev);
2192 return -EBUSY;
2193 }
2194 irq_allocated = 1;
2195 ioc->pci_irq = ioc->pcidev->irq;
2196 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002197 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2198 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002199 }
2200 }
2201
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 /* Prime reply & request queues!
2203 * (mucho alloc's) Must be done prior to
2204 * init as upper addresses are needed for init.
2205 * If fails, continue with alt-ioc processing
2206 */
2207 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2208 ret = -3;
2209
2210 /* May need to check/upload firmware & data here!
2211 * If fails, continue with alt-ioc processing
2212 */
2213 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2214 ret = -4;
2215// NEW!
2216 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002217 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2218 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 alt_ioc_ready = 0;
2220 reset_alt_ioc_active = 0;
2221 }
2222
2223 if (alt_ioc_ready) {
2224 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2225 alt_ioc_ready = 0;
2226 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002227 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2228 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 }
2230 }
2231
2232 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2233 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302234 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002235 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
2237 /* Controller is not operational, cannot do upload
2238 */
2239 if (ret == 0) {
2240 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002241 if (rc == 0) {
2242 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2243 /*
2244 * Maintain only one pointer to FW memory
2245 * so there will not be two attempt to
2246 * downloadboot onboard dual function
2247 * chips (mpt_adapter_disable,
2248 * mpt_diag_reset)
2249 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302250 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002251 "mpt_upload: alt_%s has cached_fw=%p \n",
2252 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302253 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002254 }
2255 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002256 printk(MYIOC_s_WARN_FMT
2257 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302258 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 }
2261 }
2262 }
2263
2264 if (ret == 0) {
2265 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002266 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 ioc->active = 1;
2268 }
2269
2270 if (reset_alt_ioc_active && ioc->alt_ioc) {
2271 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002272 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2273 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002274 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 ioc->alt_ioc->active = 1;
2276 }
2277
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002278 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 * and EventAck handling.
2280 */
2281 if ((ret == 0) && (!ioc->facts.EventState))
2282 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2283
2284 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2285 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2286
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002287 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2289 * recursive scenario; GetLanConfigPages times out, timer expired
2290 * routine calls HardResetHandler, which calls into here again,
2291 * and we try GetLanConfigPages again...
2292 */
2293 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002294
2295 /*
2296 * Initalize link list for inactive raid volumes.
2297 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002298 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002299 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2300
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002301 if (ioc->bus_type == SAS) {
2302
2303 /* clear persistency table */
2304 if(ioc->facts.IOCExceptions &
2305 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2306 ret = mptbase_sas_persist_operation(ioc,
2307 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2308 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002309 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002310 }
2311
2312 /* Find IM volumes
2313 */
2314 mpt_findImVolumes(ioc);
2315
2316 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2318 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2319 /*
2320 * Pre-fetch the ports LAN MAC address!
2321 * (LANPage1_t stuff)
2322 */
2323 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302324 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2325 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002326 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2327 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302328
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 }
2330 } else {
2331 /* Get NVRAM and adapter maximums from SPP 0 and 2
2332 */
2333 mpt_GetScsiPortSettings(ioc, 0);
2334
2335 /* Get version and length of SDP 1
2336 */
2337 mpt_readScsiDevicePageHeaders(ioc, 0);
2338
2339 /* Find IM volumes
2340 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002341 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 mpt_findImVolumes(ioc);
2343
2344 /* Check, and possibly reset, the coalescing value
2345 */
2346 mpt_read_ioc_pg_1(ioc);
2347
2348 mpt_read_ioc_pg_4(ioc);
2349 }
2350
2351 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302352 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 }
2354
2355 /*
2356 * Call each currently registered protocol IOC reset handler
2357 * with post-reset indication.
2358 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2359 * MptResetHandlers[] registered yet.
2360 */
2361 if (hard_reset_done) {
2362 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302363 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2364 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302365 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002366 "Calling IOC post_reset handler #%d\n",
2367 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302368 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 handlers++;
2370 }
2371
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302372 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302373 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002374 "Calling IOC post_reset handler #%d\n",
2375 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302376 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 handlers++;
2378 }
2379 }
2380 /* FIXME? Examine results here? */
2381 }
2382
Eric Moore0ccdb002006-07-11 17:33:13 -06002383 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002384 if ((ret != 0) && irq_allocated) {
2385 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302386 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002387 pci_disable_msi(ioc->pcidev);
2388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 return ret;
2390}
2391
2392/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002393/**
2394 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 * @ioc: Pointer to MPT adapter structure
2396 * @pdev: Pointer to (struct pci_dev) structure
2397 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002398 * Search for PCI bus/dev_function which matches
2399 * PCI bus/dev_function (+/-1) for newly discovered 929,
2400 * 929X, 1030 or 1035.
2401 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2403 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2404 */
2405static void
2406mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2407{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002408 struct pci_dev *peer=NULL;
2409 unsigned int slot = PCI_SLOT(pdev->devfn);
2410 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 MPT_ADAPTER *ioc_srch;
2412
Prakash, Sathya436ace72007-07-24 15:42:08 +05302413 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002414 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002415 ioc->name, pci_name(pdev), pdev->bus->number,
2416 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002417
2418 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2419 if (!peer) {
2420 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2421 if (!peer)
2422 return;
2423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 list_for_each_entry(ioc_srch, &ioc_list, list) {
2426 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002427 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 /* Paranoia checks */
2429 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002430 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002431 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 break;
2433 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002434 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002435 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 break;
2437 }
Eric Moore29dd3602007-09-14 18:46:51 -06002438 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002439 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 ioc_srch->alt_ioc = ioc;
2441 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 }
2443 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002444 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445}
2446
2447/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002448/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002450 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 */
2452static void
2453mpt_adapter_disable(MPT_ADAPTER *ioc)
2454{
2455 int sz;
2456 int ret;
2457
2458 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302459 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002460 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302461 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2462 ioc->cached_fw, CAN_SLEEP)) < 0) {
2463 printk(MYIOC_s_WARN_FMT
2464 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002465 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 }
2467 }
2468
2469 /* Disable adapter interrupts! */
2470 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2471 ioc->active = 0;
2472 /* Clear any lingering interrupt */
2473 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2474
2475 if (ioc->alloc != NULL) {
2476 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002477 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2478 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 pci_free_consistent(ioc->pcidev, sz,
2480 ioc->alloc, ioc->alloc_dma);
2481 ioc->reply_frames = NULL;
2482 ioc->req_frames = NULL;
2483 ioc->alloc = NULL;
2484 ioc->alloc_total -= sz;
2485 }
2486
2487 if (ioc->sense_buf_pool != NULL) {
2488 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2489 pci_free_consistent(ioc->pcidev, sz,
2490 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2491 ioc->sense_buf_pool = NULL;
2492 ioc->alloc_total -= sz;
2493 }
2494
2495 if (ioc->events != NULL){
2496 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2497 kfree(ioc->events);
2498 ioc->events = NULL;
2499 ioc->alloc_total -= sz;
2500 }
2501
Prakash, Sathya984621b2008-01-11 14:42:17 +05302502 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002504 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002505 mpt_inactive_raid_list_free(ioc);
2506 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002507 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002508 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002509 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 if (ioc->spi_data.pIocPg4 != NULL) {
2512 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302513 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 ioc->spi_data.pIocPg4,
2515 ioc->spi_data.IocPg4_dma);
2516 ioc->spi_data.pIocPg4 = NULL;
2517 ioc->alloc_total -= sz;
2518 }
2519
2520 if (ioc->ReqToChain != NULL) {
2521 kfree(ioc->ReqToChain);
2522 kfree(ioc->RequestNB);
2523 ioc->ReqToChain = NULL;
2524 }
2525
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002526 kfree(ioc->ChainToChain);
2527 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002528
2529 if (ioc->HostPageBuffer != NULL) {
2530 if((ret = mpt_host_page_access_control(ioc,
2531 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002532 printk(MYIOC_s_ERR_FMT
2533 "host page buffers free failed (%d)!\n",
2534 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002535 }
Eric Moore29dd3602007-09-14 18:46:51 -06002536 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002537 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2538 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002539 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002540 ioc->HostPageBuffer = NULL;
2541 ioc->HostPageBuffer_sz = 0;
2542 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544}
2545
2546/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002547/**
2548 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 * @ioc: Pointer to MPT adapter structure
2550 *
2551 * This routine unregisters h/w resources and frees all alloc'd memory
2552 * associated with a MPT adapter structure.
2553 */
2554static void
2555mpt_adapter_dispose(MPT_ADAPTER *ioc)
2556{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002557 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002559 if (ioc == NULL)
2560 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002562 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002564 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002566 if (ioc->pci_irq != -1) {
2567 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302568 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002569 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002570 ioc->pci_irq = -1;
2571 }
2572
2573 if (ioc->memmap != NULL) {
2574 iounmap(ioc->memmap);
2575 ioc->memmap = NULL;
2576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302578 pci_disable_device(ioc->pcidev);
2579 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2580
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002582 if (ioc->mtrr_reg > 0) {
2583 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002584 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586#endif
2587
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002588 /* Zap the adapter lookup ptr! */
2589 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002591 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002592 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2593 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002594
2595 if (ioc->alt_ioc)
2596 ioc->alt_ioc->alt_ioc = NULL;
2597
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002598 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599}
2600
2601/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002602/**
2603 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 * @ioc: Pointer to MPT adapter structure
2605 */
2606static void
2607MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2608{
2609 int i = 0;
2610
2611 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302612 if (ioc->prod_name)
2613 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 printk("Capabilities={");
2615
2616 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2617 printk("Initiator");
2618 i++;
2619 }
2620
2621 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2622 printk("%sTarget", i ? "," : "");
2623 i++;
2624 }
2625
2626 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2627 printk("%sLAN", i ? "," : "");
2628 i++;
2629 }
2630
2631#if 0
2632 /*
2633 * This would probably evoke more questions than it's worth
2634 */
2635 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2636 printk("%sLogBusAddr", i ? "," : "");
2637 i++;
2638 }
2639#endif
2640
2641 printk("}\n");
2642}
2643
2644/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002645/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2647 * @ioc: Pointer to MPT_ADAPTER structure
2648 * @force: Force hard KickStart of IOC
2649 * @sleepFlag: Specifies whether the process can sleep
2650 *
2651 * Returns:
2652 * 1 - DIAG reset and READY
2653 * 0 - READY initially OR soft reset and READY
2654 * -1 - Any failure on KickStart
2655 * -2 - Msg Unit Reset Failed
2656 * -3 - IO Unit Reset Failed
2657 * -4 - IOC owned by a PEER
2658 */
2659static int
2660MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2661{
2662 u32 ioc_state;
2663 int statefault = 0;
2664 int cntdn;
2665 int hard_reset_done = 0;
2666 int r;
2667 int ii;
2668 int whoinit;
2669
2670 /* Get current [raw] IOC state */
2671 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002672 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
2674 /*
2675 * Check to see if IOC got left/stuck in doorbell handshake
2676 * grip of death. If so, hard reset the IOC.
2677 */
2678 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2679 statefault = 1;
2680 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2681 ioc->name);
2682 }
2683
2684 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002685 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 return 0;
2687
2688 /*
2689 * Check to see if IOC is in FAULT state.
2690 */
2691 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2692 statefault = 2;
2693 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002694 ioc->name);
2695 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2696 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 }
2698
2699 /*
2700 * Hmmm... Did it get left operational?
2701 */
2702 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302703 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 ioc->name));
2705
2706 /* Check WhoInit.
2707 * If PCI Peer, exit.
2708 * Else, if no fault conditions are present, issue a MessageUnitReset
2709 * Else, fall through to KickStart case
2710 */
2711 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002712 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2713 "whoinit 0x%x statefault %d force %d\n",
2714 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 if (whoinit == MPI_WHOINIT_PCI_PEER)
2716 return -4;
2717 else {
2718 if ((statefault == 0 ) && (force == 0)) {
2719 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2720 return 0;
2721 }
2722 statefault = 3;
2723 }
2724 }
2725
2726 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2727 if (hard_reset_done < 0)
2728 return -1;
2729
2730 /*
2731 * Loop here waiting for IOC to come READY.
2732 */
2733 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002734 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735
2736 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2737 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2738 /*
2739 * BIOS or previous driver load left IOC in OP state.
2740 * Reset messaging FIFOs.
2741 */
2742 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2743 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2744 return -2;
2745 }
2746 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2747 /*
2748 * Something is wrong. Try to get IOC back
2749 * to a known state.
2750 */
2751 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2752 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2753 return -3;
2754 }
2755 }
2756
2757 ii++; cntdn--;
2758 if (!cntdn) {
2759 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2760 ioc->name, (int)((ii+5)/HZ));
2761 return -ETIME;
2762 }
2763
2764 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002765 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 } else {
2767 mdelay (1); /* 1 msec delay */
2768 }
2769
2770 }
2771
2772 if (statefault < 3) {
2773 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2774 ioc->name,
2775 statefault==1 ? "stuck handshake" : "IOC FAULT");
2776 }
2777
2778 return hard_reset_done;
2779}
2780
2781/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002782/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 * mpt_GetIocState - Get the current state of a MPT adapter.
2784 * @ioc: Pointer to MPT_ADAPTER structure
2785 * @cooked: Request raw or cooked IOC state
2786 *
2787 * Returns all IOC Doorbell register bits if cooked==0, else just the
2788 * Doorbell bits in MPI_IOC_STATE_MASK.
2789 */
2790u32
2791mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2792{
2793 u32 s, sc;
2794
2795 /* Get! */
2796 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 sc = s & MPI_IOC_STATE_MASK;
2798
2799 /* Save! */
2800 ioc->last_state = sc;
2801
2802 return cooked ? sc : s;
2803}
2804
2805/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002806/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 * GetIocFacts - Send IOCFacts request to MPT adapter.
2808 * @ioc: Pointer to MPT_ADAPTER structure
2809 * @sleepFlag: Specifies whether the process can sleep
2810 * @reason: If recovery, only update facts.
2811 *
2812 * Returns 0 for success, non-zero for failure.
2813 */
2814static int
2815GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2816{
2817 IOCFacts_t get_facts;
2818 IOCFactsReply_t *facts;
2819 int r;
2820 int req_sz;
2821 int reply_sz;
2822 int sz;
2823 u32 status, vv;
2824 u8 shiftFactor=1;
2825
2826 /* IOC *must* NOT be in RESET state! */
2827 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002828 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2829 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 return -44;
2831 }
2832
2833 facts = &ioc->facts;
2834
2835 /* Destination (reply area)... */
2836 reply_sz = sizeof(*facts);
2837 memset(facts, 0, reply_sz);
2838
2839 /* Request area (get_facts on the stack right now!) */
2840 req_sz = sizeof(get_facts);
2841 memset(&get_facts, 0, req_sz);
2842
2843 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2844 /* Assert: All other get_facts fields are zero! */
2845
Prakash, Sathya436ace72007-07-24 15:42:08 +05302846 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002847 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 ioc->name, req_sz, reply_sz));
2849
2850 /* No non-zero fields in the get_facts request are greater than
2851 * 1 byte in size, so we can just fire it off as is.
2852 */
2853 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2854 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2855 if (r != 0)
2856 return r;
2857
2858 /*
2859 * Now byte swap (GRRR) the necessary fields before any further
2860 * inspection of reply contents.
2861 *
2862 * But need to do some sanity checks on MsgLength (byte) field
2863 * to make sure we don't zero IOC's req_sz!
2864 */
2865 /* Did we get a valid reply? */
2866 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2867 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2868 /*
2869 * If not been here, done that, save off first WhoInit value
2870 */
2871 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2872 ioc->FirstWhoInit = facts->WhoInit;
2873 }
2874
2875 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2876 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2877 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2878 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2879 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002880 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 /* CHECKME! IOCStatus, IOCLogInfo */
2882
2883 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2884 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2885
2886 /*
2887 * FC f/w version changed between 1.1 and 1.2
2888 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2889 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2890 */
2891 if (facts->MsgVersion < 0x0102) {
2892 /*
2893 * Handle old FC f/w style, convert to new...
2894 */
2895 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2896 facts->FWVersion.Word =
2897 ((oldv<<12) & 0xFF000000) |
2898 ((oldv<<8) & 0x000FFF00);
2899 } else
2900 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2901
2902 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002903 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2904 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2905 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 facts->CurrentHostMfaHighAddr =
2907 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2908 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2909 facts->CurrentSenseBufferHighAddr =
2910 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2911 facts->CurReplyFrameSize =
2912 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002913 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
2915 /*
2916 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2917 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2918 * to 14 in MPI-1.01.0x.
2919 */
2920 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2921 facts->MsgVersion > 0x0100) {
2922 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2923 }
2924
2925 sz = facts->FWImageSize;
2926 if ( sz & 0x01 )
2927 sz += 1;
2928 if ( sz & 0x02 )
2929 sz += 2;
2930 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002931
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 if (!facts->RequestFrameSize) {
2933 /* Something is wrong! */
2934 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2935 ioc->name);
2936 return -55;
2937 }
2938
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002939 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 vv = ((63 / (sz * 4)) + 1) & 0x03;
2941 ioc->NB_for_64_byte_frame = vv;
2942 while ( sz )
2943 {
2944 shiftFactor++;
2945 sz = sz >> 1;
2946 }
2947 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302948 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002949 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2950 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002951
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2953 /*
2954 * Set values for this IOC's request & reply frame sizes,
2955 * and request & reply queue depths...
2956 */
2957 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2958 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2959 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2960 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2961
Prakash, Sathya436ace72007-07-24 15:42:08 +05302962 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302964 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 ioc->name, ioc->req_sz, ioc->req_depth));
2966
2967 /* Get port facts! */
2968 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2969 return r;
2970 }
2971 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002972 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2974 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2975 RequestFrameSize)/sizeof(u32)));
2976 return -66;
2977 }
2978
2979 return 0;
2980}
2981
2982/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002983/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 * GetPortFacts - Send PortFacts request to MPT adapter.
2985 * @ioc: Pointer to MPT_ADAPTER structure
2986 * @portnum: Port number
2987 * @sleepFlag: Specifies whether the process can sleep
2988 *
2989 * Returns 0 for success, non-zero for failure.
2990 */
2991static int
2992GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2993{
2994 PortFacts_t get_pfacts;
2995 PortFactsReply_t *pfacts;
2996 int ii;
2997 int req_sz;
2998 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002999 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000
3001 /* IOC *must* NOT be in RESET state! */
3002 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003003 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3004 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 return -4;
3006 }
3007
3008 pfacts = &ioc->pfacts[portnum];
3009
3010 /* Destination (reply area)... */
3011 reply_sz = sizeof(*pfacts);
3012 memset(pfacts, 0, reply_sz);
3013
3014 /* Request area (get_pfacts on the stack right now!) */
3015 req_sz = sizeof(get_pfacts);
3016 memset(&get_pfacts, 0, req_sz);
3017
3018 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3019 get_pfacts.PortNumber = portnum;
3020 /* Assert: All other get_pfacts fields are zero! */
3021
Prakash, Sathya436ace72007-07-24 15:42:08 +05303022 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 ioc->name, portnum));
3024
3025 /* No non-zero fields in the get_pfacts request are greater than
3026 * 1 byte in size, so we can just fire it off as is.
3027 */
3028 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3029 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3030 if (ii != 0)
3031 return ii;
3032
3033 /* Did we get a valid reply? */
3034
3035 /* Now byte swap the necessary fields in the response. */
3036 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3037 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3038 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3039 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3040 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3041 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3042 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3043 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3044 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3045
Eric Moore793955f2007-01-29 09:42:20 -07003046 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3047 pfacts->MaxDevices;
3048 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3049 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3050
3051 /*
3052 * Place all the devices on channels
3053 *
3054 * (for debuging)
3055 */
3056 if (mpt_channel_mapping) {
3057 ioc->devices_per_bus = 1;
3058 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3059 }
3060
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 return 0;
3062}
3063
3064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003065/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 * SendIocInit - Send IOCInit request to MPT adapter.
3067 * @ioc: Pointer to MPT_ADAPTER structure
3068 * @sleepFlag: Specifies whether the process can sleep
3069 *
3070 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3071 *
3072 * Returns 0 for success, non-zero for failure.
3073 */
3074static int
3075SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3076{
3077 IOCInit_t ioc_init;
3078 MPIDefaultReply_t init_reply;
3079 u32 state;
3080 int r;
3081 int count;
3082 int cntdn;
3083
3084 memset(&ioc_init, 0, sizeof(ioc_init));
3085 memset(&init_reply, 0, sizeof(init_reply));
3086
3087 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3088 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3089
3090 /* If we are in a recovery mode and we uploaded the FW image,
3091 * then this pointer is not NULL. Skip the upload a second time.
3092 * Set this flag if cached_fw set for either IOC.
3093 */
3094 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3095 ioc->upload_fw = 1;
3096 else
3097 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303098 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3100
Eric Moore793955f2007-01-29 09:42:20 -07003101 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3102 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303103 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003104 ioc->name, ioc->facts.MsgVersion));
3105 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3106 // set MsgVersion and HeaderVersion host driver was built with
3107 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3108 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003110 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3111 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3112 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3113 return -99;
3114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3116
3117 if (sizeof(dma_addr_t) == sizeof(u64)) {
3118 /* Save the upper 32-bits of the request
3119 * (reply) and sense buffers.
3120 */
3121 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3122 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3123 } else {
3124 /* Force 32-bit addressing */
3125 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3126 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3127 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003128
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3130 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003131 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3132 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
Prakash, Sathya436ace72007-07-24 15:42:08 +05303134 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 ioc->name, &ioc_init));
3136
3137 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3138 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003139 if (r != 0) {
3140 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143
3144 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003145 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 */
3147
Prakash, Sathya436ace72007-07-24 15:42:08 +05303148 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003150
3151 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3152 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
3156 /* YIKES! SUPER IMPORTANT!!!
3157 * Poll IocState until _OPERATIONAL while IOC is doing
3158 * LoopInit and TargetDiscovery!
3159 */
3160 count = 0;
3161 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3162 state = mpt_GetIocState(ioc, 1);
3163 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3164 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003165 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 } else {
3167 mdelay(1);
3168 }
3169
3170 if (!cntdn) {
3171 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3172 ioc->name, (int)((count+5)/HZ));
3173 return -9;
3174 }
3175
3176 state = mpt_GetIocState(ioc, 1);
3177 count++;
3178 }
Eric Moore29dd3602007-09-14 18:46:51 -06003179 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 ioc->name, count));
3181
Eric Mooreba856d32006-07-11 17:34:01 -06003182 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 return r;
3184}
3185
3186/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003187/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 * SendPortEnable - Send PortEnable request to MPT adapter port.
3189 * @ioc: Pointer to MPT_ADAPTER structure
3190 * @portnum: Port number to enable
3191 * @sleepFlag: Specifies whether the process can sleep
3192 *
3193 * Send PortEnable to bring IOC to OPERATIONAL state.
3194 *
3195 * Returns 0 for success, non-zero for failure.
3196 */
3197static int
3198SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3199{
3200 PortEnable_t port_enable;
3201 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003202 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 int req_sz;
3204 int reply_sz;
3205
3206 /* Destination... */
3207 reply_sz = sizeof(MPIDefaultReply_t);
3208 memset(&reply_buf, 0, reply_sz);
3209
3210 req_sz = sizeof(PortEnable_t);
3211 memset(&port_enable, 0, req_sz);
3212
3213 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3214 port_enable.PortNumber = portnum;
3215/* port_enable.ChainOffset = 0; */
3216/* port_enable.MsgFlags = 0; */
3217/* port_enable.MsgContext = 0; */
3218
Prakash, Sathya436ace72007-07-24 15:42:08 +05303219 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 ioc->name, portnum, &port_enable));
3221
3222 /* RAID FW may take a long time to enable
3223 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003224 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003225 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3226 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3227 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003228 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003229 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3230 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3231 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003233 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234}
3235
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003236/**
3237 * mpt_alloc_fw_memory - allocate firmware memory
3238 * @ioc: Pointer to MPT_ADAPTER structure
3239 * @size: total FW bytes
3240 *
3241 * If memory has already been allocated, the same (cached) value
3242 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303243 *
3244 * Return 0 if successfull, or non-zero for failure
3245 **/
3246int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3248{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303249 int rc;
3250
3251 if (ioc->cached_fw) {
3252 rc = 0; /* use already allocated memory */
3253 goto out;
3254 }
3255 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3257 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303258 rc = 0;
3259 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303261 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3262 if (!ioc->cached_fw) {
3263 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3264 ioc->name);
3265 rc = -1;
3266 } else {
3267 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3268 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3269 ioc->alloc_total += size;
3270 rc = 0;
3271 }
3272 out:
3273 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303275
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003276/**
3277 * mpt_free_fw_memory - free firmware memory
3278 * @ioc: Pointer to MPT_ADAPTER structure
3279 *
3280 * If alt_img is NULL, delete from ioc structure.
3281 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303282 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283void
3284mpt_free_fw_memory(MPT_ADAPTER *ioc)
3285{
3286 int sz;
3287
Prakash, Sathya984621b2008-01-11 14:42:17 +05303288 if (!ioc->cached_fw)
3289 return;
3290
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303292 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3293 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003294 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303295 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297}
3298
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003300/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3302 * @ioc: Pointer to MPT_ADAPTER structure
3303 * @sleepFlag: Specifies whether the process can sleep
3304 *
3305 * Returns 0 for success, >0 for handshake failure
3306 * <0 for fw upload failure.
3307 *
3308 * Remark: If bound IOC and a successful FWUpload was performed
3309 * on the bound IOC, the second image is discarded
3310 * and memory is free'd. Both channels must upload to prevent
3311 * IOC from running in degraded mode.
3312 */
3313static int
3314mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3315{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 u8 reply[sizeof(FWUploadReply_t)];
3317 FWUpload_t *prequest;
3318 FWUploadReply_t *preply;
3319 FWUploadTCSGE_t *ptcsge;
3320 int sgeoffset;
3321 u32 flagsLength;
3322 int ii, sz, reply_sz;
3323 int cmdStatus;
3324
3325 /* If the image size is 0, we are done.
3326 */
3327 if ((sz = ioc->facts.FWImageSize) == 0)
3328 return 0;
3329
Prakash, Sathya984621b2008-01-11 14:42:17 +05303330 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3331 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332
Eric Moore29dd3602007-09-14 18:46:51 -06003333 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3334 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003335
Eric Moorebc6e0892007-09-29 10:16:28 -06003336 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3337 kzalloc(ioc->req_sz, GFP_KERNEL);
3338 if (!prequest) {
3339 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3340 "while allocating memory \n", ioc->name));
3341 mpt_free_fw_memory(ioc);
3342 return -ENOMEM;
3343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344
Eric Moorebc6e0892007-09-29 10:16:28 -06003345 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
3347 reply_sz = sizeof(reply);
3348 memset(preply, 0, reply_sz);
3349
3350 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3351 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3352
3353 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3354 ptcsge->DetailsLength = 12;
3355 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3356 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003357 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358
3359 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3360
3361 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003362 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
3364 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003365 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3366 ioc->name, prequest, sgeoffset));
3367 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368
3369 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3370 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3371
Eric Moore29dd3602007-09-14 18:46:51 -06003372 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373
3374 cmdStatus = -EFAULT;
3375 if (ii == 0) {
3376 /* Handshake transfer was complete and successful.
3377 * Check the Reply Frame.
3378 */
3379 int status, transfer_sz;
3380 status = le16_to_cpu(preply->IOCStatus);
3381 if (status == MPI_IOCSTATUS_SUCCESS) {
3382 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3383 if (transfer_sz == sz)
3384 cmdStatus = 0;
3385 }
3386 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303387 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 ioc->name, cmdStatus));
3389
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003390
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 if (cmdStatus) {
3392
Prakash, Sathya436ace72007-07-24 15:42:08 +05303393 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 ioc->name));
3395 mpt_free_fw_memory(ioc);
3396 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003397 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398
3399 return cmdStatus;
3400}
3401
3402/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003403/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 * mpt_downloadboot - DownloadBoot code
3405 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003406 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 * @sleepFlag: Specifies whether the process can sleep
3408 *
3409 * FwDownloadBoot requires Programmed IO access.
3410 *
3411 * Returns 0 for success
3412 * -1 FW Image size is 0
3413 * -2 No valid cached_fw Pointer
3414 * <0 for fw upload failure.
3415 */
3416static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003417mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 MpiExtImageHeader_t *pExtImage;
3420 u32 fwSize;
3421 u32 diag0val;
3422 int count;
3423 u32 *ptrFw;
3424 u32 diagRwData;
3425 u32 nextImage;
3426 u32 load_addr;
3427 u32 ioc_state=0;
3428
Prakash, Sathya436ace72007-07-24 15:42:08 +05303429 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003430 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003431
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3433 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3434 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3435 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3436 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3437 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3438
3439 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3440
3441 /* wait 1 msec */
3442 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003443 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 } else {
3445 mdelay (1);
3446 }
3447
3448 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3449 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3450
3451 for (count = 0; count < 30; count ++) {
3452 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3453 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303454 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 ioc->name, count));
3456 break;
3457 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003458 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003460 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003462 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 }
3464 }
3465
3466 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303467 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003468 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 ioc->name, diag0val));
3470 return -3;
3471 }
3472
3473 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3474 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3475 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3476 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3477 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3478 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3479
3480 /* Set the DiagRwEn and Disable ARM bits */
3481 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3482
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 fwSize = (pFwHeader->ImageSize + 3)/4;
3484 ptrFw = (u32 *) pFwHeader;
3485
3486 /* Write the LoadStartAddress to the DiagRw Address Register
3487 * using Programmed IO
3488 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003489 if (ioc->errata_flag_1064)
3490 pci_enable_io_access(ioc->pcidev);
3491
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303493 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 ioc->name, pFwHeader->LoadStartAddress));
3495
Prakash, Sathya436ace72007-07-24 15:42:08 +05303496 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 ioc->name, fwSize*4, ptrFw));
3498 while (fwSize--) {
3499 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3500 }
3501
3502 nextImage = pFwHeader->NextImageHeaderOffset;
3503 while (nextImage) {
3504 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3505
3506 load_addr = pExtImage->LoadStartAddress;
3507
3508 fwSize = (pExtImage->ImageSize + 3) >> 2;
3509 ptrFw = (u32 *)pExtImage;
3510
Prakash, Sathya436ace72007-07-24 15:42:08 +05303511 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 +02003512 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3514
3515 while (fwSize--) {
3516 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3517 }
3518 nextImage = pExtImage->NextImageHeaderOffset;
3519 }
3520
3521 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303522 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3524
3525 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303526 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3528
3529 /* Clear the internal flash bad bit - autoincrementing register,
3530 * so must do two writes.
3531 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003532 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003533 /*
3534 * 1030 and 1035 H/W errata, workaround to access
3535 * the ClearFlashBadSignatureBit
3536 */
3537 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3538 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3539 diagRwData |= 0x40000000;
3540 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3541 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3542
3543 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3544 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3545 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3546 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3547
3548 /* wait 1 msec */
3549 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003550 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003551 } else {
3552 mdelay (1);
3553 }
3554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003556 if (ioc->errata_flag_1064)
3557 pci_disable_io_access(ioc->pcidev);
3558
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303560 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003561 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003563 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303564 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 ioc->name, diag0val));
3566 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3567
3568 /* Write 0xFF to reset the sequencer */
3569 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3570
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003571 if (ioc->bus_type == SAS) {
3572 ioc_state = mpt_GetIocState(ioc, 0);
3573 if ( (GetIocFacts(ioc, sleepFlag,
3574 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303575 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003576 ioc->name, ioc_state));
3577 return -EFAULT;
3578 }
3579 }
3580
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 for (count=0; count<HZ*20; count++) {
3582 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303583 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3584 "downloadboot successful! (count=%d) IocState=%x\n",
3585 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003586 if (ioc->bus_type == SAS) {
3587 return 0;
3588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303590 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3591 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 ioc->name));
3593 return -EFAULT;
3594 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303595 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3596 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 ioc->name));
3598 return 0;
3599 }
3600 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003601 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 } else {
3603 mdelay (10);
3604 }
3605 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303606 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3607 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 return -EFAULT;
3609}
3610
3611/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003612/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 * KickStart - Perform hard reset of MPT adapter.
3614 * @ioc: Pointer to MPT_ADAPTER structure
3615 * @force: Force hard reset
3616 * @sleepFlag: Specifies whether the process can sleep
3617 *
3618 * This routine places MPT adapter in diagnostic mode via the
3619 * WriteSequence register, and then performs a hard reset of adapter
3620 * via the Diagnostic register.
3621 *
3622 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3623 * or NO_SLEEP (interrupt thread, use mdelay)
3624 * force - 1 if doorbell active, board fault state
3625 * board operational, IOC_RECOVERY or
3626 * IOC_BRINGUP and there is an alt_ioc.
3627 * 0 else
3628 *
3629 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003630 * 1 - hard reset, READY
3631 * 0 - no reset due to History bit, READY
3632 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 * OR reset but failed to come READY
3634 * -2 - no reset, could not enter DIAG mode
3635 * -3 - reset but bad FW bit
3636 */
3637static int
3638KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3639{
3640 int hard_reset_done = 0;
3641 u32 ioc_state=0;
3642 int cnt,cntdn;
3643
Eric Moore29dd3602007-09-14 18:46:51 -06003644 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003645 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 /* Always issue a Msg Unit Reset first. This will clear some
3647 * SCSI bus hang conditions.
3648 */
3649 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3650
3651 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003652 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 } else {
3654 mdelay (1000);
3655 }
3656 }
3657
3658 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3659 if (hard_reset_done < 0)
3660 return hard_reset_done;
3661
Prakash, Sathya436ace72007-07-24 15:42:08 +05303662 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003663 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664
3665 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3666 for (cnt=0; cnt<cntdn; cnt++) {
3667 ioc_state = mpt_GetIocState(ioc, 1);
3668 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303669 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 ioc->name, cnt));
3671 return hard_reset_done;
3672 }
3673 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003674 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 } else {
3676 mdelay (10);
3677 }
3678 }
3679
Eric Moore29dd3602007-09-14 18:46:51 -06003680 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3681 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 return -1;
3683}
3684
3685/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003686/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 * mpt_diag_reset - Perform hard reset of the adapter.
3688 * @ioc: Pointer to MPT_ADAPTER structure
3689 * @ignore: Set if to honor and clear to ignore
3690 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003691 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 * else set to NO_SLEEP (use mdelay instead)
3693 *
3694 * This routine places the adapter in diagnostic mode via the
3695 * WriteSequence register and then performs a hard reset of adapter
3696 * via the Diagnostic register. Adapter should be in ready state
3697 * upon successful completion.
3698 *
3699 * Returns: 1 hard reset successful
3700 * 0 no reset performed because reset history bit set
3701 * -2 enabling diagnostic mode failed
3702 * -3 diagnostic reset failed
3703 */
3704static int
3705mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3706{
3707 u32 diag0val;
3708 u32 doorbell;
3709 int hard_reset_done = 0;
3710 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303712 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713
Eric Moorecd2c6192007-01-29 09:47:47 -07003714 /* Clear any existing interrupts */
3715 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3716
Eric Moore87cf8982006-06-27 16:09:26 -06003717 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303718 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003719 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003720 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3721 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3722 if (sleepFlag == CAN_SLEEP)
3723 msleep(1);
3724 else
3725 mdelay(1);
3726
3727 for (count = 0; count < 60; count ++) {
3728 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3729 doorbell &= MPI_IOC_STATE_MASK;
3730
Prakash, Sathya436ace72007-07-24 15:42:08 +05303731 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003732 "looking for READY STATE: doorbell=%x"
3733 " count=%d\n",
3734 ioc->name, doorbell, count));
3735 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003736 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003737 }
3738
3739 /* wait 1 sec */
3740 if (sleepFlag == CAN_SLEEP)
3741 msleep(1000);
3742 else
3743 mdelay(1000);
3744 }
3745 return -1;
3746 }
3747
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 /* Use "Diagnostic reset" method! (only thing available!) */
3749 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3750
Prakash, Sathya436ace72007-07-24 15:42:08 +05303751 if (ioc->debug_level & MPT_DEBUG) {
3752 if (ioc->alt_ioc)
3753 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3754 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757
3758 /* Do the reset if we are told to ignore the reset history
3759 * or if the reset history is 0
3760 */
3761 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3762 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3763 /* Write magic sequence to WriteSequence register
3764 * Loop until in diagnostic mode
3765 */
3766 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3767 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3768 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3769 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3770 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3771 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3772
3773 /* wait 100 msec */
3774 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003775 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 } else {
3777 mdelay (100);
3778 }
3779
3780 count++;
3781 if (count > 20) {
3782 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3783 ioc->name, diag0val);
3784 return -2;
3785
3786 }
3787
3788 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3789
Prakash, Sathya436ace72007-07-24 15:42:08 +05303790 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 ioc->name, diag0val));
3792 }
3793
Prakash, Sathya436ace72007-07-24 15:42:08 +05303794 if (ioc->debug_level & MPT_DEBUG) {
3795 if (ioc->alt_ioc)
3796 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3797 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 /*
3801 * Disable the ARM (Bug fix)
3802 *
3803 */
3804 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003805 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806
3807 /*
3808 * Now hit the reset bit in the Diagnostic register
3809 * (THE BIG HAMMER!) (Clears DRWE bit).
3810 */
3811 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3812 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303813 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 ioc->name));
3815
3816 /*
3817 * Call each currently registered protocol IOC reset handler
3818 * with pre-reset indication.
3819 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3820 * MptResetHandlers[] registered yet.
3821 */
3822 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303823 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 int r = 0;
3825
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303826 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3827 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303828 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3829 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303830 ioc->name, cb_idx));
3831 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303833 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3834 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303835 ioc->name, ioc->alt_ioc->name, cb_idx));
3836 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 }
3838 }
3839 }
3840 /* FIXME? Examine results here? */
3841 }
3842
Eric Moore0ccdb002006-07-11 17:33:13 -06003843 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303844 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003845 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303846 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3847 else
3848 cached_fw = NULL;
3849 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 /* If the DownloadBoot operation fails, the
3851 * IOC will be left unusable. This is a fatal error
3852 * case. _diag_reset will return < 0
3853 */
3854 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303855 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3857 break;
3858 }
3859
Prakash, Sathya436ace72007-07-24 15:42:08 +05303860 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303861 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 /* wait 1 sec */
3863 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003864 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 } else {
3866 mdelay (1000);
3867 }
3868 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303869 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003870 printk(MYIOC_s_WARN_FMT
3871 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 }
3873
3874 } else {
3875 /* Wait for FW to reload and for board
3876 * to go to the READY state.
3877 * Maximum wait is 60 seconds.
3878 * If fail, no error will check again
3879 * with calling program.
3880 */
3881 for (count = 0; count < 60; count ++) {
3882 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3883 doorbell &= MPI_IOC_STATE_MASK;
3884
3885 if (doorbell == MPI_IOC_STATE_READY) {
3886 break;
3887 }
3888
3889 /* wait 1 sec */
3890 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003891 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 } else {
3893 mdelay (1000);
3894 }
3895 }
3896 }
3897 }
3898
3899 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303900 if (ioc->debug_level & MPT_DEBUG) {
3901 if (ioc->alt_ioc)
3902 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3903 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3904 ioc->name, diag0val, diag1val));
3905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906
3907 /* Clear RESET_HISTORY bit! Place board in the
3908 * diagnostic mode to update the diag register.
3909 */
3910 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3911 count = 0;
3912 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3913 /* Write magic sequence to WriteSequence register
3914 * Loop until in diagnostic mode
3915 */
3916 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3917 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3918 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3919 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3920 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3921 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3922
3923 /* wait 100 msec */
3924 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003925 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 } else {
3927 mdelay (100);
3928 }
3929
3930 count++;
3931 if (count > 20) {
3932 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3933 ioc->name, diag0val);
3934 break;
3935 }
3936 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3937 }
3938 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3939 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3940 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3941 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3942 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3943 ioc->name);
3944 }
3945
3946 /* Disable Diagnostic Mode
3947 */
3948 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3949
3950 /* Check FW reload status flags.
3951 */
3952 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3953 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3954 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3955 ioc->name, diag0val);
3956 return -3;
3957 }
3958
Prakash, Sathya436ace72007-07-24 15:42:08 +05303959 if (ioc->debug_level & MPT_DEBUG) {
3960 if (ioc->alt_ioc)
3961 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3962 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965
3966 /*
3967 * Reset flag that says we've enabled event notification
3968 */
3969 ioc->facts.EventState = 0;
3970
3971 if (ioc->alt_ioc)
3972 ioc->alt_ioc->facts.EventState = 0;
3973
3974 return hard_reset_done;
3975}
3976
3977/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003978/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 * SendIocReset - Send IOCReset request to MPT adapter.
3980 * @ioc: Pointer to MPT_ADAPTER structure
3981 * @reset_type: reset type, expected values are
3982 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003983 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 *
3985 * Send IOCReset request to the MPT adapter.
3986 *
3987 * Returns 0 for success, non-zero for failure.
3988 */
3989static int
3990SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3991{
3992 int r;
3993 u32 state;
3994 int cntdn, count;
3995
Prakash, Sathya436ace72007-07-24 15:42:08 +05303996 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 ioc->name, reset_type));
3998 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3999 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4000 return r;
4001
4002 /* FW ACK'd request, wait for READY state
4003 */
4004 count = 0;
4005 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4006
4007 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4008 cntdn--;
4009 count++;
4010 if (!cntdn) {
4011 if (sleepFlag != CAN_SLEEP)
4012 count *= 10;
4013
Eric Moore29dd3602007-09-14 18:46:51 -06004014 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
4015 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 return -ETIME;
4017 }
4018
4019 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004020 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 } else {
4022 mdelay (1); /* 1 msec delay */
4023 }
4024 }
4025
4026 /* TODO!
4027 * Cleanup all event stuff for this IOC; re-issue EventNotification
4028 * request if needed.
4029 */
4030 if (ioc->facts.Function)
4031 ioc->facts.EventState = 0;
4032
4033 return 0;
4034}
4035
4036/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004037/**
4038 * initChainBuffers - Allocate memory for and initialize chain buffers
4039 * @ioc: Pointer to MPT_ADAPTER structure
4040 *
4041 * Allocates memory for and initializes chain buffers,
4042 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 */
4044static int
4045initChainBuffers(MPT_ADAPTER *ioc)
4046{
4047 u8 *mem;
4048 int sz, ii, num_chain;
4049 int scale, num_sge, numSGE;
4050
4051 /* ReqToChain size must equal the req_depth
4052 * index = req_idx
4053 */
4054 if (ioc->ReqToChain == NULL) {
4055 sz = ioc->req_depth * sizeof(int);
4056 mem = kmalloc(sz, GFP_ATOMIC);
4057 if (mem == NULL)
4058 return -1;
4059
4060 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304061 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 ioc->name, mem, sz));
4063 mem = kmalloc(sz, GFP_ATOMIC);
4064 if (mem == NULL)
4065 return -1;
4066
4067 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304068 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 ioc->name, mem, sz));
4070 }
4071 for (ii = 0; ii < ioc->req_depth; ii++) {
4072 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4073 }
4074
4075 /* ChainToChain size must equal the total number
4076 * of chain buffers to be allocated.
4077 * index = chain_idx
4078 *
4079 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004080 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 *
4082 * num_sge = num sge in request frame + last chain buffer
4083 * scale = num sge per chain buffer if no chain element
4084 */
4085 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
4086 if (sizeof(dma_addr_t) == sizeof(u64))
4087 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4088 else
4089 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4090
4091 if (sizeof(dma_addr_t) == sizeof(u64)) {
4092 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4093 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4094 } else {
4095 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4096 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4097 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304098 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 ioc->name, num_sge, numSGE));
4100
4101 if ( numSGE > MPT_SCSI_SG_DEPTH )
4102 numSGE = MPT_SCSI_SG_DEPTH;
4103
4104 num_chain = 1;
4105 while (numSGE - num_sge > 0) {
4106 num_chain++;
4107 num_sge += (scale - 1);
4108 }
4109 num_chain++;
4110
Prakash, Sathya436ace72007-07-24 15:42:08 +05304111 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 ioc->name, numSGE, num_sge, num_chain));
4113
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004114 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 num_chain *= MPT_SCSI_CAN_QUEUE;
4116 else
4117 num_chain *= MPT_FC_CAN_QUEUE;
4118
4119 ioc->num_chain = num_chain;
4120
4121 sz = num_chain * sizeof(int);
4122 if (ioc->ChainToChain == NULL) {
4123 mem = kmalloc(sz, GFP_ATOMIC);
4124 if (mem == NULL)
4125 return -1;
4126
4127 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304128 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 ioc->name, mem, sz));
4130 } else {
4131 mem = (u8 *) ioc->ChainToChain;
4132 }
4133 memset(mem, 0xFF, sz);
4134 return num_chain;
4135}
4136
4137/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004138/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4140 * @ioc: Pointer to MPT_ADAPTER structure
4141 *
4142 * This routine allocates memory for the MPT reply and request frame
4143 * pools (if necessary), and primes the IOC reply FIFO with
4144 * reply frames.
4145 *
4146 * Returns 0 for success, non-zero for failure.
4147 */
4148static int
4149PrimeIocFifos(MPT_ADAPTER *ioc)
4150{
4151 MPT_FRAME_HDR *mf;
4152 unsigned long flags;
4153 dma_addr_t alloc_dma;
4154 u8 *mem;
4155 int i, reply_sz, sz, total_size, num_chain;
4156
4157 /* Prime reply FIFO... */
4158
4159 if (ioc->reply_frames == NULL) {
4160 if ( (num_chain = initChainBuffers(ioc)) < 0)
4161 return -1;
4162
4163 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304164 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304166 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 ioc->name, reply_sz, reply_sz));
4168
4169 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304170 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304172 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 ioc->name, sz, sz));
4174 total_size += sz;
4175
4176 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304177 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304179 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 ioc->name, sz, sz, num_chain));
4181
4182 total_size += sz;
4183 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4184 if (mem == NULL) {
4185 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4186 ioc->name);
4187 goto out_fail;
4188 }
4189
Prakash, Sathya436ace72007-07-24 15:42:08 +05304190 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4192
4193 memset(mem, 0, total_size);
4194 ioc->alloc_total += total_size;
4195 ioc->alloc = mem;
4196 ioc->alloc_dma = alloc_dma;
4197 ioc->alloc_sz = total_size;
4198 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4199 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4200
Prakash, Sathya436ace72007-07-24 15:42:08 +05304201 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004202 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4203
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 alloc_dma += reply_sz;
4205 mem += reply_sz;
4206
4207 /* Request FIFO - WE manage this! */
4208
4209 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4210 ioc->req_frames_dma = alloc_dma;
4211
Prakash, Sathya436ace72007-07-24 15:42:08 +05304212 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 ioc->name, mem, (void *)(ulong)alloc_dma));
4214
4215 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4216
4217#if defined(CONFIG_MTRR) && 0
4218 /*
4219 * Enable Write Combining MTRR for IOC's memory region.
4220 * (at least as much as we can; "size and base must be
4221 * multiples of 4 kiB"
4222 */
4223 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4224 sz,
4225 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304226 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 ioc->name, ioc->req_frames_dma, sz));
4228#endif
4229
4230 for (i = 0; i < ioc->req_depth; i++) {
4231 alloc_dma += ioc->req_sz;
4232 mem += ioc->req_sz;
4233 }
4234
4235 ioc->ChainBuffer = mem;
4236 ioc->ChainBufferDMA = alloc_dma;
4237
Prakash, Sathya436ace72007-07-24 15:42:08 +05304238 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4240
4241 /* Initialize the free chain Q.
4242 */
4243
4244 INIT_LIST_HEAD(&ioc->FreeChainQ);
4245
4246 /* Post the chain buffers to the FreeChainQ.
4247 */
4248 mem = (u8 *)ioc->ChainBuffer;
4249 for (i=0; i < num_chain; i++) {
4250 mf = (MPT_FRAME_HDR *) mem;
4251 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4252 mem += ioc->req_sz;
4253 }
4254
4255 /* Initialize Request frames linked list
4256 */
4257 alloc_dma = ioc->req_frames_dma;
4258 mem = (u8 *) ioc->req_frames;
4259
4260 spin_lock_irqsave(&ioc->FreeQlock, flags);
4261 INIT_LIST_HEAD(&ioc->FreeQ);
4262 for (i = 0; i < ioc->req_depth; i++) {
4263 mf = (MPT_FRAME_HDR *) mem;
4264
4265 /* Queue REQUESTs *internally*! */
4266 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4267
4268 mem += ioc->req_sz;
4269 }
4270 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4271
4272 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4273 ioc->sense_buf_pool =
4274 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4275 if (ioc->sense_buf_pool == NULL) {
4276 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4277 ioc->name);
4278 goto out_fail;
4279 }
4280
4281 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4282 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304283 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4285
4286 }
4287
4288 /* Post Reply frames to FIFO
4289 */
4290 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304291 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4293
4294 for (i = 0; i < ioc->reply_depth; i++) {
4295 /* Write each address to the IOC! */
4296 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4297 alloc_dma += ioc->reply_sz;
4298 }
4299
4300 return 0;
4301
4302out_fail:
4303 if (ioc->alloc != NULL) {
4304 sz = ioc->alloc_sz;
4305 pci_free_consistent(ioc->pcidev,
4306 sz,
4307 ioc->alloc, ioc->alloc_dma);
4308 ioc->reply_frames = NULL;
4309 ioc->req_frames = NULL;
4310 ioc->alloc_total -= sz;
4311 }
4312 if (ioc->sense_buf_pool != NULL) {
4313 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4314 pci_free_consistent(ioc->pcidev,
4315 sz,
4316 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4317 ioc->sense_buf_pool = NULL;
4318 }
4319 return -1;
4320}
4321
4322/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4323/**
4324 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4325 * from IOC via doorbell handshake method.
4326 * @ioc: Pointer to MPT_ADAPTER structure
4327 * @reqBytes: Size of the request in bytes
4328 * @req: Pointer to MPT request frame
4329 * @replyBytes: Expected size of the reply in bytes
4330 * @u16reply: Pointer to area where reply should be written
4331 * @maxwait: Max wait time for a reply (in seconds)
4332 * @sleepFlag: Specifies whether the process can sleep
4333 *
4334 * NOTES: It is the callers responsibility to byte-swap fields in the
4335 * request which are greater than 1 byte in size. It is also the
4336 * callers responsibility to byte-swap response fields which are
4337 * greater than 1 byte in size.
4338 *
4339 * Returns 0 for success, non-zero for failure.
4340 */
4341static int
4342mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004343 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344{
4345 MPIDefaultReply_t *mptReply;
4346 int failcnt = 0;
4347 int t;
4348
4349 /*
4350 * Get ready to cache a handshake reply
4351 */
4352 ioc->hs_reply_idx = 0;
4353 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4354 mptReply->MsgLength = 0;
4355
4356 /*
4357 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4358 * then tell IOC that we want to handshake a request of N words.
4359 * (WRITE u32val to Doorbell reg).
4360 */
4361 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4362 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4363 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4364 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4365
4366 /*
4367 * Wait for IOC's doorbell handshake int
4368 */
4369 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4370 failcnt++;
4371
Prakash, Sathya436ace72007-07-24 15:42:08 +05304372 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4374
4375 /* Read doorbell and check for active bit */
4376 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4377 return -1;
4378
4379 /*
4380 * Clear doorbell int (WRITE 0 to IntStatus reg),
4381 * then wait for IOC to ACKnowledge that it's ready for
4382 * our handshake request.
4383 */
4384 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4385 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4386 failcnt++;
4387
4388 if (!failcnt) {
4389 int ii;
4390 u8 *req_as_bytes = (u8 *) req;
4391
4392 /*
4393 * Stuff request words via doorbell handshake,
4394 * with ACK from IOC for each.
4395 */
4396 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4397 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4398 (req_as_bytes[(ii*4) + 1] << 8) |
4399 (req_as_bytes[(ii*4) + 2] << 16) |
4400 (req_as_bytes[(ii*4) + 3] << 24));
4401
4402 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4403 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4404 failcnt++;
4405 }
4406
Prakash, Sathya436ace72007-07-24 15:42:08 +05304407 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004408 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409
Prakash, Sathya436ace72007-07-24 15:42:08 +05304410 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4412
4413 /*
4414 * Wait for completion of doorbell handshake reply from the IOC
4415 */
4416 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4417 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004418
Prakash, Sathya436ace72007-07-24 15:42:08 +05304419 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4421
4422 /*
4423 * Copy out the cached reply...
4424 */
4425 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4426 u16reply[ii] = ioc->hs_reply[ii];
4427 } else {
4428 return -99;
4429 }
4430
4431 return -failcnt;
4432}
4433
4434/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004435/**
4436 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 * @ioc: Pointer to MPT_ADAPTER structure
4438 * @howlong: How long to wait (in seconds)
4439 * @sleepFlag: Specifies whether the process can sleep
4440 *
4441 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004442 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4443 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 *
4445 * Returns a negative value on failure, else wait loop count.
4446 */
4447static int
4448WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4449{
4450 int cntdn;
4451 int count = 0;
4452 u32 intstat=0;
4453
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004454 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455
4456 if (sleepFlag == CAN_SLEEP) {
4457 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004458 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4460 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4461 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 count++;
4463 }
4464 } else {
4465 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004466 udelay (1000);
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 }
4473
4474 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304475 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 ioc->name, count));
4477 return count;
4478 }
4479
4480 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4481 ioc->name, count, intstat);
4482 return -1;
4483}
4484
4485/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004486/**
4487 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 * @ioc: Pointer to MPT_ADAPTER structure
4489 * @howlong: How long to wait (in seconds)
4490 * @sleepFlag: Specifies whether the process can sleep
4491 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004492 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4493 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 *
4495 * Returns a negative value on failure, else wait loop count.
4496 */
4497static int
4498WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4499{
4500 int cntdn;
4501 int count = 0;
4502 u32 intstat=0;
4503
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004504 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 if (sleepFlag == CAN_SLEEP) {
4506 while (--cntdn) {
4507 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4508 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4509 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004510 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 count++;
4512 }
4513 } else {
4514 while (--cntdn) {
4515 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4516 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4517 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004518 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 count++;
4520 }
4521 }
4522
4523 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304524 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 ioc->name, count, howlong));
4526 return count;
4527 }
4528
4529 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4530 ioc->name, count, intstat);
4531 return -1;
4532}
4533
4534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004535/**
4536 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 * @ioc: Pointer to MPT_ADAPTER structure
4538 * @howlong: How long to wait (in seconds)
4539 * @sleepFlag: Specifies whether the process can sleep
4540 *
4541 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4542 * Reply is cached to IOC private area large enough to hold a maximum
4543 * of 128 bytes of reply data.
4544 *
4545 * Returns a negative value on failure, else size of reply in WORDS.
4546 */
4547static int
4548WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4549{
4550 int u16cnt = 0;
4551 int failcnt = 0;
4552 int t;
4553 u16 *hs_reply = ioc->hs_reply;
4554 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4555 u16 hword;
4556
4557 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4558
4559 /*
4560 * Get first two u16's so we can look at IOC's intended reply MsgLength
4561 */
4562 u16cnt=0;
4563 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4564 failcnt++;
4565 } else {
4566 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4567 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4568 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4569 failcnt++;
4570 else {
4571 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4572 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4573 }
4574 }
4575
Prakash, Sathya436ace72007-07-24 15:42:08 +05304576 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004577 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4579
4580 /*
4581 * If no error (and IOC said MsgLength is > 0), piece together
4582 * reply 16 bits at a time.
4583 */
4584 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4585 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4586 failcnt++;
4587 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4588 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004589 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 hs_reply[u16cnt] = hword;
4591 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4592 }
4593
4594 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4595 failcnt++;
4596 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4597
4598 if (failcnt) {
4599 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4600 ioc->name);
4601 return -failcnt;
4602 }
4603#if 0
4604 else if (u16cnt != (2 * mptReply->MsgLength)) {
4605 return -101;
4606 }
4607 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4608 return -102;
4609 }
4610#endif
4611
Prakash, Sathya436ace72007-07-24 15:42:08 +05304612 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004613 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614
Prakash, Sathya436ace72007-07-24 15:42:08 +05304615 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 ioc->name, t, u16cnt/2));
4617 return u16cnt/2;
4618}
4619
4620/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004621/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 * GetLanConfigPages - Fetch LANConfig pages.
4623 * @ioc: Pointer to MPT_ADAPTER structure
4624 *
4625 * Return: 0 for success
4626 * -ENOMEM if no memory available
4627 * -EPERM if not allowed due to ISR context
4628 * -EAGAIN if no msg frames currently available
4629 * -EFAULT for non-successful reply or no reply (timeout)
4630 */
4631static int
4632GetLanConfigPages(MPT_ADAPTER *ioc)
4633{
4634 ConfigPageHeader_t hdr;
4635 CONFIGPARMS cfg;
4636 LANPage0_t *ppage0_alloc;
4637 dma_addr_t page0_dma;
4638 LANPage1_t *ppage1_alloc;
4639 dma_addr_t page1_dma;
4640 int rc = 0;
4641 int data_sz;
4642 int copy_sz;
4643
4644 /* Get LAN Page 0 header */
4645 hdr.PageVersion = 0;
4646 hdr.PageLength = 0;
4647 hdr.PageNumber = 0;
4648 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004649 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 cfg.physAddr = -1;
4651 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4652 cfg.dir = 0;
4653 cfg.pageAddr = 0;
4654 cfg.timeout = 0;
4655
4656 if ((rc = mpt_config(ioc, &cfg)) != 0)
4657 return rc;
4658
4659 if (hdr.PageLength > 0) {
4660 data_sz = hdr.PageLength * 4;
4661 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4662 rc = -ENOMEM;
4663 if (ppage0_alloc) {
4664 memset((u8 *)ppage0_alloc, 0, data_sz);
4665 cfg.physAddr = page0_dma;
4666 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4667
4668 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4669 /* save the data */
4670 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4671 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4672
4673 }
4674
4675 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4676
4677 /* FIXME!
4678 * Normalize endianness of structure data,
4679 * by byte-swapping all > 1 byte fields!
4680 */
4681
4682 }
4683
4684 if (rc)
4685 return rc;
4686 }
4687
4688 /* Get LAN Page 1 header */
4689 hdr.PageVersion = 0;
4690 hdr.PageLength = 0;
4691 hdr.PageNumber = 1;
4692 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004693 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 cfg.physAddr = -1;
4695 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4696 cfg.dir = 0;
4697 cfg.pageAddr = 0;
4698
4699 if ((rc = mpt_config(ioc, &cfg)) != 0)
4700 return rc;
4701
4702 if (hdr.PageLength == 0)
4703 return 0;
4704
4705 data_sz = hdr.PageLength * 4;
4706 rc = -ENOMEM;
4707 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4708 if (ppage1_alloc) {
4709 memset((u8 *)ppage1_alloc, 0, data_sz);
4710 cfg.physAddr = page1_dma;
4711 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4712
4713 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4714 /* save the data */
4715 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4716 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4717 }
4718
4719 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4720
4721 /* FIXME!
4722 * Normalize endianness of structure data,
4723 * by byte-swapping all > 1 byte fields!
4724 */
4725
4726 }
4727
4728 return rc;
4729}
4730
4731/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004732/**
4733 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004734 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004735 * @persist_opcode: see below
4736 *
4737 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4738 * devices not currently present.
4739 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4740 *
4741 * NOTE: Don't use not this function during interrupt time.
4742 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004743 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004744 */
4745
4746/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4747int
4748mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4749{
4750 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4751 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4752 MPT_FRAME_HDR *mf = NULL;
4753 MPIHeader_t *mpi_hdr;
4754
4755
4756 /* insure garbage is not sent to fw */
4757 switch(persist_opcode) {
4758
4759 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4760 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4761 break;
4762
4763 default:
4764 return -1;
4765 break;
4766 }
4767
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004768 printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004769
4770 /* Get a MF for this command.
4771 */
4772 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004773 printk("%s: no msg frames!\n",__func__);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004774 return -1;
4775 }
4776
4777 mpi_hdr = (MPIHeader_t *) mf;
4778 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4779 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4780 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4781 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4782 sasIoUnitCntrReq->Operation = persist_opcode;
4783
4784 init_timer(&ioc->persist_timer);
4785 ioc->persist_timer.data = (unsigned long) ioc;
4786 ioc->persist_timer.function = mpt_timer_expired;
4787 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4788 ioc->persist_wait_done=0;
4789 add_timer(&ioc->persist_timer);
4790 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4791 wait_event(mpt_waitq, ioc->persist_wait_done);
4792
4793 sasIoUnitCntrReply =
4794 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4795 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4796 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004797 __func__,
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004798 sasIoUnitCntrReply->IOCStatus,
4799 sasIoUnitCntrReply->IOCLogInfo);
4800 return -1;
4801 }
4802
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004803 printk("%s: success\n",__func__);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004804 return 0;
4805}
4806
4807/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004808
4809static void
4810mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4811 MpiEventDataRaid_t * pRaidEventData)
4812{
4813 int volume;
4814 int reason;
4815 int disk;
4816 int status;
4817 int flags;
4818 int state;
4819
4820 volume = pRaidEventData->VolumeID;
4821 reason = pRaidEventData->ReasonCode;
4822 disk = pRaidEventData->PhysDiskNum;
4823 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4824 flags = (status >> 0) & 0xff;
4825 state = (status >> 8) & 0xff;
4826
4827 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4828 return;
4829 }
4830
4831 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4832 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4833 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004834 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4835 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004836 } else {
4837 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4838 ioc->name, volume);
4839 }
4840
4841 switch(reason) {
4842 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4843 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4844 ioc->name);
4845 break;
4846
4847 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4848
4849 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4850 ioc->name);
4851 break;
4852
4853 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4854 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4855 ioc->name);
4856 break;
4857
4858 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4859 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4860 ioc->name,
4861 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4862 ? "optimal"
4863 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4864 ? "degraded"
4865 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4866 ? "failed"
4867 : "state unknown",
4868 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4869 ? ", enabled" : "",
4870 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4871 ? ", quiesced" : "",
4872 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4873 ? ", resync in progress" : "" );
4874 break;
4875
4876 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4877 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4878 ioc->name, disk);
4879 break;
4880
4881 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4882 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4883 ioc->name);
4884 break;
4885
4886 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4887 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4888 ioc->name);
4889 break;
4890
4891 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4892 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4893 ioc->name);
4894 break;
4895
4896 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4897 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4898 ioc->name,
4899 state == MPI_PHYSDISK0_STATUS_ONLINE
4900 ? "online"
4901 : state == MPI_PHYSDISK0_STATUS_MISSING
4902 ? "missing"
4903 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4904 ? "not compatible"
4905 : state == MPI_PHYSDISK0_STATUS_FAILED
4906 ? "failed"
4907 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4908 ? "initializing"
4909 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4910 ? "offline requested"
4911 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4912 ? "failed requested"
4913 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4914 ? "offline"
4915 : "state unknown",
4916 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4917 ? ", out of sync" : "",
4918 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4919 ? ", quiesced" : "" );
4920 break;
4921
4922 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4923 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4924 ioc->name, disk);
4925 break;
4926
4927 case MPI_EVENT_RAID_RC_SMART_DATA:
4928 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4929 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4930 break;
4931
4932 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4933 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4934 ioc->name, disk);
4935 break;
4936 }
4937}
4938
4939/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004940/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4942 * @ioc: Pointer to MPT_ADAPTER structure
4943 *
4944 * Returns: 0 for success
4945 * -ENOMEM if no memory available
4946 * -EPERM if not allowed due to ISR context
4947 * -EAGAIN if no msg frames currently available
4948 * -EFAULT for non-successful reply or no reply (timeout)
4949 */
4950static int
4951GetIoUnitPage2(MPT_ADAPTER *ioc)
4952{
4953 ConfigPageHeader_t hdr;
4954 CONFIGPARMS cfg;
4955 IOUnitPage2_t *ppage_alloc;
4956 dma_addr_t page_dma;
4957 int data_sz;
4958 int rc;
4959
4960 /* Get the page header */
4961 hdr.PageVersion = 0;
4962 hdr.PageLength = 0;
4963 hdr.PageNumber = 2;
4964 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004965 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966 cfg.physAddr = -1;
4967 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4968 cfg.dir = 0;
4969 cfg.pageAddr = 0;
4970 cfg.timeout = 0;
4971
4972 if ((rc = mpt_config(ioc, &cfg)) != 0)
4973 return rc;
4974
4975 if (hdr.PageLength == 0)
4976 return 0;
4977
4978 /* Read the config page */
4979 data_sz = hdr.PageLength * 4;
4980 rc = -ENOMEM;
4981 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4982 if (ppage_alloc) {
4983 memset((u8 *)ppage_alloc, 0, data_sz);
4984 cfg.physAddr = page_dma;
4985 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4986
4987 /* If Good, save data */
4988 if ((rc = mpt_config(ioc, &cfg)) == 0)
4989 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4990
4991 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4992 }
4993
4994 return rc;
4995}
4996
4997/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004998/**
4999 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 * @ioc: Pointer to a Adapter Strucutre
5001 * @portnum: IOC port number
5002 *
5003 * Return: -EFAULT if read of config page header fails
5004 * or if no nvram
5005 * If read of SCSI Port Page 0 fails,
5006 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5007 * Adapter settings: async, narrow
5008 * Return 1
5009 * If read of SCSI Port Page 2 fails,
5010 * Adapter settings valid
5011 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5012 * Return 1
5013 * Else
5014 * Both valid
5015 * Return 0
5016 * CHECK - what type of locking mechanisms should be used????
5017 */
5018static int
5019mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5020{
5021 u8 *pbuf;
5022 dma_addr_t buf_dma;
5023 CONFIGPARMS cfg;
5024 ConfigPageHeader_t header;
5025 int ii;
5026 int data, rc = 0;
5027
5028 /* Allocate memory
5029 */
5030 if (!ioc->spi_data.nvram) {
5031 int sz;
5032 u8 *mem;
5033 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5034 mem = kmalloc(sz, GFP_ATOMIC);
5035 if (mem == NULL)
5036 return -EFAULT;
5037
5038 ioc->spi_data.nvram = (int *) mem;
5039
Prakash, Sathya436ace72007-07-24 15:42:08 +05305040 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 ioc->name, ioc->spi_data.nvram, sz));
5042 }
5043
5044 /* Invalidate NVRAM information
5045 */
5046 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5047 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5048 }
5049
5050 /* Read SPP0 header, allocate memory, then read page.
5051 */
5052 header.PageVersion = 0;
5053 header.PageLength = 0;
5054 header.PageNumber = 0;
5055 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005056 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 cfg.physAddr = -1;
5058 cfg.pageAddr = portnum;
5059 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5060 cfg.dir = 0;
5061 cfg.timeout = 0; /* use default */
5062 if (mpt_config(ioc, &cfg) != 0)
5063 return -EFAULT;
5064
5065 if (header.PageLength > 0) {
5066 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5067 if (pbuf) {
5068 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5069 cfg.physAddr = buf_dma;
5070 if (mpt_config(ioc, &cfg) != 0) {
5071 ioc->spi_data.maxBusWidth = MPT_NARROW;
5072 ioc->spi_data.maxSyncOffset = 0;
5073 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5074 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5075 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305076 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5077 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005078 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 } else {
5080 /* Save the Port Page 0 data
5081 */
5082 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5083 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5084 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5085
5086 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5087 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005088 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5089 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 ioc->name, pPP0->Capabilities));
5091 }
5092 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5093 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5094 if (data) {
5095 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5096 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5097 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305098 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5099 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005100 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 } else {
5102 ioc->spi_data.maxSyncOffset = 0;
5103 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5104 }
5105
5106 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5107
5108 /* Update the minSyncFactor based on bus type.
5109 */
5110 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5111 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5112
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005113 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305115 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5116 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005117 ioc->name, ioc->spi_data.minSyncFactor));
5118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 }
5120 }
5121 if (pbuf) {
5122 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5123 }
5124 }
5125 }
5126
5127 /* SCSI Port Page 2 - Read the header then the page.
5128 */
5129 header.PageVersion = 0;
5130 header.PageLength = 0;
5131 header.PageNumber = 2;
5132 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005133 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134 cfg.physAddr = -1;
5135 cfg.pageAddr = portnum;
5136 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5137 cfg.dir = 0;
5138 if (mpt_config(ioc, &cfg) != 0)
5139 return -EFAULT;
5140
5141 if (header.PageLength > 0) {
5142 /* Allocate memory and read SCSI Port Page 2
5143 */
5144 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5145 if (pbuf) {
5146 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5147 cfg.physAddr = buf_dma;
5148 if (mpt_config(ioc, &cfg) != 0) {
5149 /* Nvram data is left with INVALID mark
5150 */
5151 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005152 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5153
5154 /* This is an ATTO adapter, read Page2 accordingly
5155 */
5156 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5157 ATTODeviceInfo_t *pdevice = NULL;
5158 u16 ATTOFlags;
5159
5160 /* Save the Port Page 2 data
5161 * (reformat into a 32bit quantity)
5162 */
5163 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5164 pdevice = &pPP2->DeviceSettings[ii];
5165 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5166 data = 0;
5167
5168 /* Translate ATTO device flags to LSI format
5169 */
5170 if (ATTOFlags & ATTOFLAG_DISC)
5171 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5172 if (ATTOFlags & ATTOFLAG_ID_ENB)
5173 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5174 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5175 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5176 if (ATTOFlags & ATTOFLAG_TAGGED)
5177 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5178 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5179 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5180
5181 data = (data << 16) | (pdevice->Period << 8) | 10;
5182 ioc->spi_data.nvram[ii] = data;
5183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 } else {
5185 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5186 MpiDeviceInfo_t *pdevice = NULL;
5187
Moore, Ericd8e925d2006-01-16 18:53:06 -07005188 /*
5189 * Save "Set to Avoid SCSI Bus Resets" flag
5190 */
5191 ioc->spi_data.bus_reset =
5192 (le32_to_cpu(pPP2->PortFlags) &
5193 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5194 0 : 1 ;
5195
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 /* Save the Port Page 2 data
5197 * (reformat into a 32bit quantity)
5198 */
5199 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5200 ioc->spi_data.PortFlags = data;
5201 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5202 pdevice = &pPP2->DeviceSettings[ii];
5203 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5204 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5205 ioc->spi_data.nvram[ii] = data;
5206 }
5207 }
5208
5209 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5210 }
5211 }
5212
5213 /* Update Adapter limits with those from NVRAM
5214 * Comment: Don't need to do this. Target performance
5215 * parameters will never exceed the adapters limits.
5216 */
5217
5218 return rc;
5219}
5220
5221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005222/**
5223 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 * @ioc: Pointer to a Adapter Strucutre
5225 * @portnum: IOC port number
5226 *
5227 * Return: -EFAULT if read of config page header fails
5228 * or 0 if success.
5229 */
5230static int
5231mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5232{
5233 CONFIGPARMS cfg;
5234 ConfigPageHeader_t header;
5235
5236 /* Read the SCSI Device Page 1 header
5237 */
5238 header.PageVersion = 0;
5239 header.PageLength = 0;
5240 header.PageNumber = 1;
5241 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005242 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 cfg.physAddr = -1;
5244 cfg.pageAddr = portnum;
5245 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5246 cfg.dir = 0;
5247 cfg.timeout = 0;
5248 if (mpt_config(ioc, &cfg) != 0)
5249 return -EFAULT;
5250
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005251 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5252 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253
5254 header.PageVersion = 0;
5255 header.PageLength = 0;
5256 header.PageNumber = 0;
5257 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5258 if (mpt_config(ioc, &cfg) != 0)
5259 return -EFAULT;
5260
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005261 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5262 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263
Prakash, Sathya436ace72007-07-24 15:42:08 +05305264 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5266
Prakash, Sathya436ace72007-07-24 15:42:08 +05305267 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5269 return 0;
5270}
5271
Eric Mooreb506ade2007-01-29 09:45:37 -07005272/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005273 * mpt_inactive_raid_list_free - This clears this link list.
5274 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005275 **/
5276static void
5277mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5278{
5279 struct inactive_raid_component_info *component_info, *pNext;
5280
5281 if (list_empty(&ioc->raid_data.inactive_list))
5282 return;
5283
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005284 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005285 list_for_each_entry_safe(component_info, pNext,
5286 &ioc->raid_data.inactive_list, list) {
5287 list_del(&component_info->list);
5288 kfree(component_info);
5289 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005290 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005291}
5292
5293/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005294 * 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 -07005295 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005296 * @ioc : pointer to per adapter structure
5297 * @channel : volume channel
5298 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005299 **/
5300static void
5301mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5302{
5303 CONFIGPARMS cfg;
5304 ConfigPageHeader_t hdr;
5305 dma_addr_t dma_handle;
5306 pRaidVolumePage0_t buffer = NULL;
5307 int i;
5308 RaidPhysDiskPage0_t phys_disk;
5309 struct inactive_raid_component_info *component_info;
5310 int handle_inactive_volumes;
5311
5312 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5313 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5314 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5315 cfg.pageAddr = (channel << 8) + id;
5316 cfg.cfghdr.hdr = &hdr;
5317 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5318
5319 if (mpt_config(ioc, &cfg) != 0)
5320 goto out;
5321
5322 if (!hdr.PageLength)
5323 goto out;
5324
5325 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5326 &dma_handle);
5327
5328 if (!buffer)
5329 goto out;
5330
5331 cfg.physAddr = dma_handle;
5332 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5333
5334 if (mpt_config(ioc, &cfg) != 0)
5335 goto out;
5336
5337 if (!buffer->NumPhysDisks)
5338 goto out;
5339
5340 handle_inactive_volumes =
5341 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5342 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5343 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5344 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5345
5346 if (!handle_inactive_volumes)
5347 goto out;
5348
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005349 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005350 for (i = 0; i < buffer->NumPhysDisks; i++) {
5351 if(mpt_raid_phys_disk_pg0(ioc,
5352 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5353 continue;
5354
5355 if ((component_info = kmalloc(sizeof (*component_info),
5356 GFP_KERNEL)) == NULL)
5357 continue;
5358
5359 component_info->volumeID = id;
5360 component_info->volumeBus = channel;
5361 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5362 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5363 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5364 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5365
5366 list_add_tail(&component_info->list,
5367 &ioc->raid_data.inactive_list);
5368 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005369 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005370
5371 out:
5372 if (buffer)
5373 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5374 dma_handle);
5375}
5376
5377/**
5378 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5379 * @ioc: Pointer to a Adapter Structure
5380 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5381 * @phys_disk: requested payload data returned
5382 *
5383 * Return:
5384 * 0 on success
5385 * -EFAULT if read of config page header fails or data pointer not NULL
5386 * -ENOMEM if pci_alloc failed
5387 **/
5388int
5389mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5390{
5391 CONFIGPARMS cfg;
5392 ConfigPageHeader_t hdr;
5393 dma_addr_t dma_handle;
5394 pRaidPhysDiskPage0_t buffer = NULL;
5395 int rc;
5396
5397 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5398 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5399
5400 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5401 cfg.cfghdr.hdr = &hdr;
5402 cfg.physAddr = -1;
5403 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5404
5405 if (mpt_config(ioc, &cfg) != 0) {
5406 rc = -EFAULT;
5407 goto out;
5408 }
5409
5410 if (!hdr.PageLength) {
5411 rc = -EFAULT;
5412 goto out;
5413 }
5414
5415 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5416 &dma_handle);
5417
5418 if (!buffer) {
5419 rc = -ENOMEM;
5420 goto out;
5421 }
5422
5423 cfg.physAddr = dma_handle;
5424 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5425 cfg.pageAddr = phys_disk_num;
5426
5427 if (mpt_config(ioc, &cfg) != 0) {
5428 rc = -EFAULT;
5429 goto out;
5430 }
5431
5432 rc = 0;
5433 memcpy(phys_disk, buffer, sizeof(*buffer));
5434 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5435
5436 out:
5437
5438 if (buffer)
5439 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5440 dma_handle);
5441
5442 return rc;
5443}
5444
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445/**
5446 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5447 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 *
5449 * Return:
5450 * 0 on success
5451 * -EFAULT if read of config page header fails or data pointer not NULL
5452 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005453 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454int
5455mpt_findImVolumes(MPT_ADAPTER *ioc)
5456{
5457 IOCPage2_t *pIoc2;
5458 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 dma_addr_t ioc2_dma;
5460 CONFIGPARMS cfg;
5461 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 int rc = 0;
5463 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005464 int i;
5465
5466 if (!ioc->ir_firmware)
5467 return 0;
5468
5469 /* Free the old page
5470 */
5471 kfree(ioc->raid_data.pIocPg2);
5472 ioc->raid_data.pIocPg2 = NULL;
5473 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474
5475 /* Read IOCP2 header then the page.
5476 */
5477 header.PageVersion = 0;
5478 header.PageLength = 0;
5479 header.PageNumber = 2;
5480 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005481 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 cfg.physAddr = -1;
5483 cfg.pageAddr = 0;
5484 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5485 cfg.dir = 0;
5486 cfg.timeout = 0;
5487 if (mpt_config(ioc, &cfg) != 0)
5488 return -EFAULT;
5489
5490 if (header.PageLength == 0)
5491 return -EFAULT;
5492
5493 iocpage2sz = header.PageLength * 4;
5494 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5495 if (!pIoc2)
5496 return -ENOMEM;
5497
5498 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5499 cfg.physAddr = ioc2_dma;
5500 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005501 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502
Eric Mooreb506ade2007-01-29 09:45:37 -07005503 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5504 if (!mem)
5505 goto out;
5506
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005508 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509
Eric Mooreb506ade2007-01-29 09:45:37 -07005510 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511
Eric Mooreb506ade2007-01-29 09:45:37 -07005512 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5513 mpt_inactive_raid_volumes(ioc,
5514 pIoc2->RaidVolume[i].VolumeBus,
5515 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516
Eric Mooreb506ade2007-01-29 09:45:37 -07005517 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5519
5520 return rc;
5521}
5522
Moore, Ericc972c702006-03-14 09:14:06 -07005523static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5525{
5526 IOCPage3_t *pIoc3;
5527 u8 *mem;
5528 CONFIGPARMS cfg;
5529 ConfigPageHeader_t header;
5530 dma_addr_t ioc3_dma;
5531 int iocpage3sz = 0;
5532
5533 /* Free the old page
5534 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005535 kfree(ioc->raid_data.pIocPg3);
5536 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537
5538 /* There is at least one physical disk.
5539 * Read and save IOC Page 3
5540 */
5541 header.PageVersion = 0;
5542 header.PageLength = 0;
5543 header.PageNumber = 3;
5544 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005545 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 cfg.physAddr = -1;
5547 cfg.pageAddr = 0;
5548 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5549 cfg.dir = 0;
5550 cfg.timeout = 0;
5551 if (mpt_config(ioc, &cfg) != 0)
5552 return 0;
5553
5554 if (header.PageLength == 0)
5555 return 0;
5556
5557 /* Read Header good, alloc memory
5558 */
5559 iocpage3sz = header.PageLength * 4;
5560 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5561 if (!pIoc3)
5562 return 0;
5563
5564 /* Read the Page and save the data
5565 * into malloc'd memory.
5566 */
5567 cfg.physAddr = ioc3_dma;
5568 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5569 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005570 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 if (mem) {
5572 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005573 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 }
5575 }
5576
5577 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5578
5579 return 0;
5580}
5581
5582static void
5583mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5584{
5585 IOCPage4_t *pIoc4;
5586 CONFIGPARMS cfg;
5587 ConfigPageHeader_t header;
5588 dma_addr_t ioc4_dma;
5589 int iocpage4sz;
5590
5591 /* Read and save IOC Page 4
5592 */
5593 header.PageVersion = 0;
5594 header.PageLength = 0;
5595 header.PageNumber = 4;
5596 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005597 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 cfg.physAddr = -1;
5599 cfg.pageAddr = 0;
5600 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5601 cfg.dir = 0;
5602 cfg.timeout = 0;
5603 if (mpt_config(ioc, &cfg) != 0)
5604 return;
5605
5606 if (header.PageLength == 0)
5607 return;
5608
5609 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5610 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5611 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5612 if (!pIoc4)
5613 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005614 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 } else {
5616 ioc4_dma = ioc->spi_data.IocPg4_dma;
5617 iocpage4sz = ioc->spi_data.IocPg4Sz;
5618 }
5619
5620 /* Read the Page into dma memory.
5621 */
5622 cfg.physAddr = ioc4_dma;
5623 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5624 if (mpt_config(ioc, &cfg) == 0) {
5625 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5626 ioc->spi_data.IocPg4_dma = ioc4_dma;
5627 ioc->spi_data.IocPg4Sz = iocpage4sz;
5628 } else {
5629 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5630 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005631 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 }
5633}
5634
5635static void
5636mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5637{
5638 IOCPage1_t *pIoc1;
5639 CONFIGPARMS cfg;
5640 ConfigPageHeader_t header;
5641 dma_addr_t ioc1_dma;
5642 int iocpage1sz = 0;
5643 u32 tmp;
5644
5645 /* Check the Coalescing Timeout in IOC Page 1
5646 */
5647 header.PageVersion = 0;
5648 header.PageLength = 0;
5649 header.PageNumber = 1;
5650 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005651 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 cfg.physAddr = -1;
5653 cfg.pageAddr = 0;
5654 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5655 cfg.dir = 0;
5656 cfg.timeout = 0;
5657 if (mpt_config(ioc, &cfg) != 0)
5658 return;
5659
5660 if (header.PageLength == 0)
5661 return;
5662
5663 /* Read Header good, alloc memory
5664 */
5665 iocpage1sz = header.PageLength * 4;
5666 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5667 if (!pIoc1)
5668 return;
5669
5670 /* Read the Page and check coalescing timeout
5671 */
5672 cfg.physAddr = ioc1_dma;
5673 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5674 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305675
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5677 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5678 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5679
Prakash, Sathya436ace72007-07-24 15:42:08 +05305680 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 ioc->name, tmp));
5682
5683 if (tmp > MPT_COALESCING_TIMEOUT) {
5684 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5685
5686 /* Write NVRAM and current
5687 */
5688 cfg.dir = 1;
5689 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5690 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305691 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 ioc->name, MPT_COALESCING_TIMEOUT));
5693
5694 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5695 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305696 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5697 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698 ioc->name, MPT_COALESCING_TIMEOUT));
5699 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305700 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5701 "Reset NVRAM Coalescing Timeout Failed\n",
5702 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 }
5704
5705 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305706 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5707 "Reset of Current Coalescing Timeout Failed!\n",
5708 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 }
5710 }
5711
5712 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305713 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 }
5715 }
5716
5717 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5718
5719 return;
5720}
5721
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305722static void
5723mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5724{
5725 CONFIGPARMS cfg;
5726 ConfigPageHeader_t hdr;
5727 dma_addr_t buf_dma;
5728 ManufacturingPage0_t *pbuf = NULL;
5729
5730 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5731 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5732
5733 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5734 cfg.cfghdr.hdr = &hdr;
5735 cfg.physAddr = -1;
5736 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5737 cfg.timeout = 10;
5738
5739 if (mpt_config(ioc, &cfg) != 0)
5740 goto out;
5741
5742 if (!cfg.cfghdr.hdr->PageLength)
5743 goto out;
5744
5745 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5746 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5747 if (!pbuf)
5748 goto out;
5749
5750 cfg.physAddr = buf_dma;
5751
5752 if (mpt_config(ioc, &cfg) != 0)
5753 goto out;
5754
5755 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5756 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5757 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5758
5759 out:
5760
5761 if (pbuf)
5762 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5763}
5764
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005766/**
5767 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 * @ioc: Pointer to MPT_ADAPTER structure
5769 * @EvSwitch: Event switch flags
5770 */
5771static int
5772SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5773{
5774 EventNotification_t *evnp;
5775
5776 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5777 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305778 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779 ioc->name));
5780 return 0;
5781 }
5782 memset(evnp, 0, sizeof(*evnp));
5783
Prakash, Sathya436ace72007-07-24 15:42:08 +05305784 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785
5786 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5787 evnp->ChainOffset = 0;
5788 evnp->MsgFlags = 0;
5789 evnp->Switch = EvSwitch;
5790
5791 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5792
5793 return 0;
5794}
5795
5796/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5797/**
5798 * SendEventAck - Send EventAck request to MPT adapter.
5799 * @ioc: Pointer to MPT_ADAPTER structure
5800 * @evnp: Pointer to original EventNotification request
5801 */
5802static int
5803SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5804{
5805 EventAck_t *pAck;
5806
5807 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305808 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005809 ioc->name,__func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810 return -1;
5811 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812
Prakash, Sathya436ace72007-07-24 15:42:08 +05305813 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814
5815 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5816 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005817 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005819 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820 pAck->Event = evnp->Event;
5821 pAck->EventContext = evnp->EventContext;
5822
5823 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5824
5825 return 0;
5826}
5827
5828/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5829/**
5830 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005831 * @ioc: Pointer to an adapter structure
5832 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833 * action, page address, direction, physical address
5834 * and pointer to a configuration page header
5835 * Page header is updated.
5836 *
5837 * Returns 0 for success
5838 * -EPERM if not allowed due to ISR context
5839 * -EAGAIN if no msg frames currently available
5840 * -EFAULT for non-successful reply or no reply (timeout)
5841 */
5842int
5843mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5844{
5845 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005846 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847 MPT_FRAME_HDR *mf;
5848 unsigned long flags;
5849 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005850 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 int in_isr;
5852
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005853 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 * to be in ISR context, because that is fatal!
5855 */
5856 in_isr = in_interrupt();
5857 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305858 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859 ioc->name));
5860 return -EPERM;
5861 }
5862
5863 /* Get and Populate a free Frame
5864 */
5865 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305866 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 ioc->name));
5868 return -EAGAIN;
5869 }
5870 pReq = (Config_t *)mf;
5871 pReq->Action = pCfg->action;
5872 pReq->Reserved = 0;
5873 pReq->ChainOffset = 0;
5874 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005875
5876 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 pReq->ExtPageLength = 0;
5878 pReq->ExtPageType = 0;
5879 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005880
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 for (ii=0; ii < 8; ii++)
5882 pReq->Reserved2[ii] = 0;
5883
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005884 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5885 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5886 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5887 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5888
5889 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5890 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5891 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5892 pReq->ExtPageType = pExtHdr->ExtPageType;
5893 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5894
5895 /* Page Length must be treated as a reserved field for the extended header. */
5896 pReq->Header.PageLength = 0;
5897 }
5898
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5900
5901 /* Add a SGE to the config request.
5902 */
5903 if (pCfg->dir)
5904 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5905 else
5906 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5907
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005908 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5909 flagsLength |= pExtHdr->ExtPageLength * 4;
5910
Prakash, Sathya436ace72007-07-24 15:42:08 +05305911 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 +02005912 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5913 }
5914 else {
5915 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5916
Prakash, Sathya436ace72007-07-24 15:42:08 +05305917 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 +02005918 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920
5921 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5922
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923 /* Append pCfg pointer to end of mf
5924 */
5925 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5926
5927 /* Initalize the timer
5928 */
5929 init_timer(&pCfg->timer);
5930 pCfg->timer.data = (unsigned long) ioc;
5931 pCfg->timer.function = mpt_timer_expired;
5932 pCfg->wait_done = 0;
5933
5934 /* Set the timer; ensure 10 second minimum */
5935 if (pCfg->timeout < 10)
5936 pCfg->timer.expires = jiffies + HZ*10;
5937 else
5938 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5939
5940 /* Add to end of Q, set timer and then issue this command */
5941 spin_lock_irqsave(&ioc->FreeQlock, flags);
5942 list_add_tail(&pCfg->linkage, &ioc->configQ);
5943 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5944
5945 add_timer(&pCfg->timer);
5946 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5947 wait_event(mpt_waitq, pCfg->wait_done);
5948
5949 /* mf has been freed - do not access */
5950
5951 rc = pCfg->status;
5952
5953 return rc;
5954}
5955
5956/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005957/**
5958 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 * Used only internal config functionality.
5960 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5961 */
5962static void
5963mpt_timer_expired(unsigned long data)
5964{
5965 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5966
Prakash, Sathya436ace72007-07-24 15:42:08 +05305967 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968
5969 /* Perform a FW reload */
5970 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5971 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5972
5973 /* No more processing.
5974 * Hard reset clean-up will wake up
5975 * process and free all resources.
5976 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305977 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978
5979 return;
5980}
5981
5982/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005983/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 * mpt_ioc_reset - Base cleanup for hard reset
5985 * @ioc: Pointer to the adapter structure
5986 * @reset_phase: Indicates pre- or post-reset functionality
5987 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005988 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 */
5990static int
5991mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5992{
5993 CONFIGPARMS *pCfg;
5994 unsigned long flags;
5995
Eric Moore29dd3602007-09-14 18:46:51 -06005996 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5997 ": IOC %s_reset routed to MPT base driver!\n",
5998 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5999 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000
6001 if (reset_phase == MPT_IOC_SETUP_RESET) {
6002 ;
6003 } else if (reset_phase == MPT_IOC_PRE_RESET) {
6004 /* If the internal config Q is not empty -
6005 * delete timer. MF resources will be freed when
6006 * the FIFO's are primed.
6007 */
6008 spin_lock_irqsave(&ioc->FreeQlock, flags);
6009 list_for_each_entry(pCfg, &ioc->configQ, linkage)
6010 del_timer(&pCfg->timer);
6011 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6012
6013 } else {
6014 CONFIGPARMS *pNext;
6015
6016 /* Search the configQ for internal commands.
6017 * Flush the Q, and wake up all suspended threads.
6018 */
6019 spin_lock_irqsave(&ioc->FreeQlock, flags);
6020 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
6021 list_del(&pCfg->linkage);
6022
6023 pCfg->status = MPT_CONFIG_ERROR;
6024 pCfg->wait_done = 1;
6025 wake_up(&mpt_waitq);
6026 }
6027 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6028 }
6029
6030 return 1; /* currently means nothing really */
6031}
6032
6033
6034#ifdef CONFIG_PROC_FS /* { */
6035/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6036/*
6037 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6038 */
6039/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006040/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6042 *
6043 * Returns 0 for success, non-zero for failure.
6044 */
6045static int
6046procmpt_create(void)
6047{
6048 struct proc_dir_entry *ent;
6049
6050 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6051 if (mpt_proc_root_dir == NULL)
6052 return -ENOTDIR;
6053
6054 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6055 if (ent)
6056 ent->read_proc = procmpt_summary_read;
6057
6058 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6059 if (ent)
6060 ent->read_proc = procmpt_version_read;
6061
6062 return 0;
6063}
6064
6065/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006066/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6068 *
6069 * Returns 0 for success, non-zero for failure.
6070 */
6071static void
6072procmpt_destroy(void)
6073{
6074 remove_proc_entry("version", mpt_proc_root_dir);
6075 remove_proc_entry("summary", mpt_proc_root_dir);
6076 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6077}
6078
6079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006080/**
6081 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082 * @buf: Pointer to area to write information
6083 * @start: Pointer to start pointer
6084 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006085 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086 * @eof: Pointer to EOF integer
6087 * @data: Pointer
6088 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006089 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090 * Returns number of characters written to process performing the read.
6091 */
6092static int
6093procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6094{
6095 MPT_ADAPTER *ioc;
6096 char *out = buf;
6097 int len;
6098
6099 if (data) {
6100 int more = 0;
6101
6102 ioc = data;
6103 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6104
6105 out += more;
6106 } else {
6107 list_for_each_entry(ioc, &ioc_list, list) {
6108 int more = 0;
6109
6110 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6111
6112 out += more;
6113 if ((out-buf) >= request)
6114 break;
6115 }
6116 }
6117
6118 len = out - buf;
6119
6120 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6121}
6122
6123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006124/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 * procmpt_version_read - Handle read request from /proc/mpt/version.
6126 * @buf: Pointer to area to write information
6127 * @start: Pointer to start pointer
6128 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006129 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 * @eof: Pointer to EOF integer
6131 * @data: Pointer
6132 *
6133 * Returns number of characters written to process performing the read.
6134 */
6135static int
6136procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6137{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306138 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006139 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140 char *drvname;
6141 int len;
6142
6143 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6144 len += sprintf(buf+len, " Fusion MPT base driver\n");
6145
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006146 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006147 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306149 if (MptCallbacks[cb_idx]) {
6150 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006151 case MPTSPI_DRIVER:
6152 if (!scsi++) drvname = "SPI host";
6153 break;
6154 case MPTFC_DRIVER:
6155 if (!fc++) drvname = "FC host";
6156 break;
6157 case MPTSAS_DRIVER:
6158 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 break;
6160 case MPTLAN_DRIVER:
6161 if (!lan++) drvname = "LAN";
6162 break;
6163 case MPTSTM_DRIVER:
6164 if (!targ++) drvname = "SCSI target";
6165 break;
6166 case MPTCTL_DRIVER:
6167 if (!ctl++) drvname = "ioctl";
6168 break;
6169 }
6170
6171 if (drvname)
6172 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6173 }
6174 }
6175
6176 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6177}
6178
6179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006180/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6182 * @buf: Pointer to area to write information
6183 * @start: Pointer to start pointer
6184 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006185 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186 * @eof: Pointer to EOF integer
6187 * @data: Pointer
6188 *
6189 * Returns number of characters written to process performing the read.
6190 */
6191static int
6192procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6193{
6194 MPT_ADAPTER *ioc = data;
6195 int len;
6196 char expVer[32];
6197 int sz;
6198 int p;
6199
6200 mpt_get_fw_exp_ver(expVer, ioc);
6201
6202 len = sprintf(buf, "%s:", ioc->name);
6203 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6204 len += sprintf(buf+len, " (f/w download boot flag set)");
6205// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6206// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6207
6208 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6209 ioc->facts.ProductID,
6210 ioc->prod_name);
6211 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6212 if (ioc->facts.FWImageSize)
6213 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6214 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6215 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6216 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6217
6218 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6219 ioc->facts.CurrentHostMfaHighAddr);
6220 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6221 ioc->facts.CurrentSenseBufferHighAddr);
6222
6223 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6224 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6225
6226 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6227 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6228 /*
6229 * Rounding UP to nearest 4-kB boundary here...
6230 */
6231 sz = (ioc->req_sz * ioc->req_depth) + 128;
6232 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6233 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6234 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6235 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6236 4*ioc->facts.RequestFrameSize,
6237 ioc->facts.GlobalCredits);
6238
6239 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6240 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6241 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6242 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6243 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6244 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6245 ioc->facts.CurReplyFrameSize,
6246 ioc->facts.ReplyQueueDepth);
6247
6248 len += sprintf(buf+len, " MaxDevices = %d\n",
6249 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6250 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6251
6252 /* per-port info */
6253 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6254 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6255 p+1,
6256 ioc->facts.NumberOfPorts);
6257 if (ioc->bus_type == FC) {
6258 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6259 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6260 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6261 a[5], a[4], a[3], a[2], a[1], a[0]);
6262 }
6263 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6264 ioc->fc_port_page0[p].WWNN.High,
6265 ioc->fc_port_page0[p].WWNN.Low,
6266 ioc->fc_port_page0[p].WWPN.High,
6267 ioc->fc_port_page0[p].WWPN.Low);
6268 }
6269 }
6270
6271 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6272}
6273
6274#endif /* CONFIG_PROC_FS } */
6275
6276/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6277static void
6278mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6279{
6280 buf[0] ='\0';
6281 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6282 sprintf(buf, " (Exp %02d%02d)",
6283 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6284 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6285
6286 /* insider hack! */
6287 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6288 strcat(buf, " [MDBG]");
6289 }
6290}
6291
6292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6293/**
6294 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6295 * @ioc: Pointer to MPT_ADAPTER structure
6296 * @buffer: Pointer to buffer where IOC summary info should be written
6297 * @size: Pointer to number of bytes we wrote (set by this routine)
6298 * @len: Offset at which to start writing in buffer
6299 * @showlan: Display LAN stuff?
6300 *
6301 * This routine writes (english readable) ASCII text, which represents
6302 * a summary of IOC information, to a buffer.
6303 */
6304void
6305mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6306{
6307 char expVer[32];
6308 int y;
6309
6310 mpt_get_fw_exp_ver(expVer, ioc);
6311
6312 /*
6313 * Shorter summary of attached ioc's...
6314 */
6315 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6316 ioc->name,
6317 ioc->prod_name,
6318 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6319 ioc->facts.FWVersion.Word,
6320 expVer,
6321 ioc->facts.NumberOfPorts,
6322 ioc->req_depth);
6323
6324 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6325 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6326 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6327 a[5], a[4], a[3], a[2], a[1], a[0]);
6328 }
6329
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331
6332 if (!ioc->active)
6333 y += sprintf(buffer+len+y, " (disabled)");
6334
6335 y += sprintf(buffer+len+y, "\n");
6336
6337 *size = y;
6338}
6339
6340/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6341/*
6342 * Reset Handling
6343 */
6344/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6345/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006346 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 * @ioc: Pointer to MPT_ADAPTER structure
6348 * @sleepFlag: Indicates if sleep or schedule must be called.
6349 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006350 * Issues SCSI Task Management call based on input arg values.
6351 * If TaskMgmt fails, returns associated SCSI request.
6352 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6354 * or a non-interrupt thread. In the former, must not call schedule().
6355 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006356 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357 * FW reload/initialization failed.
6358 *
6359 * Returns 0 for SUCCESS or -1 if FAILED.
6360 */
6361int
6362mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6363{
6364 int rc;
6365 unsigned long flags;
6366
Prakash, Sathya436ace72007-07-24 15:42:08 +05306367 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368#ifdef MFCNT
6369 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6370 printk("MF count 0x%x !\n", ioc->mfcnt);
6371#endif
6372
6373 /* Reset the adapter. Prevent more than 1 call to
6374 * mpt_do_ioc_recovery at any instant in time.
6375 */
6376 spin_lock_irqsave(&ioc->diagLock, flags);
6377 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6378 spin_unlock_irqrestore(&ioc->diagLock, flags);
6379 return 0;
6380 } else {
6381 ioc->diagPending = 1;
6382 }
6383 spin_unlock_irqrestore(&ioc->diagLock, flags);
6384
6385 /* FIXME: If do_ioc_recovery fails, repeat....
6386 */
6387
6388 /* The SCSI driver needs to adjust timeouts on all current
6389 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006390 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391 * For all other protocol drivers, this is a no-op.
6392 */
6393 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306394 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006395 int r = 0;
6396
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306397 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6398 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306399 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306400 ioc->name, cb_idx));
6401 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306403 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306404 ioc->name, ioc->alt_ioc->name, cb_idx));
6405 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 }
6407 }
6408 }
6409 }
6410
6411 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006412 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413 }
6414 ioc->reload_fw = 0;
6415 if (ioc->alt_ioc)
6416 ioc->alt_ioc->reload_fw = 0;
6417
6418 spin_lock_irqsave(&ioc->diagLock, flags);
6419 ioc->diagPending = 0;
6420 if (ioc->alt_ioc)
6421 ioc->alt_ioc->diagPending = 0;
6422 spin_unlock_irqrestore(&ioc->diagLock, flags);
6423
Prakash, Sathya436ace72007-07-24 15:42:08 +05306424 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425
6426 return rc;
6427}
6428
6429/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006430static void
6431EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006432{
Eric Moore509e5e52006-04-26 13:22:37 -06006433 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434
6435 switch(event) {
6436 case MPI_EVENT_NONE:
6437 ds = "None";
6438 break;
6439 case MPI_EVENT_LOG_DATA:
6440 ds = "Log Data";
6441 break;
6442 case MPI_EVENT_STATE_CHANGE:
6443 ds = "State Change";
6444 break;
6445 case MPI_EVENT_UNIT_ATTENTION:
6446 ds = "Unit Attention";
6447 break;
6448 case MPI_EVENT_IOC_BUS_RESET:
6449 ds = "IOC Bus Reset";
6450 break;
6451 case MPI_EVENT_EXT_BUS_RESET:
6452 ds = "External Bus Reset";
6453 break;
6454 case MPI_EVENT_RESCAN:
6455 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456 break;
6457 case MPI_EVENT_LINK_STATUS_CHANGE:
6458 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6459 ds = "Link Status(FAILURE) Change";
6460 else
6461 ds = "Link Status(ACTIVE) Change";
6462 break;
6463 case MPI_EVENT_LOOP_STATE_CHANGE:
6464 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6465 ds = "Loop State(LIP) Change";
6466 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006467 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468 else
Eric Moore509e5e52006-04-26 13:22:37 -06006469 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006470 break;
6471 case MPI_EVENT_LOGOUT:
6472 ds = "Logout";
6473 break;
6474 case MPI_EVENT_EVENT_CHANGE:
6475 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006476 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006477 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006478 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006479 break;
6480 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006481 {
6482 u8 ReasonCode = (u8)(evData0 >> 16);
6483 switch (ReasonCode) {
6484 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6485 ds = "Integrated Raid: Volume Created";
6486 break;
6487 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6488 ds = "Integrated Raid: Volume Deleted";
6489 break;
6490 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6491 ds = "Integrated Raid: Volume Settings Changed";
6492 break;
6493 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6494 ds = "Integrated Raid: Volume Status Changed";
6495 break;
6496 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6497 ds = "Integrated Raid: Volume Physdisk Changed";
6498 break;
6499 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6500 ds = "Integrated Raid: Physdisk Created";
6501 break;
6502 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6503 ds = "Integrated Raid: Physdisk Deleted";
6504 break;
6505 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6506 ds = "Integrated Raid: Physdisk Settings Changed";
6507 break;
6508 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6509 ds = "Integrated Raid: Physdisk Status Changed";
6510 break;
6511 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6512 ds = "Integrated Raid: Domain Validation Needed";
6513 break;
6514 case MPI_EVENT_RAID_RC_SMART_DATA :
6515 ds = "Integrated Raid; Smart Data";
6516 break;
6517 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6518 ds = "Integrated Raid: Replace Action Started";
6519 break;
6520 default:
6521 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006522 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006523 }
6524 break;
6525 }
6526 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6527 ds = "SCSI Device Status Change";
6528 break;
6529 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6530 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006531 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006532 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006533 u8 ReasonCode = (u8)(evData0 >> 16);
6534 switch (ReasonCode) {
6535 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006536 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006537 "SAS Device Status Change: Added: "
6538 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006539 break;
6540 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006541 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006542 "SAS Device Status Change: Deleted: "
6543 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006544 break;
6545 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006546 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006547 "SAS Device Status Change: SMART Data: "
6548 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006549 break;
6550 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006551 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006552 "SAS Device Status Change: No Persistancy: "
6553 "id=%d channel=%d", id, channel);
6554 break;
6555 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6556 snprintf(evStr, EVENT_DESCR_STR_SZ,
6557 "SAS Device Status Change: Unsupported Device "
6558 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006559 break;
6560 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6561 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006562 "SAS Device Status Change: Internal Device "
6563 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006564 break;
6565 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6566 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006567 "SAS Device Status Change: Internal Task "
6568 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006569 break;
6570 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6571 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006572 "SAS Device Status Change: Internal Abort "
6573 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006574 break;
6575 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6576 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006577 "SAS Device Status Change: Internal Clear "
6578 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006579 break;
6580 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6581 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006582 "SAS Device Status Change: Internal Query "
6583 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006584 break;
6585 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006586 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006587 "SAS Device Status Change: Unknown: "
6588 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006589 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006590 }
6591 break;
6592 }
6593 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6594 ds = "Bus Timer Expired";
6595 break;
6596 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006597 {
6598 u16 curr_depth = (u16)(evData0 >> 16);
6599 u8 channel = (u8)(evData0 >> 8);
6600 u8 id = (u8)(evData0);
6601
6602 snprintf(evStr, EVENT_DESCR_STR_SZ,
6603 "Queue Full: channel=%d id=%d depth=%d",
6604 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006605 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006606 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006607 case MPI_EVENT_SAS_SES:
6608 ds = "SAS SES Event";
6609 break;
6610 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6611 ds = "Persistent Table Full";
6612 break;
6613 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006614 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006615 u8 LinkRates = (u8)(evData0 >> 8);
6616 u8 PhyNumber = (u8)(evData0);
6617 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6618 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6619 switch (LinkRates) {
6620 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006621 snprintf(evStr, EVENT_DESCR_STR_SZ,
6622 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006623 " Rate Unknown",PhyNumber);
6624 break;
6625 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006626 snprintf(evStr, EVENT_DESCR_STR_SZ,
6627 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006628 " Phy Disabled",PhyNumber);
6629 break;
6630 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006631 snprintf(evStr, EVENT_DESCR_STR_SZ,
6632 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006633 " Failed Speed Nego",PhyNumber);
6634 break;
6635 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006636 snprintf(evStr, EVENT_DESCR_STR_SZ,
6637 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006638 " Sata OOB Completed",PhyNumber);
6639 break;
6640 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006641 snprintf(evStr, EVENT_DESCR_STR_SZ,
6642 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006643 " Rate 1.5 Gbps",PhyNumber);
6644 break;
6645 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006646 snprintf(evStr, EVENT_DESCR_STR_SZ,
6647 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006648 " Rate 3.0 Gpbs",PhyNumber);
6649 break;
6650 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006651 snprintf(evStr, EVENT_DESCR_STR_SZ,
6652 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006653 break;
6654 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006655 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006656 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006657 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6658 ds = "SAS Discovery Error";
6659 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006660 case MPI_EVENT_IR_RESYNC_UPDATE:
6661 {
6662 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006663 snprintf(evStr, EVENT_DESCR_STR_SZ,
6664 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006665 break;
6666 }
6667 case MPI_EVENT_IR2:
6668 {
6669 u8 ReasonCode = (u8)(evData0 >> 16);
6670 switch (ReasonCode) {
6671 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6672 ds = "IR2: LD State Changed";
6673 break;
6674 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6675 ds = "IR2: PD State Changed";
6676 break;
6677 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6678 ds = "IR2: Bad Block Table Full";
6679 break;
6680 case MPI_EVENT_IR2_RC_PD_INSERTED:
6681 ds = "IR2: PD Inserted";
6682 break;
6683 case MPI_EVENT_IR2_RC_PD_REMOVED:
6684 ds = "IR2: PD Removed";
6685 break;
6686 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6687 ds = "IR2: Foreign CFG Detected";
6688 break;
6689 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6690 ds = "IR2: Rebuild Medium Error";
6691 break;
6692 default:
6693 ds = "IR2";
6694 break;
6695 }
6696 break;
6697 }
6698 case MPI_EVENT_SAS_DISCOVERY:
6699 {
6700 if (evData0)
6701 ds = "SAS Discovery: Start";
6702 else
6703 ds = "SAS Discovery: Stop";
6704 break;
6705 }
6706 case MPI_EVENT_LOG_ENTRY_ADDED:
6707 ds = "SAS Log Entry Added";
6708 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006709
Eric Moorec6c727a2007-01-29 09:44:54 -07006710 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6711 {
6712 u8 phy_num = (u8)(evData0);
6713 u8 port_num = (u8)(evData0 >> 8);
6714 u8 port_width = (u8)(evData0 >> 16);
6715 u8 primative = (u8)(evData0 >> 24);
6716 snprintf(evStr, EVENT_DESCR_STR_SZ,
6717 "SAS Broadcase Primative: phy=%d port=%d "
6718 "width=%d primative=0x%02x",
6719 phy_num, port_num, port_width, primative);
6720 break;
6721 }
6722
6723 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6724 {
6725 u8 reason = (u8)(evData0);
6726 u8 port_num = (u8)(evData0 >> 8);
6727 u16 handle = le16_to_cpu(evData0 >> 16);
6728
6729 snprintf(evStr, EVENT_DESCR_STR_SZ,
6730 "SAS Initiator Device Status Change: reason=0x%02x "
6731 "port=%d handle=0x%04x",
6732 reason, port_num, handle);
6733 break;
6734 }
6735
6736 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6737 {
6738 u8 max_init = (u8)(evData0);
6739 u8 current_init = (u8)(evData0 >> 8);
6740
6741 snprintf(evStr, EVENT_DESCR_STR_SZ,
6742 "SAS Initiator Device Table Overflow: max initiators=%02d "
6743 "current initators=%02d",
6744 max_init, current_init);
6745 break;
6746 }
6747 case MPI_EVENT_SAS_SMP_ERROR:
6748 {
6749 u8 status = (u8)(evData0);
6750 u8 port_num = (u8)(evData0 >> 8);
6751 u8 result = (u8)(evData0 >> 16);
6752
6753 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6754 snprintf(evStr, EVENT_DESCR_STR_SZ,
6755 "SAS SMP Error: port=%d result=0x%02x",
6756 port_num, result);
6757 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6758 snprintf(evStr, EVENT_DESCR_STR_SZ,
6759 "SAS SMP Error: port=%d : CRC Error",
6760 port_num);
6761 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6762 snprintf(evStr, EVENT_DESCR_STR_SZ,
6763 "SAS SMP Error: port=%d : Timeout",
6764 port_num);
6765 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6766 snprintf(evStr, EVENT_DESCR_STR_SZ,
6767 "SAS SMP Error: port=%d : No Destination",
6768 port_num);
6769 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6770 snprintf(evStr, EVENT_DESCR_STR_SZ,
6771 "SAS SMP Error: port=%d : Bad Destination",
6772 port_num);
6773 else
6774 snprintf(evStr, EVENT_DESCR_STR_SZ,
6775 "SAS SMP Error: port=%d : status=0x%02x",
6776 port_num, status);
6777 break;
6778 }
6779
Linus Torvalds1da177e2005-04-16 15:20:36 -07006780 /*
6781 * MPT base "custom" events may be added here...
6782 */
6783 default:
6784 ds = "Unknown";
6785 break;
6786 }
Eric Moore509e5e52006-04-26 13:22:37 -06006787 if (ds)
6788 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006789}
6790
6791/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006792/**
6793 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006794 * @ioc: Pointer to MPT_ADAPTER structure
6795 * @pEventReply: Pointer to EventNotification reply frame
6796 * @evHandlers: Pointer to integer, number of event handlers
6797 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006798 * Routes a received EventNotificationReply to all currently registered
6799 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800 * Returns sum of event handlers return values.
6801 */
6802static int
6803ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6804{
6805 u16 evDataLen;
6806 u32 evData0 = 0;
6807// u32 evCtx;
6808 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306809 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810 int r = 0;
6811 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006812 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813 u8 event;
6814
6815 /*
6816 * Do platform normalization of values
6817 */
6818 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6819// evCtx = le32_to_cpu(pEventReply->EventContext);
6820 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6821 if (evDataLen) {
6822 evData0 = le32_to_cpu(pEventReply->Data[0]);
6823 }
6824
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006825 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306826 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006827 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006828 event,
6829 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006830
Prakash, Sathya436ace72007-07-24 15:42:08 +05306831#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006832 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6833 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006834 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306835 devtverboseprintk(ioc, printk(" %08x",
6836 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006837 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006838#endif
6839
6840 /*
6841 * Do general / base driver event processing
6842 */
6843 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006844 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6845 if (evDataLen) {
6846 u8 evState = evData0 & 0xFF;
6847
6848 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6849
6850 /* Update EventState field in cached IocFacts */
6851 if (ioc->facts.Function) {
6852 ioc->facts.EventState = evState;
6853 }
6854 }
6855 break;
Moore, Ericece50912006-01-16 18:53:19 -07006856 case MPI_EVENT_INTEGRATED_RAID:
6857 mptbase_raid_process_event_data(ioc,
6858 (MpiEventDataRaid_t *)pEventReply->Data);
6859 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006860 default:
6861 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006862 }
6863
6864 /*
6865 * Should this event be logged? Events are written sequentially.
6866 * When buffer is full, start again at the top.
6867 */
6868 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6869 int idx;
6870
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006871 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006872
6873 ioc->events[idx].event = event;
6874 ioc->events[idx].eventContext = ioc->eventContext;
6875
6876 for (ii = 0; ii < 2; ii++) {
6877 if (ii < evDataLen)
6878 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6879 else
6880 ioc->events[idx].data[ii] = 0;
6881 }
6882
6883 ioc->eventContext++;
6884 }
6885
6886
6887 /*
6888 * Call each currently registered protocol event handler.
6889 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006890 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306891 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306892 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306893 ioc->name, cb_idx));
6894 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006895 handlers++;
6896 }
6897 }
6898 /* FIXME? Examine results here? */
6899
6900 /*
6901 * If needed, send (a single) EventAck.
6902 */
6903 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306904 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006905 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006906 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306907 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006908 ioc->name, ii));
6909 }
6910 }
6911
6912 *evHandlers = handlers;
6913 return r;
6914}
6915
6916/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006917/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006918 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6919 * @ioc: Pointer to MPT_ADAPTER structure
6920 * @log_info: U32 LogInfo reply word from the IOC
6921 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006922 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006923 */
6924static void
6925mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6926{
Eric Moore7c431e52007-06-13 16:34:36 -06006927 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006928
Eric Moore7c431e52007-06-13 16:34:36 -06006929 switch (log_info & 0xFF000000) {
6930 case MPI_IOCLOGINFO_FC_INIT_BASE:
6931 desc = "FCP Initiator";
6932 break;
6933 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6934 desc = "FCP Target";
6935 break;
6936 case MPI_IOCLOGINFO_FC_LAN_BASE:
6937 desc = "LAN";
6938 break;
6939 case MPI_IOCLOGINFO_FC_MSG_BASE:
6940 desc = "MPI Message Layer";
6941 break;
6942 case MPI_IOCLOGINFO_FC_LINK_BASE:
6943 desc = "FC Link";
6944 break;
6945 case MPI_IOCLOGINFO_FC_CTX_BASE:
6946 desc = "Context Manager";
6947 break;
6948 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6949 desc = "Invalid Field Offset";
6950 break;
6951 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6952 desc = "State Change Info";
6953 break;
6954 }
6955
6956 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6957 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006958}
6959
6960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006961/**
Moore, Eric335a9412006-01-17 17:06:23 -07006962 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006963 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07006964 * @log_info: U32 LogInfo word from the IOC
6965 *
6966 * Refer to lsi/sp_log.h.
6967 */
6968static void
Moore, Eric335a9412006-01-17 17:06:23 -07006969mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006970{
6971 u32 info = log_info & 0x00FF0000;
6972 char *desc = "unknown";
6973
6974 switch (info) {
6975 case 0x00010000:
6976 desc = "bug! MID not found";
6977 if (ioc->reload_fw == 0)
6978 ioc->reload_fw++;
6979 break;
6980
6981 case 0x00020000:
6982 desc = "Parity Error";
6983 break;
6984
6985 case 0x00030000:
6986 desc = "ASYNC Outbound Overrun";
6987 break;
6988
6989 case 0x00040000:
6990 desc = "SYNC Offset Error";
6991 break;
6992
6993 case 0x00050000:
6994 desc = "BM Change";
6995 break;
6996
6997 case 0x00060000:
6998 desc = "Msg In Overflow";
6999 break;
7000
7001 case 0x00070000:
7002 desc = "DMA Error";
7003 break;
7004
7005 case 0x00080000:
7006 desc = "Outbound DMA Overrun";
7007 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007008
Linus Torvalds1da177e2005-04-16 15:20:36 -07007009 case 0x00090000:
7010 desc = "Task Management";
7011 break;
7012
7013 case 0x000A0000:
7014 desc = "Device Problem";
7015 break;
7016
7017 case 0x000B0000:
7018 desc = "Invalid Phase Change";
7019 break;
7020
7021 case 0x000C0000:
7022 desc = "Untagged Table Size";
7023 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007024
Linus Torvalds1da177e2005-04-16 15:20:36 -07007025 }
7026
7027 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7028}
7029
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007030/* strings for sas loginfo */
7031 static char *originator_str[] = {
7032 "IOP", /* 00h */
7033 "PL", /* 01h */
7034 "IR" /* 02h */
7035 };
7036 static char *iop_code_str[] = {
7037 NULL, /* 00h */
7038 "Invalid SAS Address", /* 01h */
7039 NULL, /* 02h */
7040 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007041 "Diag Message Error", /* 04h */
7042 "Task Terminated", /* 05h */
7043 "Enclosure Management", /* 06h */
7044 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007045 };
7046 static char *pl_code_str[] = {
7047 NULL, /* 00h */
7048 "Open Failure", /* 01h */
7049 "Invalid Scatter Gather List", /* 02h */
7050 "Wrong Relative Offset or Frame Length", /* 03h */
7051 "Frame Transfer Error", /* 04h */
7052 "Transmit Frame Connected Low", /* 05h */
7053 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7054 "SATA Read Log Receive Data Error", /* 07h */
7055 "SATA NCQ Fail All Commands After Error", /* 08h */
7056 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7057 "Receive Frame Invalid Message", /* 0Ah */
7058 "Receive Context Message Valid Error", /* 0Bh */
7059 "Receive Frame Current Frame Error", /* 0Ch */
7060 "SATA Link Down", /* 0Dh */
7061 "Discovery SATA Init W IOS", /* 0Eh */
7062 "Config Invalid Page", /* 0Fh */
7063 "Discovery SATA Init Timeout", /* 10h */
7064 "Reset", /* 11h */
7065 "Abort", /* 12h */
7066 "IO Not Yet Executed", /* 13h */
7067 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007068 "Persistent Reservation Out Not Affiliation "
7069 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007070 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007071 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007072 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007073 NULL, /* 19h */
7074 NULL, /* 1Ah */
7075 NULL, /* 1Bh */
7076 NULL, /* 1Ch */
7077 NULL, /* 1Dh */
7078 NULL, /* 1Eh */
7079 NULL, /* 1Fh */
7080 "Enclosure Management" /* 20h */
7081 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007082 static char *ir_code_str[] = {
7083 "Raid Action Error", /* 00h */
7084 NULL, /* 00h */
7085 NULL, /* 01h */
7086 NULL, /* 02h */
7087 NULL, /* 03h */
7088 NULL, /* 04h */
7089 NULL, /* 05h */
7090 NULL, /* 06h */
7091 NULL /* 07h */
7092 };
7093 static char *raid_sub_code_str[] = {
7094 NULL, /* 00h */
7095 "Volume Creation Failed: Data Passed too "
7096 "Large", /* 01h */
7097 "Volume Creation Failed: Duplicate Volumes "
7098 "Attempted", /* 02h */
7099 "Volume Creation Failed: Max Number "
7100 "Supported Volumes Exceeded", /* 03h */
7101 "Volume Creation Failed: DMA Error", /* 04h */
7102 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7103 "Volume Creation Failed: Error Reading "
7104 "MFG Page 4", /* 06h */
7105 "Volume Creation Failed: Creating Internal "
7106 "Structures", /* 07h */
7107 NULL, /* 08h */
7108 NULL, /* 09h */
7109 NULL, /* 0Ah */
7110 NULL, /* 0Bh */
7111 NULL, /* 0Ch */
7112 NULL, /* 0Dh */
7113 NULL, /* 0Eh */
7114 NULL, /* 0Fh */
7115 "Activation failed: Already Active Volume", /* 10h */
7116 "Activation failed: Unsupported Volume Type", /* 11h */
7117 "Activation failed: Too Many Active Volumes", /* 12h */
7118 "Activation failed: Volume ID in Use", /* 13h */
7119 "Activation failed: Reported Failure", /* 14h */
7120 "Activation failed: Importing a Volume", /* 15h */
7121 NULL, /* 16h */
7122 NULL, /* 17h */
7123 NULL, /* 18h */
7124 NULL, /* 19h */
7125 NULL, /* 1Ah */
7126 NULL, /* 1Bh */
7127 NULL, /* 1Ch */
7128 NULL, /* 1Dh */
7129 NULL, /* 1Eh */
7130 NULL, /* 1Fh */
7131 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7132 "Phys Disk failed: Data Passed too Large", /* 21h */
7133 "Phys Disk failed: DMA Error", /* 22h */
7134 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7135 "Phys Disk failed: Creating Phys Disk Config "
7136 "Page", /* 24h */
7137 NULL, /* 25h */
7138 NULL, /* 26h */
7139 NULL, /* 27h */
7140 NULL, /* 28h */
7141 NULL, /* 29h */
7142 NULL, /* 2Ah */
7143 NULL, /* 2Bh */
7144 NULL, /* 2Ch */
7145 NULL, /* 2Dh */
7146 NULL, /* 2Eh */
7147 NULL, /* 2Fh */
7148 "Compatibility Error: IR Disabled", /* 30h */
7149 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7150 "Compatibility Error: Device not Direct Access "
7151 "Device ", /* 32h */
7152 "Compatibility Error: Removable Device Found", /* 33h */
7153 "Compatibility Error: Device SCSI Version not "
7154 "2 or Higher", /* 34h */
7155 "Compatibility Error: SATA Device, 48 BIT LBA "
7156 "not Supported", /* 35h */
7157 "Compatibility Error: Device doesn't have "
7158 "512 Byte Block Sizes", /* 36h */
7159 "Compatibility Error: Volume Type Check Failed", /* 37h */
7160 "Compatibility Error: Volume Type is "
7161 "Unsupported by FW", /* 38h */
7162 "Compatibility Error: Disk Drive too Small for "
7163 "use in Volume", /* 39h */
7164 "Compatibility Error: Phys Disk for Create "
7165 "Volume not Found", /* 3Ah */
7166 "Compatibility Error: Too Many or too Few "
7167 "Disks for Volume Type", /* 3Bh */
7168 "Compatibility Error: Disk stripe Sizes "
7169 "Must be 64KB", /* 3Ch */
7170 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7171 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007172
7173/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007174/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007175 * mpt_sas_log_info - Log information returned from SAS IOC.
7176 * @ioc: Pointer to MPT_ADAPTER structure
7177 * @log_info: U32 LogInfo reply word from the IOC
7178 *
7179 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007180 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007181static void
7182mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7183{
7184union loginfo_type {
7185 u32 loginfo;
7186 struct {
7187 u32 subcode:16;
7188 u32 code:8;
7189 u32 originator:4;
7190 u32 bus_type:4;
7191 }dw;
7192};
7193 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007194 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007195 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007196 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007197
7198 sas_loginfo.loginfo = log_info;
7199 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007200 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007201 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007202
7203 originator_desc = originator_str[sas_loginfo.dw.originator];
7204
7205 switch (sas_loginfo.dw.originator) {
7206
7207 case 0: /* IOP */
7208 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007209 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007210 code_desc = iop_code_str[sas_loginfo.dw.code];
7211 break;
7212 case 1: /* PL */
7213 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007214 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007215 code_desc = pl_code_str[sas_loginfo.dw.code];
7216 break;
7217 case 2: /* IR */
7218 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007219 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007220 break;
7221 code_desc = ir_code_str[sas_loginfo.dw.code];
7222 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007223 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007224 break;
7225 if (sas_loginfo.dw.code == 0)
7226 sub_code_desc =
7227 raid_sub_code_str[sas_loginfo.dw.subcode];
7228 break;
7229 default:
7230 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007231 }
7232
Eric Moorec6c727a2007-01-29 09:44:54 -07007233 if (sub_code_desc != NULL)
7234 printk(MYIOC_s_INFO_FMT
7235 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7236 " SubCode={%s}\n",
7237 ioc->name, log_info, originator_desc, code_desc,
7238 sub_code_desc);
7239 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007240 printk(MYIOC_s_INFO_FMT
7241 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7242 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007243 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007244 sas_loginfo.dw.subcode);
7245 else
7246 printk(MYIOC_s_INFO_FMT
7247 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7248 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007249 ioc->name, log_info, originator_desc,
7250 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007251}
7252
Linus Torvalds1da177e2005-04-16 15:20:36 -07007253/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007254/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007255 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7256 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007257 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007258 * @mf: Pointer to MPT request frame
7259 *
7260 * Refer to lsi/mpi.h.
7261 **/
7262static void
7263mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7264{
7265 Config_t *pReq = (Config_t *)mf;
7266 char extend_desc[EVENT_DESCR_STR_SZ];
7267 char *desc = NULL;
7268 u32 form;
7269 u8 page_type;
7270
7271 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7272 page_type = pReq->ExtPageType;
7273 else
7274 page_type = pReq->Header.PageType;
7275
7276 /*
7277 * ignore invalid page messages for GET_NEXT_HANDLE
7278 */
7279 form = le32_to_cpu(pReq->PageAddress);
7280 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7281 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7282 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7283 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7284 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7285 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7286 return;
7287 }
7288 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7289 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7290 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7291 return;
7292 }
7293
7294 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7295 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7296 page_type, pReq->Header.PageNumber, pReq->Action, form);
7297
7298 switch (ioc_status) {
7299
7300 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7301 desc = "Config Page Invalid Action";
7302 break;
7303
7304 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7305 desc = "Config Page Invalid Type";
7306 break;
7307
7308 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7309 desc = "Config Page Invalid Page";
7310 break;
7311
7312 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7313 desc = "Config Page Invalid Data";
7314 break;
7315
7316 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7317 desc = "Config Page No Defaults";
7318 break;
7319
7320 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7321 desc = "Config Page Can't Commit";
7322 break;
7323 }
7324
7325 if (!desc)
7326 return;
7327
Eric Moore29dd3602007-09-14 18:46:51 -06007328 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7329 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007330}
7331
7332/**
7333 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007334 * @ioc: Pointer to MPT_ADAPTER structure
7335 * @ioc_status: U32 IOCStatus word from IOC
7336 * @mf: Pointer to MPT request frame
7337 *
7338 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007339 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007340static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007341mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007342{
7343 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007344 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007345
7346 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007347
7348/****************************************************************************/
7349/* Common IOCStatus values for all replies */
7350/****************************************************************************/
7351
Linus Torvalds1da177e2005-04-16 15:20:36 -07007352 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7353 desc = "Invalid Function";
7354 break;
7355
7356 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7357 desc = "Busy";
7358 break;
7359
7360 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7361 desc = "Invalid SGL";
7362 break;
7363
7364 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7365 desc = "Internal Error";
7366 break;
7367
7368 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7369 desc = "Reserved";
7370 break;
7371
7372 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7373 desc = "Insufficient Resources";
7374 break;
7375
7376 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7377 desc = "Invalid Field";
7378 break;
7379
7380 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7381 desc = "Invalid State";
7382 break;
7383
Eric Moorec6c727a2007-01-29 09:44:54 -07007384/****************************************************************************/
7385/* Config IOCStatus values */
7386/****************************************************************************/
7387
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7389 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7390 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7391 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7392 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7393 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007394 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007395 break;
7396
Eric Moorec6c727a2007-01-29 09:44:54 -07007397/****************************************************************************/
7398/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7399/* */
7400/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7401/* */
7402/****************************************************************************/
7403
Linus Torvalds1da177e2005-04-16 15:20:36 -07007404 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007406 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7407 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7408 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7409 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007411 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007412 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007413 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007414 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007415 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007416 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007417 break;
7418
Eric Moorec6c727a2007-01-29 09:44:54 -07007419/****************************************************************************/
7420/* SCSI Target values */
7421/****************************************************************************/
7422
7423 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7424 desc = "Target: Priority IO";
7425 break;
7426
7427 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7428 desc = "Target: Invalid Port";
7429 break;
7430
7431 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7432 desc = "Target Invalid IO Index:";
7433 break;
7434
7435 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7436 desc = "Target: Aborted";
7437 break;
7438
7439 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7440 desc = "Target: No Conn Retryable";
7441 break;
7442
7443 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7444 desc = "Target: No Connection";
7445 break;
7446
7447 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7448 desc = "Target: Transfer Count Mismatch";
7449 break;
7450
7451 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7452 desc = "Target: STS Data not Sent";
7453 break;
7454
7455 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7456 desc = "Target: Data Offset Error";
7457 break;
7458
7459 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7460 desc = "Target: Too Much Write Data";
7461 break;
7462
7463 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7464 desc = "Target: IU Too Short";
7465 break;
7466
7467 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7468 desc = "Target: ACK NAK Timeout";
7469 break;
7470
7471 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7472 desc = "Target: Nak Received";
7473 break;
7474
7475/****************************************************************************/
7476/* Fibre Channel Direct Access values */
7477/****************************************************************************/
7478
7479 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7480 desc = "FC: Aborted";
7481 break;
7482
7483 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7484 desc = "FC: RX ID Invalid";
7485 break;
7486
7487 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7488 desc = "FC: DID Invalid";
7489 break;
7490
7491 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7492 desc = "FC: Node Logged Out";
7493 break;
7494
7495 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7496 desc = "FC: Exchange Canceled";
7497 break;
7498
7499/****************************************************************************/
7500/* LAN values */
7501/****************************************************************************/
7502
7503 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7504 desc = "LAN: Device not Found";
7505 break;
7506
7507 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7508 desc = "LAN: Device Failure";
7509 break;
7510
7511 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7512 desc = "LAN: Transmit Error";
7513 break;
7514
7515 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7516 desc = "LAN: Transmit Aborted";
7517 break;
7518
7519 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7520 desc = "LAN: Receive Error";
7521 break;
7522
7523 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7524 desc = "LAN: Receive Aborted";
7525 break;
7526
7527 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7528 desc = "LAN: Partial Packet";
7529 break;
7530
7531 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7532 desc = "LAN: Canceled";
7533 break;
7534
7535/****************************************************************************/
7536/* Serial Attached SCSI values */
7537/****************************************************************************/
7538
7539 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7540 desc = "SAS: SMP Request Failed";
7541 break;
7542
7543 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7544 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007545 break;
7546
7547 default:
7548 desc = "Others";
7549 break;
7550 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007551
7552 if (!desc)
7553 return;
7554
Eric Moore29dd3602007-09-14 18:46:51 -06007555 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7556 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007557}
7558
7559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007560EXPORT_SYMBOL(mpt_attach);
7561EXPORT_SYMBOL(mpt_detach);
7562#ifdef CONFIG_PM
7563EXPORT_SYMBOL(mpt_resume);
7564EXPORT_SYMBOL(mpt_suspend);
7565#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007566EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007567EXPORT_SYMBOL(mpt_register);
7568EXPORT_SYMBOL(mpt_deregister);
7569EXPORT_SYMBOL(mpt_event_register);
7570EXPORT_SYMBOL(mpt_event_deregister);
7571EXPORT_SYMBOL(mpt_reset_register);
7572EXPORT_SYMBOL(mpt_reset_deregister);
7573EXPORT_SYMBOL(mpt_device_driver_register);
7574EXPORT_SYMBOL(mpt_device_driver_deregister);
7575EXPORT_SYMBOL(mpt_get_msg_frame);
7576EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307577EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007578EXPORT_SYMBOL(mpt_free_msg_frame);
7579EXPORT_SYMBOL(mpt_add_sge);
7580EXPORT_SYMBOL(mpt_send_handshake_request);
7581EXPORT_SYMBOL(mpt_verify_adapter);
7582EXPORT_SYMBOL(mpt_GetIocState);
7583EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007584EXPORT_SYMBOL(mpt_HardResetHandler);
7585EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007586EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007587EXPORT_SYMBOL(mpt_alloc_fw_memory);
7588EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007589EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007590EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007591
Linus Torvalds1da177e2005-04-16 15:20:36 -07007592/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007593/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007594 * fusion_init - Fusion MPT base driver initialization routine.
7595 *
7596 * Returns 0 for success, non-zero for failure.
7597 */
7598static int __init
7599fusion_init(void)
7600{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307601 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007602
7603 show_mptmod_ver(my_NAME, my_VERSION);
7604 printk(KERN_INFO COPYRIGHT "\n");
7605
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307606 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7607 MptCallbacks[cb_idx] = NULL;
7608 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7609 MptEvHandlers[cb_idx] = NULL;
7610 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007611 }
7612
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007613 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007614 * EventNotification handling.
7615 */
7616 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7617
7618 /* Register for hard reset handling callbacks.
7619 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307620 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007621
7622#ifdef CONFIG_PROC_FS
7623 (void) procmpt_create();
7624#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007625 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007626}
7627
7628/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007629/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007630 * fusion_exit - Perform driver unload cleanup.
7631 *
7632 * This routine frees all resources associated with each MPT adapter
7633 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7634 */
7635static void __exit
7636fusion_exit(void)
7637{
7638
Linus Torvalds1da177e2005-04-16 15:20:36 -07007639 mpt_reset_deregister(mpt_base_index);
7640
7641#ifdef CONFIG_PROC_FS
7642 procmpt_destroy();
7643#endif
7644}
7645
Linus Torvalds1da177e2005-04-16 15:20:36 -07007646module_init(fusion_init);
7647module_exit(fusion_exit);