blob: 75e599b85b645aba6d4de501f7f6c22e01dfa825 [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 */
Prakash, Sathya23a274c2008-03-07 15:53:21 +053082static int mpt_msi_enable = -1;
Christoph Hellwig4ddce142006-01-17 13:44:29 +000083module_param(mpt_msi_enable, int, 0);
84MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086static int mpt_channel_mapping;
87module_param(mpt_channel_mapping, int, 0);
88MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
89
Prakash, Sathya436ace72007-07-24 15:42:08 +053090static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -040091static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
92module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
93 &mpt_debug_level, 0600);
Prakash, Sathya436ace72007-07-24 15:42:08 +053094MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifdef MFCNT
97static int mfcounter = 0;
98#define PRINT_MF_COUNT 20000
99#endif
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Public data...
104 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Adrian Bunk15424922008-04-22 00:31:51 +0300106static struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108#define WHOINIT_UNKNOWN 0xAA
109
110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
111/*
112 * Private data...
113 */
114 /* Adapter link list */
115LIST_HEAD(ioc_list);
116 /* Callback lookup table */
117static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
118 /* Protocol driver class lookup table */
119static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
120 /* Event handler lookup table */
121static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
122 /* Reset handler lookup table */
123static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
124static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
127
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530128/*
129 * Driver Callback Index's
130 */
131static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
132static u8 last_drv_idx;
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
135/*
136 * Forward protos...
137 */
David Howells7d12e782006-10-05 14:55:46 +0100138static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
140static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
141 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
142 int sleepFlag);
143static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
144static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
145static void mpt_adapter_disable(MPT_ADAPTER *ioc);
146static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
147
148static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
149static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
151static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
152static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
153static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
154static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200155static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
157static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
158static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
159static int PrimeIocFifos(MPT_ADAPTER *ioc);
160static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
161static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
162static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
163static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200165int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
167static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
168static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
169static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
170static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530171static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
173static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200174static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
175static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177#ifdef CONFIG_PROC_FS
178static int procmpt_summary_read(char *buf, char **start, off_t offset,
179 int request, int *eof, void *data);
180static int procmpt_version_read(char *buf, char **start, off_t offset,
181 int request, int *eof, void *data);
182static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
183 int request, int *eof, void *data);
184#endif
185static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
186
187//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
188static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700189static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700191static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600192static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700193static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700194static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int __init fusion_init (void);
198static void __exit fusion_exit (void);
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define CHIPREG_READ32(addr) readl_relaxed(addr)
201#define CHIPREG_READ32_dmasync(addr) readl(addr)
202#define CHIPREG_WRITE32(addr,val) writel(val, addr)
203#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
204#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
205
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600206static void
207pci_disable_io_access(struct pci_dev *pdev)
208{
209 u16 command_reg;
210
211 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
212 command_reg &= ~1;
213 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
214}
215
216static void
217pci_enable_io_access(struct pci_dev *pdev)
218{
219 u16 command_reg;
220
221 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
222 command_reg |= 1;
223 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
224}
225
James Bottomleydb47c2d2007-07-28 13:40:21 -0400226static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
227{
228 int ret = param_set_int(val, kp);
229 MPT_ADAPTER *ioc;
230
231 if (ret)
232 return ret;
233
234 list_for_each_entry(ioc, &ioc_list, list)
235 ioc->debug_level = mpt_debug_level;
236 return 0;
237}
238
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530239/**
240 * mpt_get_cb_idx - obtain cb_idx for registered driver
241 * @dclass: class driver enum
242 *
243 * Returns cb_idx, or zero means it wasn't found
244 **/
245static u8
246mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
247{
248 u8 cb_idx;
249
250 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
251 if (MptDriverClass[cb_idx] == dclass)
252 return cb_idx;
253 return 0;
254}
255
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530256/**
257 * mpt_fault_reset_work - work performed on workq after ioc fault
258 * @work: input argument, used to derive ioc
259 *
260**/
261static void
262mpt_fault_reset_work(struct work_struct *work)
263{
264 MPT_ADAPTER *ioc =
265 container_of(work, MPT_ADAPTER, fault_reset_work.work);
266 u32 ioc_raw_state;
267 int rc;
268 unsigned long flags;
269
270 if (ioc->diagPending || !ioc->active)
271 goto out;
272
273 ioc_raw_state = mpt_GetIocState(ioc, 0);
274 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
275 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
276 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
277 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
278 ioc->name, __FUNCTION__);
279 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
280 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
281 __FUNCTION__, (rc == 0) ? "success" : "failed");
282 ioc_raw_state = mpt_GetIocState(ioc, 0);
283 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
284 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
285 "reset (%04xh)\n", ioc->name, ioc_raw_state &
286 MPI_DOORBELL_DATA_MASK);
287 }
288
289 out:
290 /*
291 * Take turns polling alternate controller
292 */
293 if (ioc->alt_ioc)
294 ioc = ioc->alt_ioc;
295
296 /* rearm the timer */
297 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
298 if (ioc->reset_work_q)
299 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
300 msecs_to_jiffies(MPT_POLLING_INTERVAL));
301 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
302}
303
304
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600305/*
306 * Process turbo (context) reply...
307 */
308static void
309mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
310{
311 MPT_FRAME_HDR *mf = NULL;
312 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530313 u16 req_idx = 0;
314 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600315
Prakash, Sathya436ace72007-07-24 15:42:08 +0530316 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600317 ioc->name, pa));
318
319 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
320 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
321 req_idx = pa & 0x0000FFFF;
322 cb_idx = (pa & 0x00FF0000) >> 16;
323 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
324 break;
325 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530326 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600327 /*
328 * Blind set of mf to NULL here was fatal
329 * after lan_reply says "freeme"
330 * Fix sort of combined with an optimization here;
331 * added explicit check for case where lan_reply
332 * was just returning 1 and doing nothing else.
333 * For this case skip the callback, but set up
334 * proper mf value first here:-)
335 */
336 if ((pa & 0x58000000) == 0x58000000) {
337 req_idx = pa & 0x0000FFFF;
338 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
339 mpt_free_msg_frame(ioc, mf);
340 mb();
341 return;
342 break;
343 }
344 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
345 break;
346 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530347 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600348 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
349 break;
350 default:
351 cb_idx = 0;
352 BUG();
353 }
354
355 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530356 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600357 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600358 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
359 __FUNCTION__, ioc->name, cb_idx);
360 goto out;
361 }
362
363 if (MptCallbacks[cb_idx](ioc, mf, mr))
364 mpt_free_msg_frame(ioc, mf);
365 out:
366 mb();
367}
368
369static void
370mpt_reply(MPT_ADAPTER *ioc, u32 pa)
371{
372 MPT_FRAME_HDR *mf;
373 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530374 u16 req_idx;
375 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600376 int freeme;
377
378 u32 reply_dma_low;
379 u16 ioc_stat;
380
381 /* non-TURBO reply! Hmmm, something may be up...
382 * Newest turbo reply mechanism; get address
383 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
384 */
385
386 /* Map DMA address of reply header to cpu address.
387 * pa is 32 bits - but the dma address may be 32 or 64 bits
388 * get offset based only only the low addresses
389 */
390
391 reply_dma_low = (pa <<= 1);
392 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
393 (reply_dma_low - ioc->reply_frames_low_dma));
394
395 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
396 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
397 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
398
Prakash, Sathya436ace72007-07-24 15:42:08 +0530399 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 -0600400 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600401 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600402
403 /* Check/log IOC log info
404 */
405 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
406 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
407 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
408 if (ioc->bus_type == FC)
409 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700410 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700411 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600412 else if (ioc->bus_type == SAS)
413 mpt_sas_log_info(ioc, log_info);
414 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600415
Eric Moorec6c727a2007-01-29 09:44:54 -0700416 if (ioc_stat & MPI_IOCSTATUS_MASK)
417 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600418
419 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530420 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600421 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600422 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
423 __FUNCTION__, ioc->name, cb_idx);
424 freeme = 0;
425 goto out;
426 }
427
428 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
429
430 out:
431 /* Flush (non-TURBO) reply with a WRITE! */
432 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
433
434 if (freeme)
435 mpt_free_msg_frame(ioc, mf);
436 mb();
437}
438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800440/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
442 * @irq: irq number (not used)
443 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 *
445 * This routine is registered via the request_irq() kernel API call,
446 * and handles all interrupts generated from a specific MPT adapter
447 * (also referred to as a IO Controller or IOC).
448 * This routine must clear the interrupt from the adapter and does
449 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200450 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 *
452 * This routine handles register-level access of the adapter but
453 * dispatches (calls) a protocol-specific callback routine to handle
454 * the protocol-specific details of the MPT request completion.
455 */
456static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100457mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600459 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600460 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
461
462 if (pa == 0xFFFFFFFF)
463 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 /*
466 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600468 do {
469 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600470 mpt_reply(ioc, pa);
471 else
472 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600473 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
474 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
476 return IRQ_HANDLED;
477}
478
479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800480/**
481 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 * @ioc: Pointer to MPT_ADAPTER structure
483 * @mf: Pointer to original MPT request frame
484 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
485 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800486 * MPT base driver's callback routine; all base driver
487 * "internal" request/reply processing is routed here.
488 * Currently used for EventNotification and EventAck handling.
489 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200490 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 * should be freed, or 0 if it shouldn't.
492 */
493static int
494mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
495{
496 int freereq = 1;
497 u8 func;
498
Prakash, Sathya436ace72007-07-24 15:42:08 +0530499 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
500#ifdef CONFIG_FUSION_LOGGING
501 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
502 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600503 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
504 ioc->name, mf));
505 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200507#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530510 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 ioc->name, func));
512
513 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
514 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
515 int evHandlers = 0;
516 int results;
517
518 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
519 if (results != evHandlers) {
520 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530521 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 ioc->name, evHandlers, results));
523 }
524
525 /*
526 * Hmmm... It seems that EventNotificationReply is an exception
527 * to the rule of one reply per request.
528 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200529 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200531 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530532 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200533 ioc->name, pEvReply));
534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536#ifdef CONFIG_PROC_FS
537// LogEvent(ioc, pEvReply);
538#endif
539
540 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530541 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700543 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 CONFIGPARMS *pCfg;
545 unsigned long flags;
546
Prakash, Sathya436ace72007-07-24 15:42:08 +0530547 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 ioc->name, mf, reply));
549
550 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
551
552 if (pCfg) {
553 /* disable timer and remove from linked list */
554 del_timer(&pCfg->timer);
555
556 spin_lock_irqsave(&ioc->FreeQlock, flags);
557 list_del(&pCfg->linkage);
558 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
559
560 /*
561 * If IOC Status is SUCCESS, save the header
562 * and set the status code to GOOD.
563 */
564 pCfg->status = MPT_CONFIG_ERROR;
565 if (reply) {
566 ConfigReply_t *pReply = (ConfigReply_t *)reply;
567 u16 status;
568
569 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600570 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
571 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
573 pCfg->status = status;
574 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200575 if ((pReply->Header.PageType &
576 MPI_CONFIG_PAGETYPE_MASK) ==
577 MPI_CONFIG_PAGETYPE_EXTENDED) {
578 pCfg->cfghdr.ehdr->ExtPageLength =
579 le16_to_cpu(pReply->ExtPageLength);
580 pCfg->cfghdr.ehdr->ExtPageType =
581 pReply->ExtPageType;
582 }
583 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
584
585 /* If this is a regular header, save PageLength. */
586 /* LMP Do this better so not using a reserved field! */
587 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
588 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
589 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
591 }
592
593 /*
594 * Wake up the original calling thread
595 */
596 pCfg->wait_done = 1;
597 wake_up(&mpt_waitq);
598 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200599 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
600 /* we should be always getting a reply frame */
601 memcpy(ioc->persist_reply_frame, reply,
602 min(MPT_DEFAULT_FRAME_SIZE,
603 4*reply->u.reply.MsgLength));
604 del_timer(&ioc->persist_timer);
605 ioc->persist_wait_done = 1;
606 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 } else {
608 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
609 ioc->name, func);
610 }
611
612 /*
613 * Conditionally tell caller to free the original
614 * EventNotification/EventAck/unexpected request frame!
615 */
616 return freereq;
617}
618
619/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
620/**
621 * mpt_register - Register protocol-specific main callback handler.
622 * @cbfunc: callback function pointer
623 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
624 *
625 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800626 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 * protocol-specific driver must do this before it will be able to
628 * use any IOC resources, such as obtaining request frames.
629 *
630 * NOTES: The SCSI protocol driver currently calls this routine thrice
631 * in order to register separate callbacks; one for "normal" SCSI IO;
632 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
633 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530634 * Returns u8 valued "handle" in the range (and S.O.D. order)
635 * {N,...,7,6,5,...,1} if successful.
636 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
637 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530639u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
641{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530642 u8 cb_idx;
643 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
645 /*
646 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
647 * (slot/handle 0 is reserved!)
648 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530649 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
650 if (MptCallbacks[cb_idx] == NULL) {
651 MptCallbacks[cb_idx] = cbfunc;
652 MptDriverClass[cb_idx] = dclass;
653 MptEvHandlers[cb_idx] = NULL;
654 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 break;
656 }
657 }
658
659 return last_drv_idx;
660}
661
662/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
663/**
664 * mpt_deregister - Deregister a protocol drivers resources.
665 * @cb_idx: previously registered callback handle
666 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800667 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 * module is unloaded.
669 */
670void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530671mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600673 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 MptCallbacks[cb_idx] = NULL;
675 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
676 MptEvHandlers[cb_idx] = NULL;
677
678 last_drv_idx++;
679 }
680}
681
682/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
683/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800684 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 * @cb_idx: previously registered (via mpt_register) callback handle
686 * @ev_cbfunc: callback function
687 *
688 * This routine can be called by one or more protocol-specific drivers
689 * if/when they choose to be notified of MPT events.
690 *
691 * Returns 0 for success.
692 */
693int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530694mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600696 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return -1;
698
699 MptEvHandlers[cb_idx] = ev_cbfunc;
700 return 0;
701}
702
703/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
704/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800705 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 * @cb_idx: previously registered callback handle
707 *
708 * Each protocol-specific driver should call this routine
709 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800710 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 */
712void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530713mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600715 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 return;
717
718 MptEvHandlers[cb_idx] = NULL;
719}
720
721/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
722/**
723 * mpt_reset_register - Register protocol-specific IOC reset handler.
724 * @cb_idx: previously registered (via mpt_register) callback handle
725 * @reset_func: reset function
726 *
727 * This routine can be called by one or more protocol-specific drivers
728 * if/when they choose to be notified of IOC resets.
729 *
730 * Returns 0 for success.
731 */
732int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530733mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530735 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return -1;
737
738 MptResetHandlers[cb_idx] = reset_func;
739 return 0;
740}
741
742/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
743/**
744 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
745 * @cb_idx: previously registered callback handle
746 *
747 * Each protocol-specific driver should call this routine
748 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800749 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 */
751void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530752mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530754 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return;
756
757 MptResetHandlers[cb_idx] = NULL;
758}
759
760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
761/**
762 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800763 * @dd_cbfunc: driver callbacks struct
764 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 */
766int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530767mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
769 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600770 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Eric Moore8d6d83e2007-09-14 18:47:40 -0600772 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400773 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
775 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
776
777 /* call per pci device probe entry point */
778 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600779 id = ioc->pcidev->driver ?
780 ioc->pcidev->driver->id_table : NULL;
781 if (dd_cbfunc->probe)
782 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
784
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400785 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786}
787
788/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
789/**
790 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800791 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 */
793void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530794mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
796 struct mpt_pci_driver *dd_cbfunc;
797 MPT_ADAPTER *ioc;
798
Eric Moore8d6d83e2007-09-14 18:47:40 -0600799 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return;
801
802 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
803
804 list_for_each_entry(ioc, &ioc_list, list) {
805 if (dd_cbfunc->remove)
806 dd_cbfunc->remove(ioc->pcidev);
807 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 MptDeviceDriverHandlers[cb_idx] = NULL;
810}
811
812
813/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
814/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800815 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530816 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 * @ioc: Pointer to MPT adapter structure
818 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800819 * Obtain an MPT request frame from the pool (of 1024) that are
820 * allocated per MPT adapter.
821 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 * Returns pointer to a MPT request frame or %NULL if none are available
823 * or IOC is not active.
824 */
825MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530826mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 MPT_FRAME_HDR *mf;
829 unsigned long flags;
830 u16 req_idx; /* Request index */
831
832 /* validate handle and ioc identifier */
833
834#ifdef MFCNT
835 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600836 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
837 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838#endif
839
840 /* If interrupts are not attached, do not return a request frame */
841 if (!ioc->active)
842 return NULL;
843
844 spin_lock_irqsave(&ioc->FreeQlock, flags);
845 if (!list_empty(&ioc->FreeQ)) {
846 int req_offset;
847
848 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
849 u.frame.linkage.list);
850 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200851 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530852 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
854 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500855 req_idx = req_offset / ioc->req_sz;
856 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600858 /* Default, will be changed if necessary in SG generation */
859 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860#ifdef MFCNT
861 ioc->mfcnt++;
862#endif
863 }
864 else
865 mf = NULL;
866 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
867
868#ifdef MFCNT
869 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600870 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
871 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
872 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 mfcounter++;
874 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600875 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
876 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877#endif
878
Eric Moore29dd3602007-09-14 18:46:51 -0600879 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
880 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 return mf;
882}
883
884/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
885/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800886 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530887 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 * @ioc: Pointer to MPT adapter structure
889 * @mf: Pointer to MPT request frame
890 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800891 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 * specific MPT adapter.
893 */
894void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530895mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
897 u32 mf_dma_addr;
898 int req_offset;
899 u16 req_idx; /* Request index */
900
901 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530902 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
904 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500905 req_idx = req_offset / ioc->req_sz;
906 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
908
Prakash, Sathya436ace72007-07-24 15:42:08 +0530909 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200911 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600912 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
913 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
914 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
916}
917
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530918/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800919 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530920 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530921 * @ioc: Pointer to MPT adapter structure
922 * @mf: Pointer to MPT request frame
923 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800924 * Send a protocol-specific MPT request frame to an IOC using
925 * hi-priority request queue.
926 *
927 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530928 * specific MPT adapter.
929 **/
930void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530931mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530932{
933 u32 mf_dma_addr;
934 int req_offset;
935 u16 req_idx; /* Request index */
936
937 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530938 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530939 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
940 req_idx = req_offset / ioc->req_sz;
941 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
942 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
943
944 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
945
946 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
947 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
948 ioc->name, mf_dma_addr, req_idx));
949 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
950}
951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
953/**
954 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
955 * @handle: Handle of registered MPT protocol driver
956 * @ioc: Pointer to MPT adapter structure
957 * @mf: Pointer to MPT request frame
958 *
959 * This routine places a MPT request frame back on the MPT adapter's
960 * FreeQ.
961 */
962void
963mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
964{
965 unsigned long flags;
966
967 /* Put Request back on FreeQ! */
968 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200969 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
971#ifdef MFCNT
972 ioc->mfcnt--;
973#endif
974 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
975}
976
977/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
978/**
979 * mpt_add_sge - Place a simple SGE at address pAddr.
980 * @pAddr: virtual address for SGE
981 * @flagslength: SGE flags and data transfer length
982 * @dma_addr: Physical address
983 *
984 * This routine places a MPT request frame back on the MPT adapter's
985 * FreeQ.
986 */
987void
988mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
989{
990 if (sizeof(dma_addr_t) == sizeof(u64)) {
991 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
992 u32 tmp = dma_addr & 0xFFFFFFFF;
993
994 pSge->FlagsLength = cpu_to_le32(flagslength);
995 pSge->Address.Low = cpu_to_le32(tmp);
996 tmp = (u32) ((u64)dma_addr >> 32);
997 pSge->Address.High = cpu_to_le32(tmp);
998
999 } else {
1000 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1001 pSge->FlagsLength = cpu_to_le32(flagslength);
1002 pSge->Address = cpu_to_le32(dma_addr);
1003 }
1004}
1005
1006/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1007/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001008 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301009 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 * @ioc: Pointer to MPT adapter structure
1011 * @reqBytes: Size of the request in bytes
1012 * @req: Pointer to MPT request frame
1013 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1014 *
1015 * This routine is used exclusively to send MptScsiTaskMgmt
1016 * requests since they are required to be sent via doorbell handshake.
1017 *
1018 * NOTE: It is the callers responsibility to byte-swap fields in the
1019 * request which are greater than 1 byte in size.
1020 *
1021 * Returns 0 for success, non-zero for failure.
1022 */
1023int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301024mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025{
Eric Moorecd2c6192007-01-29 09:47:47 -07001026 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 u8 *req_as_bytes;
1028 int ii;
1029
1030 /* State is known to be good upon entering
1031 * this function so issue the bus reset
1032 * request.
1033 */
1034
1035 /*
1036 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1037 * setting cb_idx/req_idx. But ONLY if this request
1038 * is in proper (pre-alloc'd) request buffer range...
1039 */
1040 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1041 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1042 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1043 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301044 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 }
1046
1047 /* Make sure there are no doorbells */
1048 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1051 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1052 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1053
1054 /* Wait for IOC doorbell int */
1055 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1056 return ii;
1057 }
1058
1059 /* Read doorbell and check for active bit */
1060 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1061 return -5;
1062
Eric Moore29dd3602007-09-14 18:46:51 -06001063 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001064 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1067
1068 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1069 return -2;
1070 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 /* Send request via doorbell handshake */
1073 req_as_bytes = (u8 *) req;
1074 for (ii = 0; ii < reqBytes/4; ii++) {
1075 u32 word;
1076
1077 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1078 (req_as_bytes[(ii*4) + 1] << 8) |
1079 (req_as_bytes[(ii*4) + 2] << 16) |
1080 (req_as_bytes[(ii*4) + 3] << 24));
1081 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1082 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1083 r = -3;
1084 break;
1085 }
1086 }
1087
1088 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1089 r = 0;
1090 else
1091 r = -4;
1092
1093 /* Make sure there are no doorbells */
1094 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return r;
1097}
1098
1099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1100/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001101 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001102 * @ioc: Pointer to MPT adapter structure
1103 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001104 * @sleepFlag: Specifies whether the process can sleep
1105 *
1106 * Provides mechanism for the host driver to control the IOC's
1107 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001108 *
1109 * Access Control Value - bits[15:12]
1110 * 0h Reserved
1111 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1112 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1113 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1114 *
1115 * Returns 0 for success, non-zero for failure.
1116 */
1117
1118static int
1119mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1120{
1121 int r = 0;
1122
1123 /* return if in use */
1124 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1125 & MPI_DOORBELL_ACTIVE)
1126 return -1;
1127
1128 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1129
1130 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1131 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1132 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1133 (access_control_value<<12)));
1134
1135 /* Wait for IOC to clear Doorbell Status bit */
1136 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1137 return -2;
1138 }else
1139 return 0;
1140}
1141
1142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1143/**
1144 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001145 * @ioc: Pointer to pointer to IOC adapter
1146 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001147 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001148 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001149 * Returns 0 for success, non-zero for failure.
1150 */
1151static int
1152mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1153{
1154 char *psge;
1155 int flags_length;
1156 u32 host_page_buffer_sz=0;
1157
1158 if(!ioc->HostPageBuffer) {
1159
1160 host_page_buffer_sz =
1161 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1162
1163 if(!host_page_buffer_sz)
1164 return 0; /* fw doesn't need any host buffers */
1165
1166 /* spin till we get enough memory */
1167 while(host_page_buffer_sz > 0) {
1168
1169 if((ioc->HostPageBuffer = pci_alloc_consistent(
1170 ioc->pcidev,
1171 host_page_buffer_sz,
1172 &ioc->HostPageBuffer_dma)) != NULL) {
1173
Prakash, Sathya436ace72007-07-24 15:42:08 +05301174 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001175 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001176 ioc->name, ioc->HostPageBuffer,
1177 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001178 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001179 ioc->alloc_total += host_page_buffer_sz;
1180 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1181 break;
1182 }
1183
1184 host_page_buffer_sz -= (4*1024);
1185 }
1186 }
1187
1188 if(!ioc->HostPageBuffer) {
1189 printk(MYIOC_s_ERR_FMT
1190 "Failed to alloc memory for host_page_buffer!\n",
1191 ioc->name);
1192 return -999;
1193 }
1194
1195 psge = (char *)&ioc_init->HostPageBufferSGE;
1196 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1197 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1198 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1199 MPI_SGE_FLAGS_HOST_TO_IOC |
1200 MPI_SGE_FLAGS_END_OF_BUFFER;
1201 if (sizeof(dma_addr_t) == sizeof(u64)) {
1202 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1203 }
1204 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1205 flags_length |= ioc->HostPageBuffer_sz;
1206 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1207 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1208
1209return 0;
1210}
1211
1212/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1213/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001214 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 * @iocid: IOC unique identifier (integer)
1216 * @iocpp: Pointer to pointer to IOC adapter
1217 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001218 * Given a unique IOC identifier, set pointer to the associated MPT
1219 * adapter structure.
1220 *
1221 * Returns iocid and sets iocpp if iocid is found.
1222 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 */
1224int
1225mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1226{
1227 MPT_ADAPTER *ioc;
1228
1229 list_for_each_entry(ioc,&ioc_list,list) {
1230 if (ioc->id == iocid) {
1231 *iocpp =ioc;
1232 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001235
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 *iocpp = NULL;
1237 return -1;
1238}
1239
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301240/**
1241 * mpt_get_product_name - returns product string
1242 * @vendor: pci vendor id
1243 * @device: pci device id
1244 * @revision: pci revision id
1245 * @prod_name: string returned
1246 *
1247 * Returns product string displayed when driver loads,
1248 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1249 *
1250 **/
1251static void
1252mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1253{
1254 char *product_str = NULL;
1255
1256 if (vendor == PCI_VENDOR_ID_BROCADE) {
1257 switch (device)
1258 {
1259 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1260 switch (revision)
1261 {
1262 case 0x00:
1263 product_str = "BRE040 A0";
1264 break;
1265 case 0x01:
1266 product_str = "BRE040 A1";
1267 break;
1268 default:
1269 product_str = "BRE040";
1270 break;
1271 }
1272 break;
1273 }
1274 goto out;
1275 }
1276
1277 switch (device)
1278 {
1279 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1280 product_str = "LSIFC909 B1";
1281 break;
1282 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1283 product_str = "LSIFC919 B0";
1284 break;
1285 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1286 product_str = "LSIFC929 B0";
1287 break;
1288 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1289 if (revision < 0x80)
1290 product_str = "LSIFC919X A0";
1291 else
1292 product_str = "LSIFC919XL A1";
1293 break;
1294 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1295 if (revision < 0x80)
1296 product_str = "LSIFC929X A0";
1297 else
1298 product_str = "LSIFC929XL A1";
1299 break;
1300 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1301 product_str = "LSIFC939X A1";
1302 break;
1303 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1304 product_str = "LSIFC949X A1";
1305 break;
1306 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1307 switch (revision)
1308 {
1309 case 0x00:
1310 product_str = "LSIFC949E A0";
1311 break;
1312 case 0x01:
1313 product_str = "LSIFC949E A1";
1314 break;
1315 default:
1316 product_str = "LSIFC949E";
1317 break;
1318 }
1319 break;
1320 case MPI_MANUFACTPAGE_DEVID_53C1030:
1321 switch (revision)
1322 {
1323 case 0x00:
1324 product_str = "LSI53C1030 A0";
1325 break;
1326 case 0x01:
1327 product_str = "LSI53C1030 B0";
1328 break;
1329 case 0x03:
1330 product_str = "LSI53C1030 B1";
1331 break;
1332 case 0x07:
1333 product_str = "LSI53C1030 B2";
1334 break;
1335 case 0x08:
1336 product_str = "LSI53C1030 C0";
1337 break;
1338 case 0x80:
1339 product_str = "LSI53C1030T A0";
1340 break;
1341 case 0x83:
1342 product_str = "LSI53C1030T A2";
1343 break;
1344 case 0x87:
1345 product_str = "LSI53C1030T A3";
1346 break;
1347 case 0xc1:
1348 product_str = "LSI53C1020A A1";
1349 break;
1350 default:
1351 product_str = "LSI53C1030";
1352 break;
1353 }
1354 break;
1355 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1356 switch (revision)
1357 {
1358 case 0x03:
1359 product_str = "LSI53C1035 A2";
1360 break;
1361 case 0x04:
1362 product_str = "LSI53C1035 B0";
1363 break;
1364 default:
1365 product_str = "LSI53C1035";
1366 break;
1367 }
1368 break;
1369 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1370 switch (revision)
1371 {
1372 case 0x00:
1373 product_str = "LSISAS1064 A1";
1374 break;
1375 case 0x01:
1376 product_str = "LSISAS1064 A2";
1377 break;
1378 case 0x02:
1379 product_str = "LSISAS1064 A3";
1380 break;
1381 case 0x03:
1382 product_str = "LSISAS1064 A4";
1383 break;
1384 default:
1385 product_str = "LSISAS1064";
1386 break;
1387 }
1388 break;
1389 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1390 switch (revision)
1391 {
1392 case 0x00:
1393 product_str = "LSISAS1064E A0";
1394 break;
1395 case 0x01:
1396 product_str = "LSISAS1064E B0";
1397 break;
1398 case 0x02:
1399 product_str = "LSISAS1064E B1";
1400 break;
1401 case 0x04:
1402 product_str = "LSISAS1064E B2";
1403 break;
1404 case 0x08:
1405 product_str = "LSISAS1064E B3";
1406 break;
1407 default:
1408 product_str = "LSISAS1064E";
1409 break;
1410 }
1411 break;
1412 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1413 switch (revision)
1414 {
1415 case 0x00:
1416 product_str = "LSISAS1068 A0";
1417 break;
1418 case 0x01:
1419 product_str = "LSISAS1068 B0";
1420 break;
1421 case 0x02:
1422 product_str = "LSISAS1068 B1";
1423 break;
1424 default:
1425 product_str = "LSISAS1068";
1426 break;
1427 }
1428 break;
1429 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1430 switch (revision)
1431 {
1432 case 0x00:
1433 product_str = "LSISAS1068E A0";
1434 break;
1435 case 0x01:
1436 product_str = "LSISAS1068E B0";
1437 break;
1438 case 0x02:
1439 product_str = "LSISAS1068E B1";
1440 break;
1441 case 0x04:
1442 product_str = "LSISAS1068E B2";
1443 break;
1444 case 0x08:
1445 product_str = "LSISAS1068E B3";
1446 break;
1447 default:
1448 product_str = "LSISAS1068E";
1449 break;
1450 }
1451 break;
1452 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1453 switch (revision)
1454 {
1455 case 0x00:
1456 product_str = "LSISAS1078 A0";
1457 break;
1458 case 0x01:
1459 product_str = "LSISAS1078 B0";
1460 break;
1461 case 0x02:
1462 product_str = "LSISAS1078 C0";
1463 break;
1464 case 0x03:
1465 product_str = "LSISAS1078 C1";
1466 break;
1467 case 0x04:
1468 product_str = "LSISAS1078 C2";
1469 break;
1470 default:
1471 product_str = "LSISAS1078";
1472 break;
1473 }
1474 break;
1475 }
1476
1477 out:
1478 if (product_str)
1479 sprintf(prod_name, "%s", product_str);
1480}
1481
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301482/**
1483 * mpt_mapresources - map in memory mapped io
1484 * @ioc: Pointer to pointer to IOC adapter
1485 *
1486 **/
1487static int
1488mpt_mapresources(MPT_ADAPTER *ioc)
1489{
1490 u8 __iomem *mem;
1491 int ii;
1492 unsigned long mem_phys;
1493 unsigned long port;
1494 u32 msize;
1495 u32 psize;
1496 u8 revision;
1497 int r = -ENODEV;
1498 struct pci_dev *pdev;
1499
1500 pdev = ioc->pcidev;
1501 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1502 if (pci_enable_device_mem(pdev)) {
1503 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1504 "failed\n", ioc->name);
1505 return r;
1506 }
1507 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1508 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1509 "MEM failed\n", ioc->name);
1510 return r;
1511 }
1512
1513 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1514
1515 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
1516 && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
1517 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1518 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1519 ioc->name));
1520 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
1521 && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
1522 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1523 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1524 ioc->name));
1525 } else {
1526 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1527 ioc->name, pci_name(pdev));
1528 pci_release_selected_regions(pdev, ioc->bars);
1529 return r;
1530 }
1531
1532 mem_phys = msize = 0;
1533 port = psize = 0;
1534 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1535 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1536 if (psize)
1537 continue;
1538 /* Get I/O space! */
1539 port = pci_resource_start(pdev, ii);
1540 psize = pci_resource_len(pdev, ii);
1541 } else {
1542 if (msize)
1543 continue;
1544 /* Get memmap */
1545 mem_phys = pci_resource_start(pdev, ii);
1546 msize = pci_resource_len(pdev, ii);
1547 }
1548 }
1549 ioc->mem_size = msize;
1550
1551 mem = NULL;
1552 /* Get logical ptr for PciMem0 space */
1553 /*mem = ioremap(mem_phys, msize);*/
1554 mem = ioremap(mem_phys, msize);
1555 if (mem == NULL) {
1556 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1557 " memory!\n", ioc->name);
1558 return -EINVAL;
1559 }
1560 ioc->memmap = mem;
1561 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1562 ioc->name, mem, mem_phys));
1563
1564 ioc->mem_phys = mem_phys;
1565 ioc->chip = (SYSIF_REGS __iomem *)mem;
1566
1567 /* Save Port IO values in case we need to do downloadboot */
1568 ioc->pio_mem_phys = port;
1569 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1570
1571 return 0;
1572}
1573
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001575/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001576 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001578 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 *
1580 * This routine performs all the steps necessary to bring the IOC of
1581 * a MPT adapter to a OPERATIONAL state. This includes registering
1582 * memory regions, registering the interrupt, and allocating request
1583 * and reply memory pools.
1584 *
1585 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1586 * MPT adapter.
1587 *
1588 * Returns 0 for success, non-zero for failure.
1589 *
1590 * TODO: Add support for polled controllers
1591 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001592int
1593mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594{
1595 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301596 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 u8 revision;
1599 u8 pcixcmd;
1600 static int mpt_ids = 0;
1601#ifdef CONFIG_PROC_FS
1602 struct proc_dir_entry *dent, *ent;
1603#endif
1604
Jesper Juhl56876192007-08-10 14:50:51 -07001605 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1606 if (ioc == NULL) {
1607 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1608 return -ENOMEM;
1609 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301610
Eric Moore29dd3602007-09-14 18:46:51 -06001611 ioc->id = mpt_ids++;
1612 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001613
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301614 /*
1615 * set initial debug level
1616 * (refer to mptdebug.h)
1617 *
1618 */
1619 ioc->debug_level = mpt_debug_level;
1620 if (mpt_debug_level)
1621 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301622
Eric Moore29dd3602007-09-14 18:46:51 -06001623 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001624
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301625 ioc->pcidev = pdev;
1626 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001627 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 return r;
1629 }
1630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 ioc->alloc_total = sizeof(MPT_ADAPTER);
1632 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1633 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001634
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 ioc->pcidev = pdev;
1636 ioc->diagPending = 0;
1637 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001638 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
1640 /* Initialize the event logging.
1641 */
1642 ioc->eventTypes = 0; /* None */
1643 ioc->eventContext = 0;
1644 ioc->eventLogSize = 0;
1645 ioc->events = NULL;
1646
1647#ifdef MFCNT
1648 ioc->mfcnt = 0;
1649#endif
1650
1651 ioc->cached_fw = NULL;
1652
1653 /* Initilize SCSI Config Data structure
1654 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001655 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
1657 /* Initialize the running configQ head.
1658 */
1659 INIT_LIST_HEAD(&ioc->configQ);
1660
Michael Reed05e8ec12006-01-13 14:31:54 -06001661 /* Initialize the fc rport list head.
1662 */
1663 INIT_LIST_HEAD(&ioc->fc_rports);
1664
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 /* Find lookup slot. */
1666 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001667
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301668
1669 /* Initialize workqueue */
1670 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1671 spin_lock_init(&ioc->fault_reset_work_lock);
1672
1673 snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id);
1674 ioc->reset_work_q =
1675 create_singlethread_workqueue(ioc->reset_work_q_name);
1676 if (!ioc->reset_work_q) {
1677 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1678 ioc->name);
1679 pci_release_selected_regions(pdev, ioc->bars);
1680 kfree(ioc);
1681 return -ENOMEM;
1682 }
1683
Eric Moore29dd3602007-09-14 18:46:51 -06001684 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1685 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301687 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1688 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1689
1690 switch (pdev->device)
1691 {
1692 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1693 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1694 ioc->errata_flag_1064 = 1;
1695 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1696 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1697 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1698 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301700 break;
1701
1702 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 /* 929X Chip Fix. Set Split transactions level
1705 * for PCIX. Set MOST bits to zero.
1706 */
1707 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1708 pcixcmd &= 0x8F;
1709 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1710 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 /* 929XL Chip Fix. Set MMRBC to 0x08.
1712 */
1713 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1714 pcixcmd |= 0x08;
1715 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1716 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301718 break;
1719
1720 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 /* 919X Chip Fix. Set Split transactions level
1722 * for PCIX. Set MOST bits to zero.
1723 */
1724 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1725 pcixcmd &= 0x8F;
1726 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001727 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301728 break;
1729
1730 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 /* 1030 Chip Fix. Disable Split transactions
1732 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1733 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 if (revision < C0_1030) {
1735 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1736 pcixcmd &= 0x8F;
1737 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1738 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301739
1740 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001741 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301742 break;
1743
1744 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1745 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001746 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301747
1748 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1749 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1750 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001751 ioc->bus_type = SAS;
1752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
James Bottomley27898982008-07-10 22:10:55 -05001754 if (mpt_msi_enable == -1) {
1755 /* Enable on SAS, disable on FC and SPI */
1756 if (ioc->bus_type == SAS)
1757 ioc->msi_enable = 1;
1758 else
1759 ioc->msi_enable = 0;
1760 } else
1761 /* follow flag: 0 - disable; 1 - enable */
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301762 ioc->msi_enable = mpt_msi_enable;
1763
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001764 if (ioc->errata_flag_1064)
1765 pci_disable_io_access(pdev);
1766
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 spin_lock_init(&ioc->FreeQlock);
1768
1769 /* Disable all! */
1770 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1771 ioc->active = 0;
1772 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1773
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301774 /* Set IOC ptr in the pcidev's driver data. */
1775 pci_set_drvdata(ioc->pcidev, ioc);
1776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 /* Set lookup ptr. */
1778 list_add_tail(&ioc->list, &ioc_list);
1779
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001780 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 */
1782 mpt_detect_bound_ports(ioc, pdev);
1783
James Bottomleyc92f2222006-03-01 09:02:49 -06001784 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1785 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001786 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1787 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001788
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001790 if (ioc->alt_ioc)
1791 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301792 iounmap(ioc->memmap);
1793 if (r != -5)
1794 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301795
1796 destroy_workqueue(ioc->reset_work_q);
1797 ioc->reset_work_q = NULL;
1798
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 kfree(ioc);
1800 pci_set_drvdata(pdev, NULL);
1801 return r;
1802 }
1803
1804 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001805 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301806 if(MptDeviceDriverHandlers[cb_idx] &&
1807 MptDeviceDriverHandlers[cb_idx]->probe) {
1808 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 }
1810 }
1811
1812#ifdef CONFIG_PROC_FS
1813 /*
1814 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1815 */
1816 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1817 if (dent) {
1818 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1819 if (ent) {
1820 ent->read_proc = procmpt_iocinfo_read;
1821 ent->data = ioc;
1822 }
1823 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1824 if (ent) {
1825 ent->read_proc = procmpt_summary_read;
1826 ent->data = ioc;
1827 }
1828 }
1829#endif
1830
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301831 if (!ioc->alt_ioc)
1832 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1833 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 return 0;
1836}
1837
1838/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001839/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001840 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 */
1843
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001844void
1845mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846{
1847 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1848 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301849 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301850 unsigned long flags;
1851 struct workqueue_struct *wq;
1852
1853 /*
1854 * Stop polling ioc for fault condition
1855 */
1856 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
1857 wq = ioc->reset_work_q;
1858 ioc->reset_work_q = NULL;
1859 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
1860 cancel_delayed_work(&ioc->fault_reset_work);
1861 destroy_workqueue(wq);
1862
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863
1864 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1865 remove_proc_entry(pname, NULL);
1866 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1867 remove_proc_entry(pname, NULL);
1868 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1869 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001870
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001872 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301873 if(MptDeviceDriverHandlers[cb_idx] &&
1874 MptDeviceDriverHandlers[cb_idx]->remove) {
1875 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 }
1877 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001878
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 /* Disable interrupts! */
1880 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1881
1882 ioc->active = 0;
1883 synchronize_irq(pdev->irq);
1884
1885 /* Clear any lingering interrupt */
1886 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1887
1888 CHIPREG_READ32(&ioc->chip->IntStatus);
1889
1890 mpt_adapter_dispose(ioc);
1891
1892 pci_set_drvdata(pdev, NULL);
1893}
1894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895/**************************************************************************
1896 * Power Management
1897 */
1898#ifdef CONFIG_PM
1899/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001900/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001901 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001902 * @pdev: Pointer to pci_dev structure
1903 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001905int
1906mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907{
1908 u32 device_state;
1909 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301911 device_state = pci_choose_state(pdev, state);
1912 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
1913 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1914 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
1916 /* put ioc into READY_STATE */
1917 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1918 printk(MYIOC_s_ERR_FMT
1919 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1920 }
1921
1922 /* disable interrupts */
1923 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1924 ioc->active = 0;
1925
1926 /* Clear any lingering interrupt */
1927 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1928
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301929 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05001930 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301931 pci_disable_msi(ioc->pcidev);
1932 ioc->pci_irq = -1;
1933 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301935 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 return 0;
1938}
1939
1940/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001941/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001942 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001943 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001945int
1946mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947{
1948 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1949 u32 device_state = pdev->current_state;
1950 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301951 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001952
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301953 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
1954 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1955 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301957 pci_set_power_state(pdev, PCI_D0);
1958 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301960 ioc->pcidev = pdev;
1961 err = mpt_mapresources(ioc);
1962 if (err)
1963 return err;
1964
1965 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1966 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1967 CHIPREG_READ32(&ioc->chip->Doorbell));
1968
1969 /*
1970 * Errata workaround for SAS pci express:
1971 * Upon returning to the D0 state, the contents of the doorbell will be
1972 * stale data, and this will incorrectly signal to the host driver that
1973 * the firmware is ready to process mpt commands. The workaround is
1974 * to issue a diagnostic reset.
1975 */
1976 if (ioc->bus_type == SAS && (pdev->device ==
1977 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
1978 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
1979 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
1980 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
1981 ioc->name);
1982 goto out;
1983 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
1986 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301987 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
1988 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1989 CAN_SLEEP);
1990 if (recovery_state != 0)
1991 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
1992 "error:[%x]\n", ioc->name, recovery_state);
1993 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301995 "pci-resume: success\n", ioc->name);
1996 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301998
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999}
2000#endif
2001
James Bottomley4ff42a62006-05-17 18:06:52 -05002002static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302003mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002004{
2005 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2006 ioc->bus_type != SPI) ||
2007 (MptDriverClass[index] == MPTFC_DRIVER &&
2008 ioc->bus_type != FC) ||
2009 (MptDriverClass[index] == MPTSAS_DRIVER &&
2010 ioc->bus_type != SAS))
2011 /* make sure we only call the relevant reset handler
2012 * for the bus */
2013 return 0;
2014 return (MptResetHandlers[index])(ioc, reset_phase);
2015}
2016
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002018/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2020 * @ioc: Pointer to MPT adapter structure
2021 * @reason: Event word / reason
2022 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2023 *
2024 * This routine performs all the steps necessary to bring the IOC
2025 * to a OPERATIONAL state.
2026 *
2027 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2028 * MPT adapter.
2029 *
2030 * Returns:
2031 * 0 for success
2032 * -1 if failed to get board READY
2033 * -2 if READY but IOCFacts Failed
2034 * -3 if READY but PrimeIOCFifos Failed
2035 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302036 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302037 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 */
2039static int
2040mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2041{
2042 int hard_reset_done = 0;
2043 int alt_ioc_ready = 0;
2044 int hard;
2045 int rc=0;
2046 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302047 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 int handlers;
2049 int ret = 0;
2050 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002051 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302052 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
Eric Moore29dd3602007-09-14 18:46:51 -06002054 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2055 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056
2057 /* Disable reply interrupts (also blocks FreeQ) */
2058 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2059 ioc->active = 0;
2060
2061 if (ioc->alt_ioc) {
2062 if (ioc->alt_ioc->active)
2063 reset_alt_ioc_active = 1;
2064
2065 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2066 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2067 ioc->alt_ioc->active = 0;
2068 }
2069
2070 hard = 1;
2071 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2072 hard = 0;
2073
2074 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2075 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002076 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2077 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
2079 if (reset_alt_ioc_active && ioc->alt_ioc) {
2080 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002081 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2082 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002083 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 ioc->alt_ioc->active = 1;
2085 }
2086
2087 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002088 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 }
2090 return -1;
2091 }
2092
2093 /* hard_reset_done = 0 if a soft reset was performed
2094 * and 1 if a hard reset was performed.
2095 */
2096 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2097 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2098 alt_ioc_ready = 1;
2099 else
Eric Moore29dd3602007-09-14 18:46:51 -06002100 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 }
2102
2103 for (ii=0; ii<5; ii++) {
2104 /* Get IOC facts! Allow 5 retries */
2105 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2106 break;
2107 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002108
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
2110 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002111 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2112 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 ret = -2;
2114 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2115 MptDisplayIocCapabilities(ioc);
2116 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002117
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 if (alt_ioc_ready) {
2119 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302120 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002121 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 /* Retry - alt IOC was initialized once
2123 */
2124 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2125 }
2126 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302127 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002128 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 alt_ioc_ready = 0;
2130 reset_alt_ioc_active = 0;
2131 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2132 MptDisplayIocCapabilities(ioc->alt_ioc);
2133 }
2134 }
2135
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302136 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2137 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2138 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2139 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2140 IORESOURCE_IO);
2141 if (pci_enable_device(ioc->pcidev))
2142 return -5;
2143 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2144 "mpt"))
2145 return -5;
2146 }
2147
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002148 /*
2149 * Device is reset now. It must have de-asserted the interrupt line
2150 * (if it was asserted) and it should be safe to register for the
2151 * interrupt now.
2152 */
2153 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2154 ioc->pci_irq = -1;
2155 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302156 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002157 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002158 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302159 else
2160 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002161 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002162 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002163 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002164 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002165 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302166 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002167 pci_disable_msi(ioc->pcidev);
2168 return -EBUSY;
2169 }
2170 irq_allocated = 1;
2171 ioc->pci_irq = ioc->pcidev->irq;
2172 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002173 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2174 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002175 }
2176 }
2177
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 /* Prime reply & request queues!
2179 * (mucho alloc's) Must be done prior to
2180 * init as upper addresses are needed for init.
2181 * If fails, continue with alt-ioc processing
2182 */
2183 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2184 ret = -3;
2185
2186 /* May need to check/upload firmware & data here!
2187 * If fails, continue with alt-ioc processing
2188 */
2189 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2190 ret = -4;
2191// NEW!
2192 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002193 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2194 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 alt_ioc_ready = 0;
2196 reset_alt_ioc_active = 0;
2197 }
2198
2199 if (alt_ioc_ready) {
2200 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2201 alt_ioc_ready = 0;
2202 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002203 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2204 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 }
2206 }
2207
2208 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2209 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302210 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002211 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
2213 /* Controller is not operational, cannot do upload
2214 */
2215 if (ret == 0) {
2216 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002217 if (rc == 0) {
2218 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2219 /*
2220 * Maintain only one pointer to FW memory
2221 * so there will not be two attempt to
2222 * downloadboot onboard dual function
2223 * chips (mpt_adapter_disable,
2224 * mpt_diag_reset)
2225 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302226 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002227 "mpt_upload: alt_%s has cached_fw=%p \n",
2228 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302229 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002230 }
2231 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002232 printk(MYIOC_s_WARN_FMT
2233 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302234 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 }
2237 }
2238 }
2239
2240 if (ret == 0) {
2241 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002242 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 ioc->active = 1;
2244 }
2245
2246 if (reset_alt_ioc_active && ioc->alt_ioc) {
2247 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002248 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2249 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002250 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 ioc->alt_ioc->active = 1;
2252 }
2253
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002254 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 * and EventAck handling.
2256 */
2257 if ((ret == 0) && (!ioc->facts.EventState))
2258 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2259
2260 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2261 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2262
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002263 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2265 * recursive scenario; GetLanConfigPages times out, timer expired
2266 * routine calls HardResetHandler, which calls into here again,
2267 * and we try GetLanConfigPages again...
2268 */
2269 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002270
2271 /*
2272 * Initalize link list for inactive raid volumes.
2273 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002274 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002275 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2276
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002277 if (ioc->bus_type == SAS) {
2278
2279 /* clear persistency table */
2280 if(ioc->facts.IOCExceptions &
2281 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2282 ret = mptbase_sas_persist_operation(ioc,
2283 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2284 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002285 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002286 }
2287
2288 /* Find IM volumes
2289 */
2290 mpt_findImVolumes(ioc);
2291
2292 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2294 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2295 /*
2296 * Pre-fetch the ports LAN MAC address!
2297 * (LANPage1_t stuff)
2298 */
2299 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302300 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2301 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002302 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2303 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302304
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 }
2306 } else {
2307 /* Get NVRAM and adapter maximums from SPP 0 and 2
2308 */
2309 mpt_GetScsiPortSettings(ioc, 0);
2310
2311 /* Get version and length of SDP 1
2312 */
2313 mpt_readScsiDevicePageHeaders(ioc, 0);
2314
2315 /* Find IM volumes
2316 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002317 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 mpt_findImVolumes(ioc);
2319
2320 /* Check, and possibly reset, the coalescing value
2321 */
2322 mpt_read_ioc_pg_1(ioc);
2323
2324 mpt_read_ioc_pg_4(ioc);
2325 }
2326
2327 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302328 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 }
2330
2331 /*
2332 * Call each currently registered protocol IOC reset handler
2333 * with post-reset indication.
2334 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2335 * MptResetHandlers[] registered yet.
2336 */
2337 if (hard_reset_done) {
2338 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302339 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2340 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302341 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002342 "Calling IOC post_reset handler #%d\n",
2343 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302344 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 handlers++;
2346 }
2347
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302348 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302349 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002350 "Calling IOC post_reset handler #%d\n",
2351 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302352 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 handlers++;
2354 }
2355 }
2356 /* FIXME? Examine results here? */
2357 }
2358
Eric Moore0ccdb002006-07-11 17:33:13 -06002359 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002360 if ((ret != 0) && irq_allocated) {
2361 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302362 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002363 pci_disable_msi(ioc->pcidev);
2364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 return ret;
2366}
2367
2368/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002369/**
2370 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 * @ioc: Pointer to MPT adapter structure
2372 * @pdev: Pointer to (struct pci_dev) structure
2373 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002374 * Search for PCI bus/dev_function which matches
2375 * PCI bus/dev_function (+/-1) for newly discovered 929,
2376 * 929X, 1030 or 1035.
2377 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2379 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2380 */
2381static void
2382mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2383{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002384 struct pci_dev *peer=NULL;
2385 unsigned int slot = PCI_SLOT(pdev->devfn);
2386 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 MPT_ADAPTER *ioc_srch;
2388
Prakash, Sathya436ace72007-07-24 15:42:08 +05302389 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002390 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002391 ioc->name, pci_name(pdev), pdev->bus->number,
2392 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002393
2394 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2395 if (!peer) {
2396 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2397 if (!peer)
2398 return;
2399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
2401 list_for_each_entry(ioc_srch, &ioc_list, list) {
2402 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002403 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 /* Paranoia checks */
2405 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002406 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002407 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 break;
2409 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002410 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002411 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 break;
2413 }
Eric Moore29dd3602007-09-14 18:46:51 -06002414 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002415 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 ioc_srch->alt_ioc = ioc;
2417 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 }
2419 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002420 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421}
2422
2423/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002424/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002426 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 */
2428static void
2429mpt_adapter_disable(MPT_ADAPTER *ioc)
2430{
2431 int sz;
2432 int ret;
2433
2434 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302435 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
2436 "adapter\n", __FUNCTION__, ioc->name));
2437 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2438 ioc->cached_fw, CAN_SLEEP)) < 0) {
2439 printk(MYIOC_s_WARN_FMT
2440 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002441 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 }
2443 }
2444
2445 /* Disable adapter interrupts! */
2446 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2447 ioc->active = 0;
2448 /* Clear any lingering interrupt */
2449 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2450
2451 if (ioc->alloc != NULL) {
2452 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002453 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2454 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 pci_free_consistent(ioc->pcidev, sz,
2456 ioc->alloc, ioc->alloc_dma);
2457 ioc->reply_frames = NULL;
2458 ioc->req_frames = NULL;
2459 ioc->alloc = NULL;
2460 ioc->alloc_total -= sz;
2461 }
2462
2463 if (ioc->sense_buf_pool != NULL) {
2464 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2465 pci_free_consistent(ioc->pcidev, sz,
2466 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2467 ioc->sense_buf_pool = NULL;
2468 ioc->alloc_total -= sz;
2469 }
2470
2471 if (ioc->events != NULL){
2472 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2473 kfree(ioc->events);
2474 ioc->events = NULL;
2475 ioc->alloc_total -= sz;
2476 }
2477
Prakash, Sathya984621b2008-01-11 14:42:17 +05302478 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002480 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002481 mpt_inactive_raid_list_free(ioc);
2482 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002483 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002484 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002485 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
2487 if (ioc->spi_data.pIocPg4 != NULL) {
2488 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302489 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 ioc->spi_data.pIocPg4,
2491 ioc->spi_data.IocPg4_dma);
2492 ioc->spi_data.pIocPg4 = NULL;
2493 ioc->alloc_total -= sz;
2494 }
2495
2496 if (ioc->ReqToChain != NULL) {
2497 kfree(ioc->ReqToChain);
2498 kfree(ioc->RequestNB);
2499 ioc->ReqToChain = NULL;
2500 }
2501
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002502 kfree(ioc->ChainToChain);
2503 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002504
2505 if (ioc->HostPageBuffer != NULL) {
2506 if((ret = mpt_host_page_access_control(ioc,
2507 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002508 printk(MYIOC_s_ERR_FMT
2509 "host page buffers free failed (%d)!\n",
2510 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002511 }
Eric Moore29dd3602007-09-14 18:46:51 -06002512 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002513 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2514 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002515 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002516 ioc->HostPageBuffer = NULL;
2517 ioc->HostPageBuffer_sz = 0;
2518 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520}
2521
2522/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002523/**
2524 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 * @ioc: Pointer to MPT adapter structure
2526 *
2527 * This routine unregisters h/w resources and frees all alloc'd memory
2528 * associated with a MPT adapter structure.
2529 */
2530static void
2531mpt_adapter_dispose(MPT_ADAPTER *ioc)
2532{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002533 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002535 if (ioc == NULL)
2536 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002538 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002540 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002542 if (ioc->pci_irq != -1) {
2543 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302544 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002545 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002546 ioc->pci_irq = -1;
2547 }
2548
2549 if (ioc->memmap != NULL) {
2550 iounmap(ioc->memmap);
2551 ioc->memmap = NULL;
2552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302554 pci_disable_device(ioc->pcidev);
2555 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2556
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002558 if (ioc->mtrr_reg > 0) {
2559 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002560 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562#endif
2563
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002564 /* Zap the adapter lookup ptr! */
2565 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002567 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002568 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2569 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002570
2571 if (ioc->alt_ioc)
2572 ioc->alt_ioc->alt_ioc = NULL;
2573
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002574 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575}
2576
2577/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002578/**
2579 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 * @ioc: Pointer to MPT adapter structure
2581 */
2582static void
2583MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2584{
2585 int i = 0;
2586
2587 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302588 if (ioc->prod_name)
2589 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 printk("Capabilities={");
2591
2592 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2593 printk("Initiator");
2594 i++;
2595 }
2596
2597 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2598 printk("%sTarget", i ? "," : "");
2599 i++;
2600 }
2601
2602 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2603 printk("%sLAN", i ? "," : "");
2604 i++;
2605 }
2606
2607#if 0
2608 /*
2609 * This would probably evoke more questions than it's worth
2610 */
2611 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2612 printk("%sLogBusAddr", i ? "," : "");
2613 i++;
2614 }
2615#endif
2616
2617 printk("}\n");
2618}
2619
2620/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002621/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2623 * @ioc: Pointer to MPT_ADAPTER structure
2624 * @force: Force hard KickStart of IOC
2625 * @sleepFlag: Specifies whether the process can sleep
2626 *
2627 * Returns:
2628 * 1 - DIAG reset and READY
2629 * 0 - READY initially OR soft reset and READY
2630 * -1 - Any failure on KickStart
2631 * -2 - Msg Unit Reset Failed
2632 * -3 - IO Unit Reset Failed
2633 * -4 - IOC owned by a PEER
2634 */
2635static int
2636MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2637{
2638 u32 ioc_state;
2639 int statefault = 0;
2640 int cntdn;
2641 int hard_reset_done = 0;
2642 int r;
2643 int ii;
2644 int whoinit;
2645
2646 /* Get current [raw] IOC state */
2647 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002648 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
2650 /*
2651 * Check to see if IOC got left/stuck in doorbell handshake
2652 * grip of death. If so, hard reset the IOC.
2653 */
2654 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2655 statefault = 1;
2656 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2657 ioc->name);
2658 }
2659
2660 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002661 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 return 0;
2663
2664 /*
2665 * Check to see if IOC is in FAULT state.
2666 */
2667 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2668 statefault = 2;
2669 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002670 ioc->name);
2671 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2672 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 }
2674
2675 /*
2676 * Hmmm... Did it get left operational?
2677 */
2678 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302679 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 ioc->name));
2681
2682 /* Check WhoInit.
2683 * If PCI Peer, exit.
2684 * Else, if no fault conditions are present, issue a MessageUnitReset
2685 * Else, fall through to KickStart case
2686 */
2687 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002688 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2689 "whoinit 0x%x statefault %d force %d\n",
2690 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 if (whoinit == MPI_WHOINIT_PCI_PEER)
2692 return -4;
2693 else {
2694 if ((statefault == 0 ) && (force == 0)) {
2695 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2696 return 0;
2697 }
2698 statefault = 3;
2699 }
2700 }
2701
2702 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2703 if (hard_reset_done < 0)
2704 return -1;
2705
2706 /*
2707 * Loop here waiting for IOC to come READY.
2708 */
2709 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002710 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
2712 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2713 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2714 /*
2715 * BIOS or previous driver load left IOC in OP state.
2716 * Reset messaging FIFOs.
2717 */
2718 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2719 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2720 return -2;
2721 }
2722 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2723 /*
2724 * Something is wrong. Try to get IOC back
2725 * to a known state.
2726 */
2727 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2728 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2729 return -3;
2730 }
2731 }
2732
2733 ii++; cntdn--;
2734 if (!cntdn) {
2735 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2736 ioc->name, (int)((ii+5)/HZ));
2737 return -ETIME;
2738 }
2739
2740 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002741 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 } else {
2743 mdelay (1); /* 1 msec delay */
2744 }
2745
2746 }
2747
2748 if (statefault < 3) {
2749 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2750 ioc->name,
2751 statefault==1 ? "stuck handshake" : "IOC FAULT");
2752 }
2753
2754 return hard_reset_done;
2755}
2756
2757/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002758/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 * mpt_GetIocState - Get the current state of a MPT adapter.
2760 * @ioc: Pointer to MPT_ADAPTER structure
2761 * @cooked: Request raw or cooked IOC state
2762 *
2763 * Returns all IOC Doorbell register bits if cooked==0, else just the
2764 * Doorbell bits in MPI_IOC_STATE_MASK.
2765 */
2766u32
2767mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2768{
2769 u32 s, sc;
2770
2771 /* Get! */
2772 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 sc = s & MPI_IOC_STATE_MASK;
2774
2775 /* Save! */
2776 ioc->last_state = sc;
2777
2778 return cooked ? sc : s;
2779}
2780
2781/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002782/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 * GetIocFacts - Send IOCFacts request to MPT adapter.
2784 * @ioc: Pointer to MPT_ADAPTER structure
2785 * @sleepFlag: Specifies whether the process can sleep
2786 * @reason: If recovery, only update facts.
2787 *
2788 * Returns 0 for success, non-zero for failure.
2789 */
2790static int
2791GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2792{
2793 IOCFacts_t get_facts;
2794 IOCFactsReply_t *facts;
2795 int r;
2796 int req_sz;
2797 int reply_sz;
2798 int sz;
2799 u32 status, vv;
2800 u8 shiftFactor=1;
2801
2802 /* IOC *must* NOT be in RESET state! */
2803 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002804 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2805 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 return -44;
2807 }
2808
2809 facts = &ioc->facts;
2810
2811 /* Destination (reply area)... */
2812 reply_sz = sizeof(*facts);
2813 memset(facts, 0, reply_sz);
2814
2815 /* Request area (get_facts on the stack right now!) */
2816 req_sz = sizeof(get_facts);
2817 memset(&get_facts, 0, req_sz);
2818
2819 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2820 /* Assert: All other get_facts fields are zero! */
2821
Prakash, Sathya436ace72007-07-24 15:42:08 +05302822 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002823 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 ioc->name, req_sz, reply_sz));
2825
2826 /* No non-zero fields in the get_facts request are greater than
2827 * 1 byte in size, so we can just fire it off as is.
2828 */
2829 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2830 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2831 if (r != 0)
2832 return r;
2833
2834 /*
2835 * Now byte swap (GRRR) the necessary fields before any further
2836 * inspection of reply contents.
2837 *
2838 * But need to do some sanity checks on MsgLength (byte) field
2839 * to make sure we don't zero IOC's req_sz!
2840 */
2841 /* Did we get a valid reply? */
2842 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2843 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2844 /*
2845 * If not been here, done that, save off first WhoInit value
2846 */
2847 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2848 ioc->FirstWhoInit = facts->WhoInit;
2849 }
2850
2851 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2852 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2853 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2854 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2855 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002856 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 /* CHECKME! IOCStatus, IOCLogInfo */
2858
2859 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2860 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2861
2862 /*
2863 * FC f/w version changed between 1.1 and 1.2
2864 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2865 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2866 */
2867 if (facts->MsgVersion < 0x0102) {
2868 /*
2869 * Handle old FC f/w style, convert to new...
2870 */
2871 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2872 facts->FWVersion.Word =
2873 ((oldv<<12) & 0xFF000000) |
2874 ((oldv<<8) & 0x000FFF00);
2875 } else
2876 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2877
2878 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002879 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2880 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2881 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 facts->CurrentHostMfaHighAddr =
2883 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2884 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2885 facts->CurrentSenseBufferHighAddr =
2886 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2887 facts->CurReplyFrameSize =
2888 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002889 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890
2891 /*
2892 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2893 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2894 * to 14 in MPI-1.01.0x.
2895 */
2896 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2897 facts->MsgVersion > 0x0100) {
2898 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2899 }
2900
2901 sz = facts->FWImageSize;
2902 if ( sz & 0x01 )
2903 sz += 1;
2904 if ( sz & 0x02 )
2905 sz += 2;
2906 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002907
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 if (!facts->RequestFrameSize) {
2909 /* Something is wrong! */
2910 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2911 ioc->name);
2912 return -55;
2913 }
2914
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002915 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 vv = ((63 / (sz * 4)) + 1) & 0x03;
2917 ioc->NB_for_64_byte_frame = vv;
2918 while ( sz )
2919 {
2920 shiftFactor++;
2921 sz = sz >> 1;
2922 }
2923 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302924 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002925 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2926 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002927
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2929 /*
2930 * Set values for this IOC's request & reply frame sizes,
2931 * and request & reply queue depths...
2932 */
2933 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2934 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2935 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2936 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2937
Prakash, Sathya436ace72007-07-24 15:42:08 +05302938 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302940 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 ioc->name, ioc->req_sz, ioc->req_depth));
2942
2943 /* Get port facts! */
2944 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2945 return r;
2946 }
2947 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002948 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2950 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2951 RequestFrameSize)/sizeof(u32)));
2952 return -66;
2953 }
2954
2955 return 0;
2956}
2957
2958/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002959/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 * GetPortFacts - Send PortFacts request to MPT adapter.
2961 * @ioc: Pointer to MPT_ADAPTER structure
2962 * @portnum: Port number
2963 * @sleepFlag: Specifies whether the process can sleep
2964 *
2965 * Returns 0 for success, non-zero for failure.
2966 */
2967static int
2968GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2969{
2970 PortFacts_t get_pfacts;
2971 PortFactsReply_t *pfacts;
2972 int ii;
2973 int req_sz;
2974 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002975 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976
2977 /* IOC *must* NOT be in RESET state! */
2978 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002979 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2980 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 return -4;
2982 }
2983
2984 pfacts = &ioc->pfacts[portnum];
2985
2986 /* Destination (reply area)... */
2987 reply_sz = sizeof(*pfacts);
2988 memset(pfacts, 0, reply_sz);
2989
2990 /* Request area (get_pfacts on the stack right now!) */
2991 req_sz = sizeof(get_pfacts);
2992 memset(&get_pfacts, 0, req_sz);
2993
2994 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2995 get_pfacts.PortNumber = portnum;
2996 /* Assert: All other get_pfacts fields are zero! */
2997
Prakash, Sathya436ace72007-07-24 15:42:08 +05302998 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 ioc->name, portnum));
3000
3001 /* No non-zero fields in the get_pfacts request are greater than
3002 * 1 byte in size, so we can just fire it off as is.
3003 */
3004 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3005 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3006 if (ii != 0)
3007 return ii;
3008
3009 /* Did we get a valid reply? */
3010
3011 /* Now byte swap the necessary fields in the response. */
3012 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3013 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3014 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3015 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3016 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3017 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3018 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3019 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3020 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3021
Eric Moore793955f2007-01-29 09:42:20 -07003022 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3023 pfacts->MaxDevices;
3024 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3025 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3026
3027 /*
3028 * Place all the devices on channels
3029 *
3030 * (for debuging)
3031 */
3032 if (mpt_channel_mapping) {
3033 ioc->devices_per_bus = 1;
3034 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3035 }
3036
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 return 0;
3038}
3039
3040/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003041/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 * SendIocInit - Send IOCInit request to MPT adapter.
3043 * @ioc: Pointer to MPT_ADAPTER structure
3044 * @sleepFlag: Specifies whether the process can sleep
3045 *
3046 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3047 *
3048 * Returns 0 for success, non-zero for failure.
3049 */
3050static int
3051SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3052{
3053 IOCInit_t ioc_init;
3054 MPIDefaultReply_t init_reply;
3055 u32 state;
3056 int r;
3057 int count;
3058 int cntdn;
3059
3060 memset(&ioc_init, 0, sizeof(ioc_init));
3061 memset(&init_reply, 0, sizeof(init_reply));
3062
3063 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3064 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3065
3066 /* If we are in a recovery mode and we uploaded the FW image,
3067 * then this pointer is not NULL. Skip the upload a second time.
3068 * Set this flag if cached_fw set for either IOC.
3069 */
3070 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3071 ioc->upload_fw = 1;
3072 else
3073 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303074 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3076
Eric Moore793955f2007-01-29 09:42:20 -07003077 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3078 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303079 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003080 ioc->name, ioc->facts.MsgVersion));
3081 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3082 // set MsgVersion and HeaderVersion host driver was built with
3083 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3084 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003086 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3087 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3088 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3089 return -99;
3090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3092
3093 if (sizeof(dma_addr_t) == sizeof(u64)) {
3094 /* Save the upper 32-bits of the request
3095 * (reply) and sense buffers.
3096 */
3097 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3098 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3099 } else {
3100 /* Force 32-bit addressing */
3101 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3102 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3103 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003104
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3106 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003107 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3108 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
Prakash, Sathya436ace72007-07-24 15:42:08 +05303110 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 ioc->name, &ioc_init));
3112
3113 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3114 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003115 if (r != 0) {
3116 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119
3120 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003121 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 */
3123
Prakash, Sathya436ace72007-07-24 15:42:08 +05303124 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003126
3127 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3128 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131
3132 /* YIKES! SUPER IMPORTANT!!!
3133 * Poll IocState until _OPERATIONAL while IOC is doing
3134 * LoopInit and TargetDiscovery!
3135 */
3136 count = 0;
3137 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3138 state = mpt_GetIocState(ioc, 1);
3139 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3140 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003141 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 } else {
3143 mdelay(1);
3144 }
3145
3146 if (!cntdn) {
3147 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3148 ioc->name, (int)((count+5)/HZ));
3149 return -9;
3150 }
3151
3152 state = mpt_GetIocState(ioc, 1);
3153 count++;
3154 }
Eric Moore29dd3602007-09-14 18:46:51 -06003155 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 ioc->name, count));
3157
Eric Mooreba856d32006-07-11 17:34:01 -06003158 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 return r;
3160}
3161
3162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003163/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 * SendPortEnable - Send PortEnable request to MPT adapter port.
3165 * @ioc: Pointer to MPT_ADAPTER structure
3166 * @portnum: Port number to enable
3167 * @sleepFlag: Specifies whether the process can sleep
3168 *
3169 * Send PortEnable to bring IOC to OPERATIONAL state.
3170 *
3171 * Returns 0 for success, non-zero for failure.
3172 */
3173static int
3174SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3175{
3176 PortEnable_t port_enable;
3177 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003178 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 int req_sz;
3180 int reply_sz;
3181
3182 /* Destination... */
3183 reply_sz = sizeof(MPIDefaultReply_t);
3184 memset(&reply_buf, 0, reply_sz);
3185
3186 req_sz = sizeof(PortEnable_t);
3187 memset(&port_enable, 0, req_sz);
3188
3189 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3190 port_enable.PortNumber = portnum;
3191/* port_enable.ChainOffset = 0; */
3192/* port_enable.MsgFlags = 0; */
3193/* port_enable.MsgContext = 0; */
3194
Prakash, Sathya436ace72007-07-24 15:42:08 +05303195 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 ioc->name, portnum, &port_enable));
3197
3198 /* RAID FW may take a long time to enable
3199 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003200 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003201 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3202 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3203 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003204 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003205 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3206 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3207 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003209 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210}
3211
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003212/**
3213 * mpt_alloc_fw_memory - allocate firmware memory
3214 * @ioc: Pointer to MPT_ADAPTER structure
3215 * @size: total FW bytes
3216 *
3217 * If memory has already been allocated, the same (cached) value
3218 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303219 *
3220 * Return 0 if successfull, or non-zero for failure
3221 **/
3222int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3224{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303225 int rc;
3226
3227 if (ioc->cached_fw) {
3228 rc = 0; /* use already allocated memory */
3229 goto out;
3230 }
3231 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3233 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303234 rc = 0;
3235 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303237 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3238 if (!ioc->cached_fw) {
3239 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3240 ioc->name);
3241 rc = -1;
3242 } else {
3243 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3244 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3245 ioc->alloc_total += size;
3246 rc = 0;
3247 }
3248 out:
3249 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303251
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003252/**
3253 * mpt_free_fw_memory - free firmware memory
3254 * @ioc: Pointer to MPT_ADAPTER structure
3255 *
3256 * If alt_img is NULL, delete from ioc structure.
3257 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303258 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259void
3260mpt_free_fw_memory(MPT_ADAPTER *ioc)
3261{
3262 int sz;
3263
Prakash, Sathya984621b2008-01-11 14:42:17 +05303264 if (!ioc->cached_fw)
3265 return;
3266
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303268 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3269 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003270 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303271 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273}
3274
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003276/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3278 * @ioc: Pointer to MPT_ADAPTER structure
3279 * @sleepFlag: Specifies whether the process can sleep
3280 *
3281 * Returns 0 for success, >0 for handshake failure
3282 * <0 for fw upload failure.
3283 *
3284 * Remark: If bound IOC and a successful FWUpload was performed
3285 * on the bound IOC, the second image is discarded
3286 * and memory is free'd. Both channels must upload to prevent
3287 * IOC from running in degraded mode.
3288 */
3289static int
3290mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3291{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 u8 reply[sizeof(FWUploadReply_t)];
3293 FWUpload_t *prequest;
3294 FWUploadReply_t *preply;
3295 FWUploadTCSGE_t *ptcsge;
3296 int sgeoffset;
3297 u32 flagsLength;
3298 int ii, sz, reply_sz;
3299 int cmdStatus;
3300
3301 /* If the image size is 0, we are done.
3302 */
3303 if ((sz = ioc->facts.FWImageSize) == 0)
3304 return 0;
3305
Prakash, Sathya984621b2008-01-11 14:42:17 +05303306 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3307 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308
Eric Moore29dd3602007-09-14 18:46:51 -06003309 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3310 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003311
Eric Moorebc6e0892007-09-29 10:16:28 -06003312 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3313 kzalloc(ioc->req_sz, GFP_KERNEL);
3314 if (!prequest) {
3315 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3316 "while allocating memory \n", ioc->name));
3317 mpt_free_fw_memory(ioc);
3318 return -ENOMEM;
3319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320
Eric Moorebc6e0892007-09-29 10:16:28 -06003321 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322
3323 reply_sz = sizeof(reply);
3324 memset(preply, 0, reply_sz);
3325
3326 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3327 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3328
3329 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3330 ptcsge->DetailsLength = 12;
3331 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3332 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003333 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334
3335 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3336
3337 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003338 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
3340 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003341 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3342 ioc->name, prequest, sgeoffset));
3343 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344
3345 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3346 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3347
Eric Moore29dd3602007-09-14 18:46:51 -06003348 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349
3350 cmdStatus = -EFAULT;
3351 if (ii == 0) {
3352 /* Handshake transfer was complete and successful.
3353 * Check the Reply Frame.
3354 */
3355 int status, transfer_sz;
3356 status = le16_to_cpu(preply->IOCStatus);
3357 if (status == MPI_IOCSTATUS_SUCCESS) {
3358 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3359 if (transfer_sz == sz)
3360 cmdStatus = 0;
3361 }
3362 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303363 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 ioc->name, cmdStatus));
3365
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003366
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 if (cmdStatus) {
3368
Prakash, Sathya436ace72007-07-24 15:42:08 +05303369 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 ioc->name));
3371 mpt_free_fw_memory(ioc);
3372 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003373 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374
3375 return cmdStatus;
3376}
3377
3378/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003379/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 * mpt_downloadboot - DownloadBoot code
3381 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003382 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 * @sleepFlag: Specifies whether the process can sleep
3384 *
3385 * FwDownloadBoot requires Programmed IO access.
3386 *
3387 * Returns 0 for success
3388 * -1 FW Image size is 0
3389 * -2 No valid cached_fw Pointer
3390 * <0 for fw upload failure.
3391 */
3392static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003393mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 MpiExtImageHeader_t *pExtImage;
3396 u32 fwSize;
3397 u32 diag0val;
3398 int count;
3399 u32 *ptrFw;
3400 u32 diagRwData;
3401 u32 nextImage;
3402 u32 load_addr;
3403 u32 ioc_state=0;
3404
Prakash, Sathya436ace72007-07-24 15:42:08 +05303405 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003406 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003407
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3409 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3410 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3411 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3412 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3413 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3414
3415 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3416
3417 /* wait 1 msec */
3418 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003419 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 } else {
3421 mdelay (1);
3422 }
3423
3424 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3425 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3426
3427 for (count = 0; count < 30; count ++) {
3428 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3429 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303430 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 ioc->name, count));
3432 break;
3433 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003434 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003436 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003438 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 }
3440 }
3441
3442 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303443 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003444 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 ioc->name, diag0val));
3446 return -3;
3447 }
3448
3449 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3450 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3451 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3452 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3453 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3454 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3455
3456 /* Set the DiagRwEn and Disable ARM bits */
3457 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3458
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 fwSize = (pFwHeader->ImageSize + 3)/4;
3460 ptrFw = (u32 *) pFwHeader;
3461
3462 /* Write the LoadStartAddress to the DiagRw Address Register
3463 * using Programmed IO
3464 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003465 if (ioc->errata_flag_1064)
3466 pci_enable_io_access(ioc->pcidev);
3467
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303469 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 ioc->name, pFwHeader->LoadStartAddress));
3471
Prakash, Sathya436ace72007-07-24 15:42:08 +05303472 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 ioc->name, fwSize*4, ptrFw));
3474 while (fwSize--) {
3475 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3476 }
3477
3478 nextImage = pFwHeader->NextImageHeaderOffset;
3479 while (nextImage) {
3480 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3481
3482 load_addr = pExtImage->LoadStartAddress;
3483
3484 fwSize = (pExtImage->ImageSize + 3) >> 2;
3485 ptrFw = (u32 *)pExtImage;
3486
Prakash, Sathya436ace72007-07-24 15:42:08 +05303487 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 +02003488 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3490
3491 while (fwSize--) {
3492 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3493 }
3494 nextImage = pExtImage->NextImageHeaderOffset;
3495 }
3496
3497 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303498 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3500
3501 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303502 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3504
3505 /* Clear the internal flash bad bit - autoincrementing register,
3506 * so must do two writes.
3507 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003508 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003509 /*
3510 * 1030 and 1035 H/W errata, workaround to access
3511 * the ClearFlashBadSignatureBit
3512 */
3513 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3514 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3515 diagRwData |= 0x40000000;
3516 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3517 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3518
3519 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3520 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3521 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3522 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3523
3524 /* wait 1 msec */
3525 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003526 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003527 } else {
3528 mdelay (1);
3529 }
3530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003532 if (ioc->errata_flag_1064)
3533 pci_disable_io_access(ioc->pcidev);
3534
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303536 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003537 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003539 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303540 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 ioc->name, diag0val));
3542 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3543
3544 /* Write 0xFF to reset the sequencer */
3545 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3546
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003547 if (ioc->bus_type == SAS) {
3548 ioc_state = mpt_GetIocState(ioc, 0);
3549 if ( (GetIocFacts(ioc, sleepFlag,
3550 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303551 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003552 ioc->name, ioc_state));
3553 return -EFAULT;
3554 }
3555 }
3556
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 for (count=0; count<HZ*20; count++) {
3558 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303559 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3560 "downloadboot successful! (count=%d) IocState=%x\n",
3561 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003562 if (ioc->bus_type == SAS) {
3563 return 0;
3564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303566 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3567 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 ioc->name));
3569 return -EFAULT;
3570 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303571 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3572 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 ioc->name));
3574 return 0;
3575 }
3576 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003577 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 } else {
3579 mdelay (10);
3580 }
3581 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303582 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3583 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 return -EFAULT;
3585}
3586
3587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003588/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 * KickStart - Perform hard reset of MPT adapter.
3590 * @ioc: Pointer to MPT_ADAPTER structure
3591 * @force: Force hard reset
3592 * @sleepFlag: Specifies whether the process can sleep
3593 *
3594 * This routine places MPT adapter in diagnostic mode via the
3595 * WriteSequence register, and then performs a hard reset of adapter
3596 * via the Diagnostic register.
3597 *
3598 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3599 * or NO_SLEEP (interrupt thread, use mdelay)
3600 * force - 1 if doorbell active, board fault state
3601 * board operational, IOC_RECOVERY or
3602 * IOC_BRINGUP and there is an alt_ioc.
3603 * 0 else
3604 *
3605 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003606 * 1 - hard reset, READY
3607 * 0 - no reset due to History bit, READY
3608 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 * OR reset but failed to come READY
3610 * -2 - no reset, could not enter DIAG mode
3611 * -3 - reset but bad FW bit
3612 */
3613static int
3614KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3615{
3616 int hard_reset_done = 0;
3617 u32 ioc_state=0;
3618 int cnt,cntdn;
3619
Eric Moore29dd3602007-09-14 18:46:51 -06003620 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003621 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 /* Always issue a Msg Unit Reset first. This will clear some
3623 * SCSI bus hang conditions.
3624 */
3625 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3626
3627 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003628 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 } else {
3630 mdelay (1000);
3631 }
3632 }
3633
3634 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3635 if (hard_reset_done < 0)
3636 return hard_reset_done;
3637
Prakash, Sathya436ace72007-07-24 15:42:08 +05303638 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003639 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640
3641 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3642 for (cnt=0; cnt<cntdn; cnt++) {
3643 ioc_state = mpt_GetIocState(ioc, 1);
3644 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303645 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 ioc->name, cnt));
3647 return hard_reset_done;
3648 }
3649 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003650 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 } else {
3652 mdelay (10);
3653 }
3654 }
3655
Eric Moore29dd3602007-09-14 18:46:51 -06003656 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3657 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 return -1;
3659}
3660
3661/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003662/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 * mpt_diag_reset - Perform hard reset of the adapter.
3664 * @ioc: Pointer to MPT_ADAPTER structure
3665 * @ignore: Set if to honor and clear to ignore
3666 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003667 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 * else set to NO_SLEEP (use mdelay instead)
3669 *
3670 * This routine places the adapter in diagnostic mode via the
3671 * WriteSequence register and then performs a hard reset of adapter
3672 * via the Diagnostic register. Adapter should be in ready state
3673 * upon successful completion.
3674 *
3675 * Returns: 1 hard reset successful
3676 * 0 no reset performed because reset history bit set
3677 * -2 enabling diagnostic mode failed
3678 * -3 diagnostic reset failed
3679 */
3680static int
3681mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3682{
3683 u32 diag0val;
3684 u32 doorbell;
3685 int hard_reset_done = 0;
3686 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303688 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689
Eric Moorecd2c6192007-01-29 09:47:47 -07003690 /* Clear any existing interrupts */
3691 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3692
Eric Moore87cf8982006-06-27 16:09:26 -06003693 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303694 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003695 "address=%p\n", ioc->name, __FUNCTION__,
3696 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3697 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3698 if (sleepFlag == CAN_SLEEP)
3699 msleep(1);
3700 else
3701 mdelay(1);
3702
3703 for (count = 0; count < 60; count ++) {
3704 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3705 doorbell &= MPI_IOC_STATE_MASK;
3706
Prakash, Sathya436ace72007-07-24 15:42:08 +05303707 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003708 "looking for READY STATE: doorbell=%x"
3709 " count=%d\n",
3710 ioc->name, doorbell, count));
3711 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003712 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003713 }
3714
3715 /* wait 1 sec */
3716 if (sleepFlag == CAN_SLEEP)
3717 msleep(1000);
3718 else
3719 mdelay(1000);
3720 }
3721 return -1;
3722 }
3723
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 /* Use "Diagnostic reset" method! (only thing available!) */
3725 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3726
Prakash, Sathya436ace72007-07-24 15:42:08 +05303727 if (ioc->debug_level & MPT_DEBUG) {
3728 if (ioc->alt_ioc)
3729 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3730 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733
3734 /* Do the reset if we are told to ignore the reset history
3735 * or if the reset history is 0
3736 */
3737 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3738 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3739 /* Write magic sequence to WriteSequence register
3740 * Loop until in diagnostic mode
3741 */
3742 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3743 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3744 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3745 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3746 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3747 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3748
3749 /* wait 100 msec */
3750 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003751 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 } else {
3753 mdelay (100);
3754 }
3755
3756 count++;
3757 if (count > 20) {
3758 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3759 ioc->name, diag0val);
3760 return -2;
3761
3762 }
3763
3764 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3765
Prakash, Sathya436ace72007-07-24 15:42:08 +05303766 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 ioc->name, diag0val));
3768 }
3769
Prakash, Sathya436ace72007-07-24 15:42:08 +05303770 if (ioc->debug_level & MPT_DEBUG) {
3771 if (ioc->alt_ioc)
3772 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3773 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 /*
3777 * Disable the ARM (Bug fix)
3778 *
3779 */
3780 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003781 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
3783 /*
3784 * Now hit the reset bit in the Diagnostic register
3785 * (THE BIG HAMMER!) (Clears DRWE bit).
3786 */
3787 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3788 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303789 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 ioc->name));
3791
3792 /*
3793 * Call each currently registered protocol IOC reset handler
3794 * with pre-reset indication.
3795 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3796 * MptResetHandlers[] registered yet.
3797 */
3798 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303799 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 int r = 0;
3801
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303802 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3803 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303804 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3805 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303806 ioc->name, cb_idx));
3807 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303809 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3810 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303811 ioc->name, ioc->alt_ioc->name, cb_idx));
3812 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 }
3814 }
3815 }
3816 /* FIXME? Examine results here? */
3817 }
3818
Eric Moore0ccdb002006-07-11 17:33:13 -06003819 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303820 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003821 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303822 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3823 else
3824 cached_fw = NULL;
3825 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 /* If the DownloadBoot operation fails, the
3827 * IOC will be left unusable. This is a fatal error
3828 * case. _diag_reset will return < 0
3829 */
3830 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303831 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3833 break;
3834 }
3835
Prakash, Sathya436ace72007-07-24 15:42:08 +05303836 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303837 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 /* wait 1 sec */
3839 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003840 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 } else {
3842 mdelay (1000);
3843 }
3844 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303845 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003846 printk(MYIOC_s_WARN_FMT
3847 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 }
3849
3850 } else {
3851 /* Wait for FW to reload and for board
3852 * to go to the READY state.
3853 * Maximum wait is 60 seconds.
3854 * If fail, no error will check again
3855 * with calling program.
3856 */
3857 for (count = 0; count < 60; count ++) {
3858 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3859 doorbell &= MPI_IOC_STATE_MASK;
3860
3861 if (doorbell == MPI_IOC_STATE_READY) {
3862 break;
3863 }
3864
3865 /* wait 1 sec */
3866 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003867 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 } else {
3869 mdelay (1000);
3870 }
3871 }
3872 }
3873 }
3874
3875 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303876 if (ioc->debug_level & MPT_DEBUG) {
3877 if (ioc->alt_ioc)
3878 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3879 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3880 ioc->name, diag0val, diag1val));
3881 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882
3883 /* Clear RESET_HISTORY bit! Place board in the
3884 * diagnostic mode to update the diag register.
3885 */
3886 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3887 count = 0;
3888 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3889 /* Write magic sequence to WriteSequence register
3890 * Loop until in diagnostic mode
3891 */
3892 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3893 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3894 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3895 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3896 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3897 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3898
3899 /* wait 100 msec */
3900 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003901 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 } else {
3903 mdelay (100);
3904 }
3905
3906 count++;
3907 if (count > 20) {
3908 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3909 ioc->name, diag0val);
3910 break;
3911 }
3912 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3913 }
3914 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3915 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3916 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3917 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3918 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3919 ioc->name);
3920 }
3921
3922 /* Disable Diagnostic Mode
3923 */
3924 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3925
3926 /* Check FW reload status flags.
3927 */
3928 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3929 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3930 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3931 ioc->name, diag0val);
3932 return -3;
3933 }
3934
Prakash, Sathya436ace72007-07-24 15:42:08 +05303935 if (ioc->debug_level & MPT_DEBUG) {
3936 if (ioc->alt_ioc)
3937 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3938 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303940 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941
3942 /*
3943 * Reset flag that says we've enabled event notification
3944 */
3945 ioc->facts.EventState = 0;
3946
3947 if (ioc->alt_ioc)
3948 ioc->alt_ioc->facts.EventState = 0;
3949
3950 return hard_reset_done;
3951}
3952
3953/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003954/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 * SendIocReset - Send IOCReset request to MPT adapter.
3956 * @ioc: Pointer to MPT_ADAPTER structure
3957 * @reset_type: reset type, expected values are
3958 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003959 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 *
3961 * Send IOCReset request to the MPT adapter.
3962 *
3963 * Returns 0 for success, non-zero for failure.
3964 */
3965static int
3966SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3967{
3968 int r;
3969 u32 state;
3970 int cntdn, count;
3971
Prakash, Sathya436ace72007-07-24 15:42:08 +05303972 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 ioc->name, reset_type));
3974 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3975 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3976 return r;
3977
3978 /* FW ACK'd request, wait for READY state
3979 */
3980 count = 0;
3981 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3982
3983 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3984 cntdn--;
3985 count++;
3986 if (!cntdn) {
3987 if (sleepFlag != CAN_SLEEP)
3988 count *= 10;
3989
Eric Moore29dd3602007-09-14 18:46:51 -06003990 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3991 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 return -ETIME;
3993 }
3994
3995 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003996 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 } else {
3998 mdelay (1); /* 1 msec delay */
3999 }
4000 }
4001
4002 /* TODO!
4003 * Cleanup all event stuff for this IOC; re-issue EventNotification
4004 * request if needed.
4005 */
4006 if (ioc->facts.Function)
4007 ioc->facts.EventState = 0;
4008
4009 return 0;
4010}
4011
4012/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004013/**
4014 * initChainBuffers - Allocate memory for and initialize chain buffers
4015 * @ioc: Pointer to MPT_ADAPTER structure
4016 *
4017 * Allocates memory for and initializes chain buffers,
4018 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 */
4020static int
4021initChainBuffers(MPT_ADAPTER *ioc)
4022{
4023 u8 *mem;
4024 int sz, ii, num_chain;
4025 int scale, num_sge, numSGE;
4026
4027 /* ReqToChain size must equal the req_depth
4028 * index = req_idx
4029 */
4030 if (ioc->ReqToChain == NULL) {
4031 sz = ioc->req_depth * sizeof(int);
4032 mem = kmalloc(sz, GFP_ATOMIC);
4033 if (mem == NULL)
4034 return -1;
4035
4036 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304037 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 ioc->name, mem, sz));
4039 mem = kmalloc(sz, GFP_ATOMIC);
4040 if (mem == NULL)
4041 return -1;
4042
4043 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304044 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 ioc->name, mem, sz));
4046 }
4047 for (ii = 0; ii < ioc->req_depth; ii++) {
4048 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4049 }
4050
4051 /* ChainToChain size must equal the total number
4052 * of chain buffers to be allocated.
4053 * index = chain_idx
4054 *
4055 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004056 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 *
4058 * num_sge = num sge in request frame + last chain buffer
4059 * scale = num sge per chain buffer if no chain element
4060 */
4061 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
4062 if (sizeof(dma_addr_t) == sizeof(u64))
4063 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4064 else
4065 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4066
4067 if (sizeof(dma_addr_t) == sizeof(u64)) {
4068 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4069 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4070 } else {
4071 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4072 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4073 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304074 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 ioc->name, num_sge, numSGE));
4076
4077 if ( numSGE > MPT_SCSI_SG_DEPTH )
4078 numSGE = MPT_SCSI_SG_DEPTH;
4079
4080 num_chain = 1;
4081 while (numSGE - num_sge > 0) {
4082 num_chain++;
4083 num_sge += (scale - 1);
4084 }
4085 num_chain++;
4086
Prakash, Sathya436ace72007-07-24 15:42:08 +05304087 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 ioc->name, numSGE, num_sge, num_chain));
4089
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004090 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 num_chain *= MPT_SCSI_CAN_QUEUE;
4092 else
4093 num_chain *= MPT_FC_CAN_QUEUE;
4094
4095 ioc->num_chain = num_chain;
4096
4097 sz = num_chain * sizeof(int);
4098 if (ioc->ChainToChain == NULL) {
4099 mem = kmalloc(sz, GFP_ATOMIC);
4100 if (mem == NULL)
4101 return -1;
4102
4103 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304104 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 ioc->name, mem, sz));
4106 } else {
4107 mem = (u8 *) ioc->ChainToChain;
4108 }
4109 memset(mem, 0xFF, sz);
4110 return num_chain;
4111}
4112
4113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004114/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4116 * @ioc: Pointer to MPT_ADAPTER structure
4117 *
4118 * This routine allocates memory for the MPT reply and request frame
4119 * pools (if necessary), and primes the IOC reply FIFO with
4120 * reply frames.
4121 *
4122 * Returns 0 for success, non-zero for failure.
4123 */
4124static int
4125PrimeIocFifos(MPT_ADAPTER *ioc)
4126{
4127 MPT_FRAME_HDR *mf;
4128 unsigned long flags;
4129 dma_addr_t alloc_dma;
4130 u8 *mem;
4131 int i, reply_sz, sz, total_size, num_chain;
4132
4133 /* Prime reply FIFO... */
4134
4135 if (ioc->reply_frames == NULL) {
4136 if ( (num_chain = initChainBuffers(ioc)) < 0)
4137 return -1;
4138
4139 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304140 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304142 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 ioc->name, reply_sz, reply_sz));
4144
4145 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304146 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304148 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 ioc->name, sz, sz));
4150 total_size += sz;
4151
4152 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304153 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304155 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 ioc->name, sz, sz, num_chain));
4157
4158 total_size += sz;
4159 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4160 if (mem == NULL) {
4161 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4162 ioc->name);
4163 goto out_fail;
4164 }
4165
Prakash, Sathya436ace72007-07-24 15:42:08 +05304166 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4168
4169 memset(mem, 0, total_size);
4170 ioc->alloc_total += total_size;
4171 ioc->alloc = mem;
4172 ioc->alloc_dma = alloc_dma;
4173 ioc->alloc_sz = total_size;
4174 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4175 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4176
Prakash, Sathya436ace72007-07-24 15:42:08 +05304177 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004178 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4179
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 alloc_dma += reply_sz;
4181 mem += reply_sz;
4182
4183 /* Request FIFO - WE manage this! */
4184
4185 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4186 ioc->req_frames_dma = alloc_dma;
4187
Prakash, Sathya436ace72007-07-24 15:42:08 +05304188 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 ioc->name, mem, (void *)(ulong)alloc_dma));
4190
4191 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4192
4193#if defined(CONFIG_MTRR) && 0
4194 /*
4195 * Enable Write Combining MTRR for IOC's memory region.
4196 * (at least as much as we can; "size and base must be
4197 * multiples of 4 kiB"
4198 */
4199 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4200 sz,
4201 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304202 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 ioc->name, ioc->req_frames_dma, sz));
4204#endif
4205
4206 for (i = 0; i < ioc->req_depth; i++) {
4207 alloc_dma += ioc->req_sz;
4208 mem += ioc->req_sz;
4209 }
4210
4211 ioc->ChainBuffer = mem;
4212 ioc->ChainBufferDMA = alloc_dma;
4213
Prakash, Sathya436ace72007-07-24 15:42:08 +05304214 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4216
4217 /* Initialize the free chain Q.
4218 */
4219
4220 INIT_LIST_HEAD(&ioc->FreeChainQ);
4221
4222 /* Post the chain buffers to the FreeChainQ.
4223 */
4224 mem = (u8 *)ioc->ChainBuffer;
4225 for (i=0; i < num_chain; i++) {
4226 mf = (MPT_FRAME_HDR *) mem;
4227 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4228 mem += ioc->req_sz;
4229 }
4230
4231 /* Initialize Request frames linked list
4232 */
4233 alloc_dma = ioc->req_frames_dma;
4234 mem = (u8 *) ioc->req_frames;
4235
4236 spin_lock_irqsave(&ioc->FreeQlock, flags);
4237 INIT_LIST_HEAD(&ioc->FreeQ);
4238 for (i = 0; i < ioc->req_depth; i++) {
4239 mf = (MPT_FRAME_HDR *) mem;
4240
4241 /* Queue REQUESTs *internally*! */
4242 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4243
4244 mem += ioc->req_sz;
4245 }
4246 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4247
4248 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4249 ioc->sense_buf_pool =
4250 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4251 if (ioc->sense_buf_pool == NULL) {
4252 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4253 ioc->name);
4254 goto out_fail;
4255 }
4256
4257 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4258 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304259 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4261
4262 }
4263
4264 /* Post Reply frames to FIFO
4265 */
4266 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304267 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4269
4270 for (i = 0; i < ioc->reply_depth; i++) {
4271 /* Write each address to the IOC! */
4272 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4273 alloc_dma += ioc->reply_sz;
4274 }
4275
4276 return 0;
4277
4278out_fail:
4279 if (ioc->alloc != NULL) {
4280 sz = ioc->alloc_sz;
4281 pci_free_consistent(ioc->pcidev,
4282 sz,
4283 ioc->alloc, ioc->alloc_dma);
4284 ioc->reply_frames = NULL;
4285 ioc->req_frames = NULL;
4286 ioc->alloc_total -= sz;
4287 }
4288 if (ioc->sense_buf_pool != NULL) {
4289 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4290 pci_free_consistent(ioc->pcidev,
4291 sz,
4292 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4293 ioc->sense_buf_pool = NULL;
4294 }
4295 return -1;
4296}
4297
4298/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4299/**
4300 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4301 * from IOC via doorbell handshake method.
4302 * @ioc: Pointer to MPT_ADAPTER structure
4303 * @reqBytes: Size of the request in bytes
4304 * @req: Pointer to MPT request frame
4305 * @replyBytes: Expected size of the reply in bytes
4306 * @u16reply: Pointer to area where reply should be written
4307 * @maxwait: Max wait time for a reply (in seconds)
4308 * @sleepFlag: Specifies whether the process can sleep
4309 *
4310 * NOTES: It is the callers responsibility to byte-swap fields in the
4311 * request which are greater than 1 byte in size. It is also the
4312 * callers responsibility to byte-swap response fields which are
4313 * greater than 1 byte in size.
4314 *
4315 * Returns 0 for success, non-zero for failure.
4316 */
4317static int
4318mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004319 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320{
4321 MPIDefaultReply_t *mptReply;
4322 int failcnt = 0;
4323 int t;
4324
4325 /*
4326 * Get ready to cache a handshake reply
4327 */
4328 ioc->hs_reply_idx = 0;
4329 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4330 mptReply->MsgLength = 0;
4331
4332 /*
4333 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4334 * then tell IOC that we want to handshake a request of N words.
4335 * (WRITE u32val to Doorbell reg).
4336 */
4337 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4338 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4339 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4340 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4341
4342 /*
4343 * Wait for IOC's doorbell handshake int
4344 */
4345 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4346 failcnt++;
4347
Prakash, Sathya436ace72007-07-24 15:42:08 +05304348 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4350
4351 /* Read doorbell and check for active bit */
4352 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4353 return -1;
4354
4355 /*
4356 * Clear doorbell int (WRITE 0 to IntStatus reg),
4357 * then wait for IOC to ACKnowledge that it's ready for
4358 * our handshake request.
4359 */
4360 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4361 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4362 failcnt++;
4363
4364 if (!failcnt) {
4365 int ii;
4366 u8 *req_as_bytes = (u8 *) req;
4367
4368 /*
4369 * Stuff request words via doorbell handshake,
4370 * with ACK from IOC for each.
4371 */
4372 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4373 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4374 (req_as_bytes[(ii*4) + 1] << 8) |
4375 (req_as_bytes[(ii*4) + 2] << 16) |
4376 (req_as_bytes[(ii*4) + 3] << 24));
4377
4378 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4379 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4380 failcnt++;
4381 }
4382
Prakash, Sathya436ace72007-07-24 15:42:08 +05304383 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004384 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385
Prakash, Sathya436ace72007-07-24 15:42:08 +05304386 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4388
4389 /*
4390 * Wait for completion of doorbell handshake reply from the IOC
4391 */
4392 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4393 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004394
Prakash, Sathya436ace72007-07-24 15:42:08 +05304395 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4397
4398 /*
4399 * Copy out the cached reply...
4400 */
4401 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4402 u16reply[ii] = ioc->hs_reply[ii];
4403 } else {
4404 return -99;
4405 }
4406
4407 return -failcnt;
4408}
4409
4410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004411/**
4412 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 * @ioc: Pointer to MPT_ADAPTER structure
4414 * @howlong: How long to wait (in seconds)
4415 * @sleepFlag: Specifies whether the process can sleep
4416 *
4417 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004418 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4419 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 *
4421 * Returns a negative value on failure, else wait loop count.
4422 */
4423static int
4424WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4425{
4426 int cntdn;
4427 int count = 0;
4428 u32 intstat=0;
4429
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004430 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431
4432 if (sleepFlag == CAN_SLEEP) {
4433 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004434 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4436 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4437 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 count++;
4439 }
4440 } else {
4441 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004442 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4444 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4445 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 count++;
4447 }
4448 }
4449
4450 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304451 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 ioc->name, count));
4453 return count;
4454 }
4455
4456 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4457 ioc->name, count, intstat);
4458 return -1;
4459}
4460
4461/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004462/**
4463 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 * @ioc: Pointer to MPT_ADAPTER structure
4465 * @howlong: How long to wait (in seconds)
4466 * @sleepFlag: Specifies whether the process can sleep
4467 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004468 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4469 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 *
4471 * Returns a negative value on failure, else wait loop count.
4472 */
4473static int
4474WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4475{
4476 int cntdn;
4477 int count = 0;
4478 u32 intstat=0;
4479
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004480 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 if (sleepFlag == CAN_SLEEP) {
4482 while (--cntdn) {
4483 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4484 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4485 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004486 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 count++;
4488 }
4489 } else {
4490 while (--cntdn) {
4491 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4492 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4493 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004494 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 count++;
4496 }
4497 }
4498
4499 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304500 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 ioc->name, count, howlong));
4502 return count;
4503 }
4504
4505 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4506 ioc->name, count, intstat);
4507 return -1;
4508}
4509
4510/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004511/**
4512 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 * @ioc: Pointer to MPT_ADAPTER structure
4514 * @howlong: How long to wait (in seconds)
4515 * @sleepFlag: Specifies whether the process can sleep
4516 *
4517 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4518 * Reply is cached to IOC private area large enough to hold a maximum
4519 * of 128 bytes of reply data.
4520 *
4521 * Returns a negative value on failure, else size of reply in WORDS.
4522 */
4523static int
4524WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4525{
4526 int u16cnt = 0;
4527 int failcnt = 0;
4528 int t;
4529 u16 *hs_reply = ioc->hs_reply;
4530 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4531 u16 hword;
4532
4533 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4534
4535 /*
4536 * Get first two u16's so we can look at IOC's intended reply MsgLength
4537 */
4538 u16cnt=0;
4539 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4540 failcnt++;
4541 } else {
4542 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4543 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4544 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4545 failcnt++;
4546 else {
4547 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4548 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4549 }
4550 }
4551
Prakash, Sathya436ace72007-07-24 15:42:08 +05304552 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004553 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4555
4556 /*
4557 * If no error (and IOC said MsgLength is > 0), piece together
4558 * reply 16 bits at a time.
4559 */
4560 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4561 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4562 failcnt++;
4563 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4564 /* don't overflow our IOC hs_reply[] buffer! */
4565 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4566 hs_reply[u16cnt] = hword;
4567 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4568 }
4569
4570 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4571 failcnt++;
4572 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4573
4574 if (failcnt) {
4575 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4576 ioc->name);
4577 return -failcnt;
4578 }
4579#if 0
4580 else if (u16cnt != (2 * mptReply->MsgLength)) {
4581 return -101;
4582 }
4583 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4584 return -102;
4585 }
4586#endif
4587
Prakash, Sathya436ace72007-07-24 15:42:08 +05304588 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004589 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590
Prakash, Sathya436ace72007-07-24 15:42:08 +05304591 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 ioc->name, t, u16cnt/2));
4593 return u16cnt/2;
4594}
4595
4596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004597/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 * GetLanConfigPages - Fetch LANConfig pages.
4599 * @ioc: Pointer to MPT_ADAPTER structure
4600 *
4601 * Return: 0 for success
4602 * -ENOMEM if no memory available
4603 * -EPERM if not allowed due to ISR context
4604 * -EAGAIN if no msg frames currently available
4605 * -EFAULT for non-successful reply or no reply (timeout)
4606 */
4607static int
4608GetLanConfigPages(MPT_ADAPTER *ioc)
4609{
4610 ConfigPageHeader_t hdr;
4611 CONFIGPARMS cfg;
4612 LANPage0_t *ppage0_alloc;
4613 dma_addr_t page0_dma;
4614 LANPage1_t *ppage1_alloc;
4615 dma_addr_t page1_dma;
4616 int rc = 0;
4617 int data_sz;
4618 int copy_sz;
4619
4620 /* Get LAN Page 0 header */
4621 hdr.PageVersion = 0;
4622 hdr.PageLength = 0;
4623 hdr.PageNumber = 0;
4624 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004625 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 cfg.physAddr = -1;
4627 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4628 cfg.dir = 0;
4629 cfg.pageAddr = 0;
4630 cfg.timeout = 0;
4631
4632 if ((rc = mpt_config(ioc, &cfg)) != 0)
4633 return rc;
4634
4635 if (hdr.PageLength > 0) {
4636 data_sz = hdr.PageLength * 4;
4637 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4638 rc = -ENOMEM;
4639 if (ppage0_alloc) {
4640 memset((u8 *)ppage0_alloc, 0, data_sz);
4641 cfg.physAddr = page0_dma;
4642 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4643
4644 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4645 /* save the data */
4646 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4647 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4648
4649 }
4650
4651 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4652
4653 /* FIXME!
4654 * Normalize endianness of structure data,
4655 * by byte-swapping all > 1 byte fields!
4656 */
4657
4658 }
4659
4660 if (rc)
4661 return rc;
4662 }
4663
4664 /* Get LAN Page 1 header */
4665 hdr.PageVersion = 0;
4666 hdr.PageLength = 0;
4667 hdr.PageNumber = 1;
4668 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004669 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 cfg.physAddr = -1;
4671 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4672 cfg.dir = 0;
4673 cfg.pageAddr = 0;
4674
4675 if ((rc = mpt_config(ioc, &cfg)) != 0)
4676 return rc;
4677
4678 if (hdr.PageLength == 0)
4679 return 0;
4680
4681 data_sz = hdr.PageLength * 4;
4682 rc = -ENOMEM;
4683 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4684 if (ppage1_alloc) {
4685 memset((u8 *)ppage1_alloc, 0, data_sz);
4686 cfg.physAddr = page1_dma;
4687 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4688
4689 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4690 /* save the data */
4691 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4692 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4693 }
4694
4695 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4696
4697 /* FIXME!
4698 * Normalize endianness of structure data,
4699 * by byte-swapping all > 1 byte fields!
4700 */
4701
4702 }
4703
4704 return rc;
4705}
4706
4707/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004708/**
4709 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004710 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004711 * @persist_opcode: see below
4712 *
4713 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4714 * devices not currently present.
4715 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4716 *
4717 * NOTE: Don't use not this function during interrupt time.
4718 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004719 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004720 */
4721
4722/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4723int
4724mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4725{
4726 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4727 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4728 MPT_FRAME_HDR *mf = NULL;
4729 MPIHeader_t *mpi_hdr;
4730
4731
4732 /* insure garbage is not sent to fw */
4733 switch(persist_opcode) {
4734
4735 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4736 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4737 break;
4738
4739 default:
4740 return -1;
4741 break;
4742 }
4743
4744 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4745
4746 /* Get a MF for this command.
4747 */
4748 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4749 printk("%s: no msg frames!\n",__FUNCTION__);
4750 return -1;
4751 }
4752
4753 mpi_hdr = (MPIHeader_t *) mf;
4754 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4755 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4756 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4757 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4758 sasIoUnitCntrReq->Operation = persist_opcode;
4759
4760 init_timer(&ioc->persist_timer);
4761 ioc->persist_timer.data = (unsigned long) ioc;
4762 ioc->persist_timer.function = mpt_timer_expired;
4763 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4764 ioc->persist_wait_done=0;
4765 add_timer(&ioc->persist_timer);
4766 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4767 wait_event(mpt_waitq, ioc->persist_wait_done);
4768
4769 sasIoUnitCntrReply =
4770 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4771 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4772 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4773 __FUNCTION__,
4774 sasIoUnitCntrReply->IOCStatus,
4775 sasIoUnitCntrReply->IOCLogInfo);
4776 return -1;
4777 }
4778
4779 printk("%s: success\n",__FUNCTION__);
4780 return 0;
4781}
4782
4783/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004784
4785static void
4786mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4787 MpiEventDataRaid_t * pRaidEventData)
4788{
4789 int volume;
4790 int reason;
4791 int disk;
4792 int status;
4793 int flags;
4794 int state;
4795
4796 volume = pRaidEventData->VolumeID;
4797 reason = pRaidEventData->ReasonCode;
4798 disk = pRaidEventData->PhysDiskNum;
4799 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4800 flags = (status >> 0) & 0xff;
4801 state = (status >> 8) & 0xff;
4802
4803 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4804 return;
4805 }
4806
4807 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4808 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4809 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004810 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4811 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004812 } else {
4813 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4814 ioc->name, volume);
4815 }
4816
4817 switch(reason) {
4818 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4819 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4820 ioc->name);
4821 break;
4822
4823 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4824
4825 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4826 ioc->name);
4827 break;
4828
4829 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4830 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4831 ioc->name);
4832 break;
4833
4834 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4835 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4836 ioc->name,
4837 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4838 ? "optimal"
4839 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4840 ? "degraded"
4841 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4842 ? "failed"
4843 : "state unknown",
4844 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4845 ? ", enabled" : "",
4846 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4847 ? ", quiesced" : "",
4848 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4849 ? ", resync in progress" : "" );
4850 break;
4851
4852 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4853 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4854 ioc->name, disk);
4855 break;
4856
4857 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4858 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4859 ioc->name);
4860 break;
4861
4862 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4863 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4864 ioc->name);
4865 break;
4866
4867 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4868 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4869 ioc->name);
4870 break;
4871
4872 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4873 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4874 ioc->name,
4875 state == MPI_PHYSDISK0_STATUS_ONLINE
4876 ? "online"
4877 : state == MPI_PHYSDISK0_STATUS_MISSING
4878 ? "missing"
4879 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4880 ? "not compatible"
4881 : state == MPI_PHYSDISK0_STATUS_FAILED
4882 ? "failed"
4883 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4884 ? "initializing"
4885 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4886 ? "offline requested"
4887 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4888 ? "failed requested"
4889 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4890 ? "offline"
4891 : "state unknown",
4892 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4893 ? ", out of sync" : "",
4894 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4895 ? ", quiesced" : "" );
4896 break;
4897
4898 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4899 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4900 ioc->name, disk);
4901 break;
4902
4903 case MPI_EVENT_RAID_RC_SMART_DATA:
4904 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4905 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4906 break;
4907
4908 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4909 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4910 ioc->name, disk);
4911 break;
4912 }
4913}
4914
4915/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004916/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4918 * @ioc: Pointer to MPT_ADAPTER structure
4919 *
4920 * Returns: 0 for success
4921 * -ENOMEM if no memory available
4922 * -EPERM if not allowed due to ISR context
4923 * -EAGAIN if no msg frames currently available
4924 * -EFAULT for non-successful reply or no reply (timeout)
4925 */
4926static int
4927GetIoUnitPage2(MPT_ADAPTER *ioc)
4928{
4929 ConfigPageHeader_t hdr;
4930 CONFIGPARMS cfg;
4931 IOUnitPage2_t *ppage_alloc;
4932 dma_addr_t page_dma;
4933 int data_sz;
4934 int rc;
4935
4936 /* Get the page header */
4937 hdr.PageVersion = 0;
4938 hdr.PageLength = 0;
4939 hdr.PageNumber = 2;
4940 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004941 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 cfg.physAddr = -1;
4943 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4944 cfg.dir = 0;
4945 cfg.pageAddr = 0;
4946 cfg.timeout = 0;
4947
4948 if ((rc = mpt_config(ioc, &cfg)) != 0)
4949 return rc;
4950
4951 if (hdr.PageLength == 0)
4952 return 0;
4953
4954 /* Read the config page */
4955 data_sz = hdr.PageLength * 4;
4956 rc = -ENOMEM;
4957 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4958 if (ppage_alloc) {
4959 memset((u8 *)ppage_alloc, 0, data_sz);
4960 cfg.physAddr = page_dma;
4961 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4962
4963 /* If Good, save data */
4964 if ((rc = mpt_config(ioc, &cfg)) == 0)
4965 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4966
4967 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4968 }
4969
4970 return rc;
4971}
4972
4973/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004974/**
4975 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 * @ioc: Pointer to a Adapter Strucutre
4977 * @portnum: IOC port number
4978 *
4979 * Return: -EFAULT if read of config page header fails
4980 * or if no nvram
4981 * If read of SCSI Port Page 0 fails,
4982 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4983 * Adapter settings: async, narrow
4984 * Return 1
4985 * If read of SCSI Port Page 2 fails,
4986 * Adapter settings valid
4987 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4988 * Return 1
4989 * Else
4990 * Both valid
4991 * Return 0
4992 * CHECK - what type of locking mechanisms should be used????
4993 */
4994static int
4995mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4996{
4997 u8 *pbuf;
4998 dma_addr_t buf_dma;
4999 CONFIGPARMS cfg;
5000 ConfigPageHeader_t header;
5001 int ii;
5002 int data, rc = 0;
5003
5004 /* Allocate memory
5005 */
5006 if (!ioc->spi_data.nvram) {
5007 int sz;
5008 u8 *mem;
5009 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5010 mem = kmalloc(sz, GFP_ATOMIC);
5011 if (mem == NULL)
5012 return -EFAULT;
5013
5014 ioc->spi_data.nvram = (int *) mem;
5015
Prakash, Sathya436ace72007-07-24 15:42:08 +05305016 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 ioc->name, ioc->spi_data.nvram, sz));
5018 }
5019
5020 /* Invalidate NVRAM information
5021 */
5022 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5023 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5024 }
5025
5026 /* Read SPP0 header, allocate memory, then read page.
5027 */
5028 header.PageVersion = 0;
5029 header.PageLength = 0;
5030 header.PageNumber = 0;
5031 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005032 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 cfg.physAddr = -1;
5034 cfg.pageAddr = portnum;
5035 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5036 cfg.dir = 0;
5037 cfg.timeout = 0; /* use default */
5038 if (mpt_config(ioc, &cfg) != 0)
5039 return -EFAULT;
5040
5041 if (header.PageLength > 0) {
5042 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5043 if (pbuf) {
5044 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5045 cfg.physAddr = buf_dma;
5046 if (mpt_config(ioc, &cfg) != 0) {
5047 ioc->spi_data.maxBusWidth = MPT_NARROW;
5048 ioc->spi_data.maxSyncOffset = 0;
5049 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5050 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5051 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305052 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5053 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005054 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 } else {
5056 /* Save the Port Page 0 data
5057 */
5058 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5059 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5060 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5061
5062 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5063 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005064 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5065 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 ioc->name, pPP0->Capabilities));
5067 }
5068 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5069 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5070 if (data) {
5071 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5072 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5073 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305074 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5075 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005076 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 } else {
5078 ioc->spi_data.maxSyncOffset = 0;
5079 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5080 }
5081
5082 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5083
5084 /* Update the minSyncFactor based on bus type.
5085 */
5086 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5087 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5088
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005089 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305091 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5092 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005093 ioc->name, ioc->spi_data.minSyncFactor));
5094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095 }
5096 }
5097 if (pbuf) {
5098 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5099 }
5100 }
5101 }
5102
5103 /* SCSI Port Page 2 - Read the header then the page.
5104 */
5105 header.PageVersion = 0;
5106 header.PageLength = 0;
5107 header.PageNumber = 2;
5108 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005109 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 cfg.physAddr = -1;
5111 cfg.pageAddr = portnum;
5112 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5113 cfg.dir = 0;
5114 if (mpt_config(ioc, &cfg) != 0)
5115 return -EFAULT;
5116
5117 if (header.PageLength > 0) {
5118 /* Allocate memory and read SCSI Port Page 2
5119 */
5120 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5121 if (pbuf) {
5122 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5123 cfg.physAddr = buf_dma;
5124 if (mpt_config(ioc, &cfg) != 0) {
5125 /* Nvram data is left with INVALID mark
5126 */
5127 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005128 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5129
5130 /* This is an ATTO adapter, read Page2 accordingly
5131 */
5132 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5133 ATTODeviceInfo_t *pdevice = NULL;
5134 u16 ATTOFlags;
5135
5136 /* Save the Port Page 2 data
5137 * (reformat into a 32bit quantity)
5138 */
5139 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5140 pdevice = &pPP2->DeviceSettings[ii];
5141 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5142 data = 0;
5143
5144 /* Translate ATTO device flags to LSI format
5145 */
5146 if (ATTOFlags & ATTOFLAG_DISC)
5147 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5148 if (ATTOFlags & ATTOFLAG_ID_ENB)
5149 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5150 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5151 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5152 if (ATTOFlags & ATTOFLAG_TAGGED)
5153 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5154 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5155 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5156
5157 data = (data << 16) | (pdevice->Period << 8) | 10;
5158 ioc->spi_data.nvram[ii] = data;
5159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 } else {
5161 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5162 MpiDeviceInfo_t *pdevice = NULL;
5163
Moore, Ericd8e925d2006-01-16 18:53:06 -07005164 /*
5165 * Save "Set to Avoid SCSI Bus Resets" flag
5166 */
5167 ioc->spi_data.bus_reset =
5168 (le32_to_cpu(pPP2->PortFlags) &
5169 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5170 0 : 1 ;
5171
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 /* Save the Port Page 2 data
5173 * (reformat into a 32bit quantity)
5174 */
5175 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5176 ioc->spi_data.PortFlags = data;
5177 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5178 pdevice = &pPP2->DeviceSettings[ii];
5179 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5180 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5181 ioc->spi_data.nvram[ii] = data;
5182 }
5183 }
5184
5185 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5186 }
5187 }
5188
5189 /* Update Adapter limits with those from NVRAM
5190 * Comment: Don't need to do this. Target performance
5191 * parameters will never exceed the adapters limits.
5192 */
5193
5194 return rc;
5195}
5196
5197/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005198/**
5199 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 * @ioc: Pointer to a Adapter Strucutre
5201 * @portnum: IOC port number
5202 *
5203 * Return: -EFAULT if read of config page header fails
5204 * or 0 if success.
5205 */
5206static int
5207mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5208{
5209 CONFIGPARMS cfg;
5210 ConfigPageHeader_t header;
5211
5212 /* Read the SCSI Device Page 1 header
5213 */
5214 header.PageVersion = 0;
5215 header.PageLength = 0;
5216 header.PageNumber = 1;
5217 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005218 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 cfg.physAddr = -1;
5220 cfg.pageAddr = portnum;
5221 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5222 cfg.dir = 0;
5223 cfg.timeout = 0;
5224 if (mpt_config(ioc, &cfg) != 0)
5225 return -EFAULT;
5226
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005227 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5228 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229
5230 header.PageVersion = 0;
5231 header.PageLength = 0;
5232 header.PageNumber = 0;
5233 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5234 if (mpt_config(ioc, &cfg) != 0)
5235 return -EFAULT;
5236
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005237 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5238 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239
Prakash, Sathya436ace72007-07-24 15:42:08 +05305240 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5242
Prakash, Sathya436ace72007-07-24 15:42:08 +05305243 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5245 return 0;
5246}
5247
Eric Mooreb506ade2007-01-29 09:45:37 -07005248/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005249 * mpt_inactive_raid_list_free - This clears this link list.
5250 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005251 **/
5252static void
5253mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5254{
5255 struct inactive_raid_component_info *component_info, *pNext;
5256
5257 if (list_empty(&ioc->raid_data.inactive_list))
5258 return;
5259
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005260 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005261 list_for_each_entry_safe(component_info, pNext,
5262 &ioc->raid_data.inactive_list, list) {
5263 list_del(&component_info->list);
5264 kfree(component_info);
5265 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005266 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005267}
5268
5269/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005270 * 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 -07005271 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005272 * @ioc : pointer to per adapter structure
5273 * @channel : volume channel
5274 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005275 **/
5276static void
5277mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5278{
5279 CONFIGPARMS cfg;
5280 ConfigPageHeader_t hdr;
5281 dma_addr_t dma_handle;
5282 pRaidVolumePage0_t buffer = NULL;
5283 int i;
5284 RaidPhysDiskPage0_t phys_disk;
5285 struct inactive_raid_component_info *component_info;
5286 int handle_inactive_volumes;
5287
5288 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5289 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5290 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5291 cfg.pageAddr = (channel << 8) + id;
5292 cfg.cfghdr.hdr = &hdr;
5293 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5294
5295 if (mpt_config(ioc, &cfg) != 0)
5296 goto out;
5297
5298 if (!hdr.PageLength)
5299 goto out;
5300
5301 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5302 &dma_handle);
5303
5304 if (!buffer)
5305 goto out;
5306
5307 cfg.physAddr = dma_handle;
5308 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5309
5310 if (mpt_config(ioc, &cfg) != 0)
5311 goto out;
5312
5313 if (!buffer->NumPhysDisks)
5314 goto out;
5315
5316 handle_inactive_volumes =
5317 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5318 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5319 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5320 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5321
5322 if (!handle_inactive_volumes)
5323 goto out;
5324
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005325 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005326 for (i = 0; i < buffer->NumPhysDisks; i++) {
5327 if(mpt_raid_phys_disk_pg0(ioc,
5328 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5329 continue;
5330
5331 if ((component_info = kmalloc(sizeof (*component_info),
5332 GFP_KERNEL)) == NULL)
5333 continue;
5334
5335 component_info->volumeID = id;
5336 component_info->volumeBus = channel;
5337 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5338 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5339 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5340 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5341
5342 list_add_tail(&component_info->list,
5343 &ioc->raid_data.inactive_list);
5344 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005345 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005346
5347 out:
5348 if (buffer)
5349 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5350 dma_handle);
5351}
5352
5353/**
5354 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5355 * @ioc: Pointer to a Adapter Structure
5356 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5357 * @phys_disk: requested payload data returned
5358 *
5359 * Return:
5360 * 0 on success
5361 * -EFAULT if read of config page header fails or data pointer not NULL
5362 * -ENOMEM if pci_alloc failed
5363 **/
5364int
5365mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5366{
5367 CONFIGPARMS cfg;
5368 ConfigPageHeader_t hdr;
5369 dma_addr_t dma_handle;
5370 pRaidPhysDiskPage0_t buffer = NULL;
5371 int rc;
5372
5373 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5374 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5375
5376 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5377 cfg.cfghdr.hdr = &hdr;
5378 cfg.physAddr = -1;
5379 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5380
5381 if (mpt_config(ioc, &cfg) != 0) {
5382 rc = -EFAULT;
5383 goto out;
5384 }
5385
5386 if (!hdr.PageLength) {
5387 rc = -EFAULT;
5388 goto out;
5389 }
5390
5391 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5392 &dma_handle);
5393
5394 if (!buffer) {
5395 rc = -ENOMEM;
5396 goto out;
5397 }
5398
5399 cfg.physAddr = dma_handle;
5400 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5401 cfg.pageAddr = phys_disk_num;
5402
5403 if (mpt_config(ioc, &cfg) != 0) {
5404 rc = -EFAULT;
5405 goto out;
5406 }
5407
5408 rc = 0;
5409 memcpy(phys_disk, buffer, sizeof(*buffer));
5410 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5411
5412 out:
5413
5414 if (buffer)
5415 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5416 dma_handle);
5417
5418 return rc;
5419}
5420
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421/**
5422 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5423 * @ioc: Pointer to a Adapter Strucutre
5424 * @portnum: IOC port number
5425 *
5426 * Return:
5427 * 0 on success
5428 * -EFAULT if read of config page header fails or data pointer not NULL
5429 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005430 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431int
5432mpt_findImVolumes(MPT_ADAPTER *ioc)
5433{
5434 IOCPage2_t *pIoc2;
5435 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 dma_addr_t ioc2_dma;
5437 CONFIGPARMS cfg;
5438 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 int rc = 0;
5440 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005441 int i;
5442
5443 if (!ioc->ir_firmware)
5444 return 0;
5445
5446 /* Free the old page
5447 */
5448 kfree(ioc->raid_data.pIocPg2);
5449 ioc->raid_data.pIocPg2 = NULL;
5450 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451
5452 /* Read IOCP2 header then the page.
5453 */
5454 header.PageVersion = 0;
5455 header.PageLength = 0;
5456 header.PageNumber = 2;
5457 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005458 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 cfg.physAddr = -1;
5460 cfg.pageAddr = 0;
5461 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5462 cfg.dir = 0;
5463 cfg.timeout = 0;
5464 if (mpt_config(ioc, &cfg) != 0)
5465 return -EFAULT;
5466
5467 if (header.PageLength == 0)
5468 return -EFAULT;
5469
5470 iocpage2sz = header.PageLength * 4;
5471 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5472 if (!pIoc2)
5473 return -ENOMEM;
5474
5475 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5476 cfg.physAddr = ioc2_dma;
5477 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005478 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479
Eric Mooreb506ade2007-01-29 09:45:37 -07005480 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5481 if (!mem)
5482 goto out;
5483
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005485 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486
Eric Mooreb506ade2007-01-29 09:45:37 -07005487 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
Eric Mooreb506ade2007-01-29 09:45:37 -07005489 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5490 mpt_inactive_raid_volumes(ioc,
5491 pIoc2->RaidVolume[i].VolumeBus,
5492 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493
Eric Mooreb506ade2007-01-29 09:45:37 -07005494 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5496
5497 return rc;
5498}
5499
Moore, Ericc972c702006-03-14 09:14:06 -07005500static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5502{
5503 IOCPage3_t *pIoc3;
5504 u8 *mem;
5505 CONFIGPARMS cfg;
5506 ConfigPageHeader_t header;
5507 dma_addr_t ioc3_dma;
5508 int iocpage3sz = 0;
5509
5510 /* Free the old page
5511 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005512 kfree(ioc->raid_data.pIocPg3);
5513 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514
5515 /* There is at least one physical disk.
5516 * Read and save IOC Page 3
5517 */
5518 header.PageVersion = 0;
5519 header.PageLength = 0;
5520 header.PageNumber = 3;
5521 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005522 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 cfg.physAddr = -1;
5524 cfg.pageAddr = 0;
5525 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5526 cfg.dir = 0;
5527 cfg.timeout = 0;
5528 if (mpt_config(ioc, &cfg) != 0)
5529 return 0;
5530
5531 if (header.PageLength == 0)
5532 return 0;
5533
5534 /* Read Header good, alloc memory
5535 */
5536 iocpage3sz = header.PageLength * 4;
5537 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5538 if (!pIoc3)
5539 return 0;
5540
5541 /* Read the Page and save the data
5542 * into malloc'd memory.
5543 */
5544 cfg.physAddr = ioc3_dma;
5545 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5546 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005547 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 if (mem) {
5549 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005550 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 }
5552 }
5553
5554 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5555
5556 return 0;
5557}
5558
5559static void
5560mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5561{
5562 IOCPage4_t *pIoc4;
5563 CONFIGPARMS cfg;
5564 ConfigPageHeader_t header;
5565 dma_addr_t ioc4_dma;
5566 int iocpage4sz;
5567
5568 /* Read and save IOC Page 4
5569 */
5570 header.PageVersion = 0;
5571 header.PageLength = 0;
5572 header.PageNumber = 4;
5573 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005574 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 cfg.physAddr = -1;
5576 cfg.pageAddr = 0;
5577 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5578 cfg.dir = 0;
5579 cfg.timeout = 0;
5580 if (mpt_config(ioc, &cfg) != 0)
5581 return;
5582
5583 if (header.PageLength == 0)
5584 return;
5585
5586 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5587 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5588 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5589 if (!pIoc4)
5590 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005591 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 } else {
5593 ioc4_dma = ioc->spi_data.IocPg4_dma;
5594 iocpage4sz = ioc->spi_data.IocPg4Sz;
5595 }
5596
5597 /* Read the Page into dma memory.
5598 */
5599 cfg.physAddr = ioc4_dma;
5600 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5601 if (mpt_config(ioc, &cfg) == 0) {
5602 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5603 ioc->spi_data.IocPg4_dma = ioc4_dma;
5604 ioc->spi_data.IocPg4Sz = iocpage4sz;
5605 } else {
5606 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5607 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005608 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 }
5610}
5611
5612static void
5613mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5614{
5615 IOCPage1_t *pIoc1;
5616 CONFIGPARMS cfg;
5617 ConfigPageHeader_t header;
5618 dma_addr_t ioc1_dma;
5619 int iocpage1sz = 0;
5620 u32 tmp;
5621
5622 /* Check the Coalescing Timeout in IOC Page 1
5623 */
5624 header.PageVersion = 0;
5625 header.PageLength = 0;
5626 header.PageNumber = 1;
5627 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005628 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 cfg.physAddr = -1;
5630 cfg.pageAddr = 0;
5631 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5632 cfg.dir = 0;
5633 cfg.timeout = 0;
5634 if (mpt_config(ioc, &cfg) != 0)
5635 return;
5636
5637 if (header.PageLength == 0)
5638 return;
5639
5640 /* Read Header good, alloc memory
5641 */
5642 iocpage1sz = header.PageLength * 4;
5643 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5644 if (!pIoc1)
5645 return;
5646
5647 /* Read the Page and check coalescing timeout
5648 */
5649 cfg.physAddr = ioc1_dma;
5650 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5651 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305652
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5654 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5655 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5656
Prakash, Sathya436ace72007-07-24 15:42:08 +05305657 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 ioc->name, tmp));
5659
5660 if (tmp > MPT_COALESCING_TIMEOUT) {
5661 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5662
5663 /* Write NVRAM and current
5664 */
5665 cfg.dir = 1;
5666 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5667 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305668 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 ioc->name, MPT_COALESCING_TIMEOUT));
5670
5671 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5672 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305673 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5674 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 ioc->name, MPT_COALESCING_TIMEOUT));
5676 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305677 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5678 "Reset NVRAM Coalescing Timeout Failed\n",
5679 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680 }
5681
5682 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305683 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5684 "Reset of Current Coalescing Timeout Failed!\n",
5685 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 }
5687 }
5688
5689 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305690 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 }
5692 }
5693
5694 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5695
5696 return;
5697}
5698
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305699static void
5700mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5701{
5702 CONFIGPARMS cfg;
5703 ConfigPageHeader_t hdr;
5704 dma_addr_t buf_dma;
5705 ManufacturingPage0_t *pbuf = NULL;
5706
5707 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5708 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5709
5710 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5711 cfg.cfghdr.hdr = &hdr;
5712 cfg.physAddr = -1;
5713 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5714 cfg.timeout = 10;
5715
5716 if (mpt_config(ioc, &cfg) != 0)
5717 goto out;
5718
5719 if (!cfg.cfghdr.hdr->PageLength)
5720 goto out;
5721
5722 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5723 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5724 if (!pbuf)
5725 goto out;
5726
5727 cfg.physAddr = buf_dma;
5728
5729 if (mpt_config(ioc, &cfg) != 0)
5730 goto out;
5731
5732 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5733 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5734 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5735
5736 out:
5737
5738 if (pbuf)
5739 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5740}
5741
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005743/**
5744 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 * @ioc: Pointer to MPT_ADAPTER structure
5746 * @EvSwitch: Event switch flags
5747 */
5748static int
5749SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5750{
5751 EventNotification_t *evnp;
5752
5753 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5754 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305755 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756 ioc->name));
5757 return 0;
5758 }
5759 memset(evnp, 0, sizeof(*evnp));
5760
Prakash, Sathya436ace72007-07-24 15:42:08 +05305761 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762
5763 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5764 evnp->ChainOffset = 0;
5765 evnp->MsgFlags = 0;
5766 evnp->Switch = EvSwitch;
5767
5768 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5769
5770 return 0;
5771}
5772
5773/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5774/**
5775 * SendEventAck - Send EventAck request to MPT adapter.
5776 * @ioc: Pointer to MPT_ADAPTER structure
5777 * @evnp: Pointer to original EventNotification request
5778 */
5779static int
5780SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5781{
5782 EventAck_t *pAck;
5783
5784 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305785 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005786 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787 return -1;
5788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
Prakash, Sathya436ace72007-07-24 15:42:08 +05305790 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
5792 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5793 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005794 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005796 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797 pAck->Event = evnp->Event;
5798 pAck->EventContext = evnp->EventContext;
5799
5800 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5801
5802 return 0;
5803}
5804
5805/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5806/**
5807 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005808 * @ioc: Pointer to an adapter structure
5809 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810 * action, page address, direction, physical address
5811 * and pointer to a configuration page header
5812 * Page header is updated.
5813 *
5814 * Returns 0 for success
5815 * -EPERM if not allowed due to ISR context
5816 * -EAGAIN if no msg frames currently available
5817 * -EFAULT for non-successful reply or no reply (timeout)
5818 */
5819int
5820mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5821{
5822 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005823 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824 MPT_FRAME_HDR *mf;
5825 unsigned long flags;
5826 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005827 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828 int in_isr;
5829
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005830 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 * to be in ISR context, because that is fatal!
5832 */
5833 in_isr = in_interrupt();
5834 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305835 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836 ioc->name));
5837 return -EPERM;
5838 }
5839
5840 /* Get and Populate a free Frame
5841 */
5842 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305843 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844 ioc->name));
5845 return -EAGAIN;
5846 }
5847 pReq = (Config_t *)mf;
5848 pReq->Action = pCfg->action;
5849 pReq->Reserved = 0;
5850 pReq->ChainOffset = 0;
5851 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005852
5853 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 pReq->ExtPageLength = 0;
5855 pReq->ExtPageType = 0;
5856 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005857
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 for (ii=0; ii < 8; ii++)
5859 pReq->Reserved2[ii] = 0;
5860
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005861 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5862 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5863 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5864 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5865
5866 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5867 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5868 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5869 pReq->ExtPageType = pExtHdr->ExtPageType;
5870 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5871
5872 /* Page Length must be treated as a reserved field for the extended header. */
5873 pReq->Header.PageLength = 0;
5874 }
5875
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5877
5878 /* Add a SGE to the config request.
5879 */
5880 if (pCfg->dir)
5881 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5882 else
5883 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5884
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005885 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5886 flagsLength |= pExtHdr->ExtPageLength * 4;
5887
Prakash, Sathya436ace72007-07-24 15:42:08 +05305888 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 +02005889 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5890 }
5891 else {
5892 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5893
Prakash, Sathya436ace72007-07-24 15:42:08 +05305894 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 +02005895 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897
5898 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5899
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900 /* Append pCfg pointer to end of mf
5901 */
5902 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5903
5904 /* Initalize the timer
5905 */
5906 init_timer(&pCfg->timer);
5907 pCfg->timer.data = (unsigned long) ioc;
5908 pCfg->timer.function = mpt_timer_expired;
5909 pCfg->wait_done = 0;
5910
5911 /* Set the timer; ensure 10 second minimum */
5912 if (pCfg->timeout < 10)
5913 pCfg->timer.expires = jiffies + HZ*10;
5914 else
5915 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5916
5917 /* Add to end of Q, set timer and then issue this command */
5918 spin_lock_irqsave(&ioc->FreeQlock, flags);
5919 list_add_tail(&pCfg->linkage, &ioc->configQ);
5920 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5921
5922 add_timer(&pCfg->timer);
5923 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5924 wait_event(mpt_waitq, pCfg->wait_done);
5925
5926 /* mf has been freed - do not access */
5927
5928 rc = pCfg->status;
5929
5930 return rc;
5931}
5932
5933/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005934/**
5935 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 * Used only internal config functionality.
5937 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5938 */
5939static void
5940mpt_timer_expired(unsigned long data)
5941{
5942 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5943
Prakash, Sathya436ace72007-07-24 15:42:08 +05305944 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945
5946 /* Perform a FW reload */
5947 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5948 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5949
5950 /* No more processing.
5951 * Hard reset clean-up will wake up
5952 * process and free all resources.
5953 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305954 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955
5956 return;
5957}
5958
5959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005960/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 * mpt_ioc_reset - Base cleanup for hard reset
5962 * @ioc: Pointer to the adapter structure
5963 * @reset_phase: Indicates pre- or post-reset functionality
5964 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005965 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 */
5967static int
5968mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5969{
5970 CONFIGPARMS *pCfg;
5971 unsigned long flags;
5972
Eric Moore29dd3602007-09-14 18:46:51 -06005973 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5974 ": IOC %s_reset routed to MPT base driver!\n",
5975 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5976 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977
5978 if (reset_phase == MPT_IOC_SETUP_RESET) {
5979 ;
5980 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5981 /* If the internal config Q is not empty -
5982 * delete timer. MF resources will be freed when
5983 * the FIFO's are primed.
5984 */
5985 spin_lock_irqsave(&ioc->FreeQlock, flags);
5986 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5987 del_timer(&pCfg->timer);
5988 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5989
5990 } else {
5991 CONFIGPARMS *pNext;
5992
5993 /* Search the configQ for internal commands.
5994 * Flush the Q, and wake up all suspended threads.
5995 */
5996 spin_lock_irqsave(&ioc->FreeQlock, flags);
5997 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5998 list_del(&pCfg->linkage);
5999
6000 pCfg->status = MPT_CONFIG_ERROR;
6001 pCfg->wait_done = 1;
6002 wake_up(&mpt_waitq);
6003 }
6004 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6005 }
6006
6007 return 1; /* currently means nothing really */
6008}
6009
6010
6011#ifdef CONFIG_PROC_FS /* { */
6012/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6013/*
6014 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6015 */
6016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006017/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6019 *
6020 * Returns 0 for success, non-zero for failure.
6021 */
6022static int
6023procmpt_create(void)
6024{
6025 struct proc_dir_entry *ent;
6026
6027 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6028 if (mpt_proc_root_dir == NULL)
6029 return -ENOTDIR;
6030
6031 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6032 if (ent)
6033 ent->read_proc = procmpt_summary_read;
6034
6035 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6036 if (ent)
6037 ent->read_proc = procmpt_version_read;
6038
6039 return 0;
6040}
6041
6042/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006043/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6045 *
6046 * Returns 0 for success, non-zero for failure.
6047 */
6048static void
6049procmpt_destroy(void)
6050{
6051 remove_proc_entry("version", mpt_proc_root_dir);
6052 remove_proc_entry("summary", mpt_proc_root_dir);
6053 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6054}
6055
6056/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006057/**
6058 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 * @buf: Pointer to area to write information
6060 * @start: Pointer to start pointer
6061 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006062 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063 * @eof: Pointer to EOF integer
6064 * @data: Pointer
6065 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006066 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 * Returns number of characters written to process performing the read.
6068 */
6069static int
6070procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6071{
6072 MPT_ADAPTER *ioc;
6073 char *out = buf;
6074 int len;
6075
6076 if (data) {
6077 int more = 0;
6078
6079 ioc = data;
6080 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6081
6082 out += more;
6083 } else {
6084 list_for_each_entry(ioc, &ioc_list, list) {
6085 int more = 0;
6086
6087 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6088
6089 out += more;
6090 if ((out-buf) >= request)
6091 break;
6092 }
6093 }
6094
6095 len = out - buf;
6096
6097 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6098}
6099
6100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006101/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 * procmpt_version_read - Handle read request from /proc/mpt/version.
6103 * @buf: Pointer to area to write information
6104 * @start: Pointer to start pointer
6105 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006106 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107 * @eof: Pointer to EOF integer
6108 * @data: Pointer
6109 *
6110 * Returns number of characters written to process performing the read.
6111 */
6112static int
6113procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6114{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306115 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006116 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006117 char *drvname;
6118 int len;
6119
6120 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6121 len += sprintf(buf+len, " Fusion MPT base driver\n");
6122
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006123 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006124 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306126 if (MptCallbacks[cb_idx]) {
6127 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006128 case MPTSPI_DRIVER:
6129 if (!scsi++) drvname = "SPI host";
6130 break;
6131 case MPTFC_DRIVER:
6132 if (!fc++) drvname = "FC host";
6133 break;
6134 case MPTSAS_DRIVER:
6135 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 break;
6137 case MPTLAN_DRIVER:
6138 if (!lan++) drvname = "LAN";
6139 break;
6140 case MPTSTM_DRIVER:
6141 if (!targ++) drvname = "SCSI target";
6142 break;
6143 case MPTCTL_DRIVER:
6144 if (!ctl++) drvname = "ioctl";
6145 break;
6146 }
6147
6148 if (drvname)
6149 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6150 }
6151 }
6152
6153 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6154}
6155
6156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006157/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6159 * @buf: Pointer to area to write information
6160 * @start: Pointer to start pointer
6161 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006162 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 * @eof: Pointer to EOF integer
6164 * @data: Pointer
6165 *
6166 * Returns number of characters written to process performing the read.
6167 */
6168static int
6169procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6170{
6171 MPT_ADAPTER *ioc = data;
6172 int len;
6173 char expVer[32];
6174 int sz;
6175 int p;
6176
6177 mpt_get_fw_exp_ver(expVer, ioc);
6178
6179 len = sprintf(buf, "%s:", ioc->name);
6180 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6181 len += sprintf(buf+len, " (f/w download boot flag set)");
6182// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6183// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6184
6185 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6186 ioc->facts.ProductID,
6187 ioc->prod_name);
6188 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6189 if (ioc->facts.FWImageSize)
6190 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6191 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6192 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6193 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6194
6195 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6196 ioc->facts.CurrentHostMfaHighAddr);
6197 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6198 ioc->facts.CurrentSenseBufferHighAddr);
6199
6200 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6201 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6202
6203 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6204 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6205 /*
6206 * Rounding UP to nearest 4-kB boundary here...
6207 */
6208 sz = (ioc->req_sz * ioc->req_depth) + 128;
6209 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6210 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6211 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6212 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6213 4*ioc->facts.RequestFrameSize,
6214 ioc->facts.GlobalCredits);
6215
6216 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6217 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6218 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6219 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6220 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6221 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6222 ioc->facts.CurReplyFrameSize,
6223 ioc->facts.ReplyQueueDepth);
6224
6225 len += sprintf(buf+len, " MaxDevices = %d\n",
6226 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6227 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6228
6229 /* per-port info */
6230 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6231 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6232 p+1,
6233 ioc->facts.NumberOfPorts);
6234 if (ioc->bus_type == FC) {
6235 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6236 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6237 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6238 a[5], a[4], a[3], a[2], a[1], a[0]);
6239 }
6240 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6241 ioc->fc_port_page0[p].WWNN.High,
6242 ioc->fc_port_page0[p].WWNN.Low,
6243 ioc->fc_port_page0[p].WWPN.High,
6244 ioc->fc_port_page0[p].WWPN.Low);
6245 }
6246 }
6247
6248 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6249}
6250
6251#endif /* CONFIG_PROC_FS } */
6252
6253/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6254static void
6255mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6256{
6257 buf[0] ='\0';
6258 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6259 sprintf(buf, " (Exp %02d%02d)",
6260 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6261 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6262
6263 /* insider hack! */
6264 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6265 strcat(buf, " [MDBG]");
6266 }
6267}
6268
6269/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6270/**
6271 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6272 * @ioc: Pointer to MPT_ADAPTER structure
6273 * @buffer: Pointer to buffer where IOC summary info should be written
6274 * @size: Pointer to number of bytes we wrote (set by this routine)
6275 * @len: Offset at which to start writing in buffer
6276 * @showlan: Display LAN stuff?
6277 *
6278 * This routine writes (english readable) ASCII text, which represents
6279 * a summary of IOC information, to a buffer.
6280 */
6281void
6282mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6283{
6284 char expVer[32];
6285 int y;
6286
6287 mpt_get_fw_exp_ver(expVer, ioc);
6288
6289 /*
6290 * Shorter summary of attached ioc's...
6291 */
6292 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6293 ioc->name,
6294 ioc->prod_name,
6295 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6296 ioc->facts.FWVersion.Word,
6297 expVer,
6298 ioc->facts.NumberOfPorts,
6299 ioc->req_depth);
6300
6301 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6302 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6303 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6304 a[5], a[4], a[3], a[2], a[1], a[0]);
6305 }
6306
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308
6309 if (!ioc->active)
6310 y += sprintf(buffer+len+y, " (disabled)");
6311
6312 y += sprintf(buffer+len+y, "\n");
6313
6314 *size = y;
6315}
6316
6317/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6318/*
6319 * Reset Handling
6320 */
6321/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6322/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006323 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324 * @ioc: Pointer to MPT_ADAPTER structure
6325 * @sleepFlag: Indicates if sleep or schedule must be called.
6326 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006327 * Issues SCSI Task Management call based on input arg values.
6328 * If TaskMgmt fails, returns associated SCSI request.
6329 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6331 * or a non-interrupt thread. In the former, must not call schedule().
6332 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006333 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 * FW reload/initialization failed.
6335 *
6336 * Returns 0 for SUCCESS or -1 if FAILED.
6337 */
6338int
6339mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6340{
6341 int rc;
6342 unsigned long flags;
6343
Prakash, Sathya436ace72007-07-24 15:42:08 +05306344 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345#ifdef MFCNT
6346 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6347 printk("MF count 0x%x !\n", ioc->mfcnt);
6348#endif
6349
6350 /* Reset the adapter. Prevent more than 1 call to
6351 * mpt_do_ioc_recovery at any instant in time.
6352 */
6353 spin_lock_irqsave(&ioc->diagLock, flags);
6354 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6355 spin_unlock_irqrestore(&ioc->diagLock, flags);
6356 return 0;
6357 } else {
6358 ioc->diagPending = 1;
6359 }
6360 spin_unlock_irqrestore(&ioc->diagLock, flags);
6361
6362 /* FIXME: If do_ioc_recovery fails, repeat....
6363 */
6364
6365 /* The SCSI driver needs to adjust timeouts on all current
6366 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006367 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 * For all other protocol drivers, this is a no-op.
6369 */
6370 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306371 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 int r = 0;
6373
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306374 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6375 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306376 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306377 ioc->name, cb_idx));
6378 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306380 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306381 ioc->name, ioc->alt_ioc->name, cb_idx));
6382 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 }
6384 }
6385 }
6386 }
6387
6388 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006389 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006390 }
6391 ioc->reload_fw = 0;
6392 if (ioc->alt_ioc)
6393 ioc->alt_ioc->reload_fw = 0;
6394
6395 spin_lock_irqsave(&ioc->diagLock, flags);
6396 ioc->diagPending = 0;
6397 if (ioc->alt_ioc)
6398 ioc->alt_ioc->diagPending = 0;
6399 spin_unlock_irqrestore(&ioc->diagLock, flags);
6400
Prakash, Sathya436ace72007-07-24 15:42:08 +05306401 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402
6403 return rc;
6404}
6405
6406/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006407static void
6408EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409{
Eric Moore509e5e52006-04-26 13:22:37 -06006410 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411
6412 switch(event) {
6413 case MPI_EVENT_NONE:
6414 ds = "None";
6415 break;
6416 case MPI_EVENT_LOG_DATA:
6417 ds = "Log Data";
6418 break;
6419 case MPI_EVENT_STATE_CHANGE:
6420 ds = "State Change";
6421 break;
6422 case MPI_EVENT_UNIT_ATTENTION:
6423 ds = "Unit Attention";
6424 break;
6425 case MPI_EVENT_IOC_BUS_RESET:
6426 ds = "IOC Bus Reset";
6427 break;
6428 case MPI_EVENT_EXT_BUS_RESET:
6429 ds = "External Bus Reset";
6430 break;
6431 case MPI_EVENT_RESCAN:
6432 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006433 break;
6434 case MPI_EVENT_LINK_STATUS_CHANGE:
6435 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6436 ds = "Link Status(FAILURE) Change";
6437 else
6438 ds = "Link Status(ACTIVE) Change";
6439 break;
6440 case MPI_EVENT_LOOP_STATE_CHANGE:
6441 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6442 ds = "Loop State(LIP) Change";
6443 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006444 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445 else
Eric Moore509e5e52006-04-26 13:22:37 -06006446 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447 break;
6448 case MPI_EVENT_LOGOUT:
6449 ds = "Logout";
6450 break;
6451 case MPI_EVENT_EVENT_CHANGE:
6452 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006453 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006454 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006455 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456 break;
6457 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006458 {
6459 u8 ReasonCode = (u8)(evData0 >> 16);
6460 switch (ReasonCode) {
6461 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6462 ds = "Integrated Raid: Volume Created";
6463 break;
6464 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6465 ds = "Integrated Raid: Volume Deleted";
6466 break;
6467 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6468 ds = "Integrated Raid: Volume Settings Changed";
6469 break;
6470 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6471 ds = "Integrated Raid: Volume Status Changed";
6472 break;
6473 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6474 ds = "Integrated Raid: Volume Physdisk Changed";
6475 break;
6476 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6477 ds = "Integrated Raid: Physdisk Created";
6478 break;
6479 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6480 ds = "Integrated Raid: Physdisk Deleted";
6481 break;
6482 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6483 ds = "Integrated Raid: Physdisk Settings Changed";
6484 break;
6485 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6486 ds = "Integrated Raid: Physdisk Status Changed";
6487 break;
6488 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6489 ds = "Integrated Raid: Domain Validation Needed";
6490 break;
6491 case MPI_EVENT_RAID_RC_SMART_DATA :
6492 ds = "Integrated Raid; Smart Data";
6493 break;
6494 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6495 ds = "Integrated Raid: Replace Action Started";
6496 break;
6497 default:
6498 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006499 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006500 }
6501 break;
6502 }
6503 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6504 ds = "SCSI Device Status Change";
6505 break;
6506 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6507 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006508 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006509 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006510 u8 ReasonCode = (u8)(evData0 >> 16);
6511 switch (ReasonCode) {
6512 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006513 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006514 "SAS Device Status Change: Added: "
6515 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006516 break;
6517 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006518 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006519 "SAS Device Status Change: Deleted: "
6520 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006521 break;
6522 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006523 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006524 "SAS Device Status Change: SMART Data: "
6525 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006526 break;
6527 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006528 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006529 "SAS Device Status Change: No Persistancy: "
6530 "id=%d channel=%d", id, channel);
6531 break;
6532 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6533 snprintf(evStr, EVENT_DESCR_STR_SZ,
6534 "SAS Device Status Change: Unsupported Device "
6535 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006536 break;
6537 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6538 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006539 "SAS Device Status Change: Internal Device "
6540 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006541 break;
6542 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6543 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006544 "SAS Device Status Change: Internal Task "
6545 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006546 break;
6547 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6548 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006549 "SAS Device Status Change: Internal Abort "
6550 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006551 break;
6552 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6553 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006554 "SAS Device Status Change: Internal Clear "
6555 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006556 break;
6557 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6558 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006559 "SAS Device Status Change: Internal Query "
6560 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006561 break;
6562 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006563 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006564 "SAS Device Status Change: Unknown: "
6565 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006566 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006567 }
6568 break;
6569 }
6570 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6571 ds = "Bus Timer Expired";
6572 break;
6573 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006574 {
6575 u16 curr_depth = (u16)(evData0 >> 16);
6576 u8 channel = (u8)(evData0 >> 8);
6577 u8 id = (u8)(evData0);
6578
6579 snprintf(evStr, EVENT_DESCR_STR_SZ,
6580 "Queue Full: channel=%d id=%d depth=%d",
6581 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006582 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006583 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006584 case MPI_EVENT_SAS_SES:
6585 ds = "SAS SES Event";
6586 break;
6587 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6588 ds = "Persistent Table Full";
6589 break;
6590 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006591 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006592 u8 LinkRates = (u8)(evData0 >> 8);
6593 u8 PhyNumber = (u8)(evData0);
6594 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6595 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6596 switch (LinkRates) {
6597 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006598 snprintf(evStr, EVENT_DESCR_STR_SZ,
6599 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006600 " Rate Unknown",PhyNumber);
6601 break;
6602 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006603 snprintf(evStr, EVENT_DESCR_STR_SZ,
6604 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006605 " Phy Disabled",PhyNumber);
6606 break;
6607 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006608 snprintf(evStr, EVENT_DESCR_STR_SZ,
6609 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006610 " Failed Speed Nego",PhyNumber);
6611 break;
6612 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006613 snprintf(evStr, EVENT_DESCR_STR_SZ,
6614 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006615 " Sata OOB Completed",PhyNumber);
6616 break;
6617 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006618 snprintf(evStr, EVENT_DESCR_STR_SZ,
6619 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006620 " Rate 1.5 Gbps",PhyNumber);
6621 break;
6622 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006623 snprintf(evStr, EVENT_DESCR_STR_SZ,
6624 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006625 " Rate 3.0 Gpbs",PhyNumber);
6626 break;
6627 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006628 snprintf(evStr, EVENT_DESCR_STR_SZ,
6629 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006630 break;
6631 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006632 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006633 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006634 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6635 ds = "SAS Discovery Error";
6636 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006637 case MPI_EVENT_IR_RESYNC_UPDATE:
6638 {
6639 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006640 snprintf(evStr, EVENT_DESCR_STR_SZ,
6641 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006642 break;
6643 }
6644 case MPI_EVENT_IR2:
6645 {
6646 u8 ReasonCode = (u8)(evData0 >> 16);
6647 switch (ReasonCode) {
6648 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6649 ds = "IR2: LD State Changed";
6650 break;
6651 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6652 ds = "IR2: PD State Changed";
6653 break;
6654 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6655 ds = "IR2: Bad Block Table Full";
6656 break;
6657 case MPI_EVENT_IR2_RC_PD_INSERTED:
6658 ds = "IR2: PD Inserted";
6659 break;
6660 case MPI_EVENT_IR2_RC_PD_REMOVED:
6661 ds = "IR2: PD Removed";
6662 break;
6663 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6664 ds = "IR2: Foreign CFG Detected";
6665 break;
6666 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6667 ds = "IR2: Rebuild Medium Error";
6668 break;
6669 default:
6670 ds = "IR2";
6671 break;
6672 }
6673 break;
6674 }
6675 case MPI_EVENT_SAS_DISCOVERY:
6676 {
6677 if (evData0)
6678 ds = "SAS Discovery: Start";
6679 else
6680 ds = "SAS Discovery: Stop";
6681 break;
6682 }
6683 case MPI_EVENT_LOG_ENTRY_ADDED:
6684 ds = "SAS Log Entry Added";
6685 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006686
Eric Moorec6c727a2007-01-29 09:44:54 -07006687 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6688 {
6689 u8 phy_num = (u8)(evData0);
6690 u8 port_num = (u8)(evData0 >> 8);
6691 u8 port_width = (u8)(evData0 >> 16);
6692 u8 primative = (u8)(evData0 >> 24);
6693 snprintf(evStr, EVENT_DESCR_STR_SZ,
6694 "SAS Broadcase Primative: phy=%d port=%d "
6695 "width=%d primative=0x%02x",
6696 phy_num, port_num, port_width, primative);
6697 break;
6698 }
6699
6700 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6701 {
6702 u8 reason = (u8)(evData0);
6703 u8 port_num = (u8)(evData0 >> 8);
6704 u16 handle = le16_to_cpu(evData0 >> 16);
6705
6706 snprintf(evStr, EVENT_DESCR_STR_SZ,
6707 "SAS Initiator Device Status Change: reason=0x%02x "
6708 "port=%d handle=0x%04x",
6709 reason, port_num, handle);
6710 break;
6711 }
6712
6713 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6714 {
6715 u8 max_init = (u8)(evData0);
6716 u8 current_init = (u8)(evData0 >> 8);
6717
6718 snprintf(evStr, EVENT_DESCR_STR_SZ,
6719 "SAS Initiator Device Table Overflow: max initiators=%02d "
6720 "current initators=%02d",
6721 max_init, current_init);
6722 break;
6723 }
6724 case MPI_EVENT_SAS_SMP_ERROR:
6725 {
6726 u8 status = (u8)(evData0);
6727 u8 port_num = (u8)(evData0 >> 8);
6728 u8 result = (u8)(evData0 >> 16);
6729
6730 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6731 snprintf(evStr, EVENT_DESCR_STR_SZ,
6732 "SAS SMP Error: port=%d result=0x%02x",
6733 port_num, result);
6734 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6735 snprintf(evStr, EVENT_DESCR_STR_SZ,
6736 "SAS SMP Error: port=%d : CRC Error",
6737 port_num);
6738 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6739 snprintf(evStr, EVENT_DESCR_STR_SZ,
6740 "SAS SMP Error: port=%d : Timeout",
6741 port_num);
6742 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6743 snprintf(evStr, EVENT_DESCR_STR_SZ,
6744 "SAS SMP Error: port=%d : No Destination",
6745 port_num);
6746 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6747 snprintf(evStr, EVENT_DESCR_STR_SZ,
6748 "SAS SMP Error: port=%d : Bad Destination",
6749 port_num);
6750 else
6751 snprintf(evStr, EVENT_DESCR_STR_SZ,
6752 "SAS SMP Error: port=%d : status=0x%02x",
6753 port_num, status);
6754 break;
6755 }
6756
Linus Torvalds1da177e2005-04-16 15:20:36 -07006757 /*
6758 * MPT base "custom" events may be added here...
6759 */
6760 default:
6761 ds = "Unknown";
6762 break;
6763 }
Eric Moore509e5e52006-04-26 13:22:37 -06006764 if (ds)
6765 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006766}
6767
6768/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006769/**
6770 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771 * @ioc: Pointer to MPT_ADAPTER structure
6772 * @pEventReply: Pointer to EventNotification reply frame
6773 * @evHandlers: Pointer to integer, number of event handlers
6774 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006775 * Routes a received EventNotificationReply to all currently registered
6776 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006777 * Returns sum of event handlers return values.
6778 */
6779static int
6780ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6781{
6782 u16 evDataLen;
6783 u32 evData0 = 0;
6784// u32 evCtx;
6785 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306786 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006787 int r = 0;
6788 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006789 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006790 u8 event;
6791
6792 /*
6793 * Do platform normalization of values
6794 */
6795 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6796// evCtx = le32_to_cpu(pEventReply->EventContext);
6797 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6798 if (evDataLen) {
6799 evData0 = le32_to_cpu(pEventReply->Data[0]);
6800 }
6801
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006802 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306803 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006804 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006805 event,
6806 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006807
Prakash, Sathya436ace72007-07-24 15:42:08 +05306808#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006809 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6810 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006811 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306812 devtverboseprintk(ioc, printk(" %08x",
6813 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006814 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006815#endif
6816
6817 /*
6818 * Do general / base driver event processing
6819 */
6820 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006821 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6822 if (evDataLen) {
6823 u8 evState = evData0 & 0xFF;
6824
6825 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6826
6827 /* Update EventState field in cached IocFacts */
6828 if (ioc->facts.Function) {
6829 ioc->facts.EventState = evState;
6830 }
6831 }
6832 break;
Moore, Ericece50912006-01-16 18:53:19 -07006833 case MPI_EVENT_INTEGRATED_RAID:
6834 mptbase_raid_process_event_data(ioc,
6835 (MpiEventDataRaid_t *)pEventReply->Data);
6836 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006837 default:
6838 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006839 }
6840
6841 /*
6842 * Should this event be logged? Events are written sequentially.
6843 * When buffer is full, start again at the top.
6844 */
6845 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6846 int idx;
6847
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006848 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006849
6850 ioc->events[idx].event = event;
6851 ioc->events[idx].eventContext = ioc->eventContext;
6852
6853 for (ii = 0; ii < 2; ii++) {
6854 if (ii < evDataLen)
6855 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6856 else
6857 ioc->events[idx].data[ii] = 0;
6858 }
6859
6860 ioc->eventContext++;
6861 }
6862
6863
6864 /*
6865 * Call each currently registered protocol event handler.
6866 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006867 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306868 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306869 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306870 ioc->name, cb_idx));
6871 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006872 handlers++;
6873 }
6874 }
6875 /* FIXME? Examine results here? */
6876
6877 /*
6878 * If needed, send (a single) EventAck.
6879 */
6880 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306881 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006882 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006883 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306884 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006885 ioc->name, ii));
6886 }
6887 }
6888
6889 *evHandlers = handlers;
6890 return r;
6891}
6892
6893/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006894/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006895 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6896 * @ioc: Pointer to MPT_ADAPTER structure
6897 * @log_info: U32 LogInfo reply word from the IOC
6898 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006899 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006900 */
6901static void
6902mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6903{
Eric Moore7c431e52007-06-13 16:34:36 -06006904 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006905
Eric Moore7c431e52007-06-13 16:34:36 -06006906 switch (log_info & 0xFF000000) {
6907 case MPI_IOCLOGINFO_FC_INIT_BASE:
6908 desc = "FCP Initiator";
6909 break;
6910 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6911 desc = "FCP Target";
6912 break;
6913 case MPI_IOCLOGINFO_FC_LAN_BASE:
6914 desc = "LAN";
6915 break;
6916 case MPI_IOCLOGINFO_FC_MSG_BASE:
6917 desc = "MPI Message Layer";
6918 break;
6919 case MPI_IOCLOGINFO_FC_LINK_BASE:
6920 desc = "FC Link";
6921 break;
6922 case MPI_IOCLOGINFO_FC_CTX_BASE:
6923 desc = "Context Manager";
6924 break;
6925 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6926 desc = "Invalid Field Offset";
6927 break;
6928 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6929 desc = "State Change Info";
6930 break;
6931 }
6932
6933 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6934 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935}
6936
6937/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006938/**
Moore, Eric335a9412006-01-17 17:06:23 -07006939 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006940 * @ioc: Pointer to MPT_ADAPTER structure
6941 * @mr: Pointer to MPT reply frame
6942 * @log_info: U32 LogInfo word from the IOC
6943 *
6944 * Refer to lsi/sp_log.h.
6945 */
6946static void
Moore, Eric335a9412006-01-17 17:06:23 -07006947mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006948{
6949 u32 info = log_info & 0x00FF0000;
6950 char *desc = "unknown";
6951
6952 switch (info) {
6953 case 0x00010000:
6954 desc = "bug! MID not found";
6955 if (ioc->reload_fw == 0)
6956 ioc->reload_fw++;
6957 break;
6958
6959 case 0x00020000:
6960 desc = "Parity Error";
6961 break;
6962
6963 case 0x00030000:
6964 desc = "ASYNC Outbound Overrun";
6965 break;
6966
6967 case 0x00040000:
6968 desc = "SYNC Offset Error";
6969 break;
6970
6971 case 0x00050000:
6972 desc = "BM Change";
6973 break;
6974
6975 case 0x00060000:
6976 desc = "Msg In Overflow";
6977 break;
6978
6979 case 0x00070000:
6980 desc = "DMA Error";
6981 break;
6982
6983 case 0x00080000:
6984 desc = "Outbound DMA Overrun";
6985 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006986
Linus Torvalds1da177e2005-04-16 15:20:36 -07006987 case 0x00090000:
6988 desc = "Task Management";
6989 break;
6990
6991 case 0x000A0000:
6992 desc = "Device Problem";
6993 break;
6994
6995 case 0x000B0000:
6996 desc = "Invalid Phase Change";
6997 break;
6998
6999 case 0x000C0000:
7000 desc = "Untagged Table Size";
7001 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007002
Linus Torvalds1da177e2005-04-16 15:20:36 -07007003 }
7004
7005 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7006}
7007
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007008/* strings for sas loginfo */
7009 static char *originator_str[] = {
7010 "IOP", /* 00h */
7011 "PL", /* 01h */
7012 "IR" /* 02h */
7013 };
7014 static char *iop_code_str[] = {
7015 NULL, /* 00h */
7016 "Invalid SAS Address", /* 01h */
7017 NULL, /* 02h */
7018 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007019 "Diag Message Error", /* 04h */
7020 "Task Terminated", /* 05h */
7021 "Enclosure Management", /* 06h */
7022 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007023 };
7024 static char *pl_code_str[] = {
7025 NULL, /* 00h */
7026 "Open Failure", /* 01h */
7027 "Invalid Scatter Gather List", /* 02h */
7028 "Wrong Relative Offset or Frame Length", /* 03h */
7029 "Frame Transfer Error", /* 04h */
7030 "Transmit Frame Connected Low", /* 05h */
7031 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7032 "SATA Read Log Receive Data Error", /* 07h */
7033 "SATA NCQ Fail All Commands After Error", /* 08h */
7034 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7035 "Receive Frame Invalid Message", /* 0Ah */
7036 "Receive Context Message Valid Error", /* 0Bh */
7037 "Receive Frame Current Frame Error", /* 0Ch */
7038 "SATA Link Down", /* 0Dh */
7039 "Discovery SATA Init W IOS", /* 0Eh */
7040 "Config Invalid Page", /* 0Fh */
7041 "Discovery SATA Init Timeout", /* 10h */
7042 "Reset", /* 11h */
7043 "Abort", /* 12h */
7044 "IO Not Yet Executed", /* 13h */
7045 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007046 "Persistent Reservation Out Not Affiliation "
7047 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007048 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007049 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007050 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007051 NULL, /* 19h */
7052 NULL, /* 1Ah */
7053 NULL, /* 1Bh */
7054 NULL, /* 1Ch */
7055 NULL, /* 1Dh */
7056 NULL, /* 1Eh */
7057 NULL, /* 1Fh */
7058 "Enclosure Management" /* 20h */
7059 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007060 static char *ir_code_str[] = {
7061 "Raid Action Error", /* 00h */
7062 NULL, /* 00h */
7063 NULL, /* 01h */
7064 NULL, /* 02h */
7065 NULL, /* 03h */
7066 NULL, /* 04h */
7067 NULL, /* 05h */
7068 NULL, /* 06h */
7069 NULL /* 07h */
7070 };
7071 static char *raid_sub_code_str[] = {
7072 NULL, /* 00h */
7073 "Volume Creation Failed: Data Passed too "
7074 "Large", /* 01h */
7075 "Volume Creation Failed: Duplicate Volumes "
7076 "Attempted", /* 02h */
7077 "Volume Creation Failed: Max Number "
7078 "Supported Volumes Exceeded", /* 03h */
7079 "Volume Creation Failed: DMA Error", /* 04h */
7080 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7081 "Volume Creation Failed: Error Reading "
7082 "MFG Page 4", /* 06h */
7083 "Volume Creation Failed: Creating Internal "
7084 "Structures", /* 07h */
7085 NULL, /* 08h */
7086 NULL, /* 09h */
7087 NULL, /* 0Ah */
7088 NULL, /* 0Bh */
7089 NULL, /* 0Ch */
7090 NULL, /* 0Dh */
7091 NULL, /* 0Eh */
7092 NULL, /* 0Fh */
7093 "Activation failed: Already Active Volume", /* 10h */
7094 "Activation failed: Unsupported Volume Type", /* 11h */
7095 "Activation failed: Too Many Active Volumes", /* 12h */
7096 "Activation failed: Volume ID in Use", /* 13h */
7097 "Activation failed: Reported Failure", /* 14h */
7098 "Activation failed: Importing a Volume", /* 15h */
7099 NULL, /* 16h */
7100 NULL, /* 17h */
7101 NULL, /* 18h */
7102 NULL, /* 19h */
7103 NULL, /* 1Ah */
7104 NULL, /* 1Bh */
7105 NULL, /* 1Ch */
7106 NULL, /* 1Dh */
7107 NULL, /* 1Eh */
7108 NULL, /* 1Fh */
7109 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7110 "Phys Disk failed: Data Passed too Large", /* 21h */
7111 "Phys Disk failed: DMA Error", /* 22h */
7112 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7113 "Phys Disk failed: Creating Phys Disk Config "
7114 "Page", /* 24h */
7115 NULL, /* 25h */
7116 NULL, /* 26h */
7117 NULL, /* 27h */
7118 NULL, /* 28h */
7119 NULL, /* 29h */
7120 NULL, /* 2Ah */
7121 NULL, /* 2Bh */
7122 NULL, /* 2Ch */
7123 NULL, /* 2Dh */
7124 NULL, /* 2Eh */
7125 NULL, /* 2Fh */
7126 "Compatibility Error: IR Disabled", /* 30h */
7127 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7128 "Compatibility Error: Device not Direct Access "
7129 "Device ", /* 32h */
7130 "Compatibility Error: Removable Device Found", /* 33h */
7131 "Compatibility Error: Device SCSI Version not "
7132 "2 or Higher", /* 34h */
7133 "Compatibility Error: SATA Device, 48 BIT LBA "
7134 "not Supported", /* 35h */
7135 "Compatibility Error: Device doesn't have "
7136 "512 Byte Block Sizes", /* 36h */
7137 "Compatibility Error: Volume Type Check Failed", /* 37h */
7138 "Compatibility Error: Volume Type is "
7139 "Unsupported by FW", /* 38h */
7140 "Compatibility Error: Disk Drive too Small for "
7141 "use in Volume", /* 39h */
7142 "Compatibility Error: Phys Disk for Create "
7143 "Volume not Found", /* 3Ah */
7144 "Compatibility Error: Too Many or too Few "
7145 "Disks for Volume Type", /* 3Bh */
7146 "Compatibility Error: Disk stripe Sizes "
7147 "Must be 64KB", /* 3Ch */
7148 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7149 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007150
7151/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007152/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007153 * mpt_sas_log_info - Log information returned from SAS IOC.
7154 * @ioc: Pointer to MPT_ADAPTER structure
7155 * @log_info: U32 LogInfo reply word from the IOC
7156 *
7157 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007158 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007159static void
7160mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7161{
7162union loginfo_type {
7163 u32 loginfo;
7164 struct {
7165 u32 subcode:16;
7166 u32 code:8;
7167 u32 originator:4;
7168 u32 bus_type:4;
7169 }dw;
7170};
7171 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007172 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007173 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007174 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007175
7176 sas_loginfo.loginfo = log_info;
7177 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
7178 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
7179 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007180
7181 originator_desc = originator_str[sas_loginfo.dw.originator];
7182
7183 switch (sas_loginfo.dw.originator) {
7184
7185 case 0: /* IOP */
7186 if (sas_loginfo.dw.code <
7187 sizeof(iop_code_str)/sizeof(char*))
7188 code_desc = iop_code_str[sas_loginfo.dw.code];
7189 break;
7190 case 1: /* PL */
7191 if (sas_loginfo.dw.code <
7192 sizeof(pl_code_str)/sizeof(char*))
7193 code_desc = pl_code_str[sas_loginfo.dw.code];
7194 break;
7195 case 2: /* IR */
7196 if (sas_loginfo.dw.code >=
7197 sizeof(ir_code_str)/sizeof(char*))
7198 break;
7199 code_desc = ir_code_str[sas_loginfo.dw.code];
7200 if (sas_loginfo.dw.subcode >=
7201 sizeof(raid_sub_code_str)/sizeof(char*))
7202 break;
7203 if (sas_loginfo.dw.code == 0)
7204 sub_code_desc =
7205 raid_sub_code_str[sas_loginfo.dw.subcode];
7206 break;
7207 default:
7208 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007209 }
7210
Eric Moorec6c727a2007-01-29 09:44:54 -07007211 if (sub_code_desc != NULL)
7212 printk(MYIOC_s_INFO_FMT
7213 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7214 " SubCode={%s}\n",
7215 ioc->name, log_info, originator_desc, code_desc,
7216 sub_code_desc);
7217 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007218 printk(MYIOC_s_INFO_FMT
7219 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7220 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007221 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007222 sas_loginfo.dw.subcode);
7223 else
7224 printk(MYIOC_s_INFO_FMT
7225 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7226 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007227 ioc->name, log_info, originator_desc,
7228 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007229}
7230
Linus Torvalds1da177e2005-04-16 15:20:36 -07007231/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007232/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007233 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7234 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007235 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007236 * @mf: Pointer to MPT request frame
7237 *
7238 * Refer to lsi/mpi.h.
7239 **/
7240static void
7241mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7242{
7243 Config_t *pReq = (Config_t *)mf;
7244 char extend_desc[EVENT_DESCR_STR_SZ];
7245 char *desc = NULL;
7246 u32 form;
7247 u8 page_type;
7248
7249 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7250 page_type = pReq->ExtPageType;
7251 else
7252 page_type = pReq->Header.PageType;
7253
7254 /*
7255 * ignore invalid page messages for GET_NEXT_HANDLE
7256 */
7257 form = le32_to_cpu(pReq->PageAddress);
7258 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7259 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7260 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7261 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7262 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7263 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7264 return;
7265 }
7266 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7267 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7268 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7269 return;
7270 }
7271
7272 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7273 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7274 page_type, pReq->Header.PageNumber, pReq->Action, form);
7275
7276 switch (ioc_status) {
7277
7278 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7279 desc = "Config Page Invalid Action";
7280 break;
7281
7282 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7283 desc = "Config Page Invalid Type";
7284 break;
7285
7286 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7287 desc = "Config Page Invalid Page";
7288 break;
7289
7290 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7291 desc = "Config Page Invalid Data";
7292 break;
7293
7294 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7295 desc = "Config Page No Defaults";
7296 break;
7297
7298 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7299 desc = "Config Page Can't Commit";
7300 break;
7301 }
7302
7303 if (!desc)
7304 return;
7305
Eric Moore29dd3602007-09-14 18:46:51 -06007306 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7307 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007308}
7309
7310/**
7311 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007312 * @ioc: Pointer to MPT_ADAPTER structure
7313 * @ioc_status: U32 IOCStatus word from IOC
7314 * @mf: Pointer to MPT request frame
7315 *
7316 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007317 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007318static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007319mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007320{
7321 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007322 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007323
7324 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007325
7326/****************************************************************************/
7327/* Common IOCStatus values for all replies */
7328/****************************************************************************/
7329
Linus Torvalds1da177e2005-04-16 15:20:36 -07007330 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7331 desc = "Invalid Function";
7332 break;
7333
7334 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7335 desc = "Busy";
7336 break;
7337
7338 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7339 desc = "Invalid SGL";
7340 break;
7341
7342 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7343 desc = "Internal Error";
7344 break;
7345
7346 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7347 desc = "Reserved";
7348 break;
7349
7350 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7351 desc = "Insufficient Resources";
7352 break;
7353
7354 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7355 desc = "Invalid Field";
7356 break;
7357
7358 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7359 desc = "Invalid State";
7360 break;
7361
Eric Moorec6c727a2007-01-29 09:44:54 -07007362/****************************************************************************/
7363/* Config IOCStatus values */
7364/****************************************************************************/
7365
Linus Torvalds1da177e2005-04-16 15:20:36 -07007366 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7367 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7368 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7369 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7370 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7371 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007372 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373 break;
7374
Eric Moorec6c727a2007-01-29 09:44:54 -07007375/****************************************************************************/
7376/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7377/* */
7378/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7379/* */
7380/****************************************************************************/
7381
Linus Torvalds1da177e2005-04-16 15:20:36 -07007382 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007384 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7385 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7386 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7387 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007389 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007390 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007391 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007392 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007394 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007395 break;
7396
Eric Moorec6c727a2007-01-29 09:44:54 -07007397/****************************************************************************/
7398/* SCSI Target values */
7399/****************************************************************************/
7400
7401 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7402 desc = "Target: Priority IO";
7403 break;
7404
7405 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7406 desc = "Target: Invalid Port";
7407 break;
7408
7409 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7410 desc = "Target Invalid IO Index:";
7411 break;
7412
7413 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7414 desc = "Target: Aborted";
7415 break;
7416
7417 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7418 desc = "Target: No Conn Retryable";
7419 break;
7420
7421 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7422 desc = "Target: No Connection";
7423 break;
7424
7425 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7426 desc = "Target: Transfer Count Mismatch";
7427 break;
7428
7429 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7430 desc = "Target: STS Data not Sent";
7431 break;
7432
7433 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7434 desc = "Target: Data Offset Error";
7435 break;
7436
7437 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7438 desc = "Target: Too Much Write Data";
7439 break;
7440
7441 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7442 desc = "Target: IU Too Short";
7443 break;
7444
7445 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7446 desc = "Target: ACK NAK Timeout";
7447 break;
7448
7449 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7450 desc = "Target: Nak Received";
7451 break;
7452
7453/****************************************************************************/
7454/* Fibre Channel Direct Access values */
7455/****************************************************************************/
7456
7457 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7458 desc = "FC: Aborted";
7459 break;
7460
7461 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7462 desc = "FC: RX ID Invalid";
7463 break;
7464
7465 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7466 desc = "FC: DID Invalid";
7467 break;
7468
7469 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7470 desc = "FC: Node Logged Out";
7471 break;
7472
7473 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7474 desc = "FC: Exchange Canceled";
7475 break;
7476
7477/****************************************************************************/
7478/* LAN values */
7479/****************************************************************************/
7480
7481 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7482 desc = "LAN: Device not Found";
7483 break;
7484
7485 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7486 desc = "LAN: Device Failure";
7487 break;
7488
7489 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7490 desc = "LAN: Transmit Error";
7491 break;
7492
7493 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7494 desc = "LAN: Transmit Aborted";
7495 break;
7496
7497 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7498 desc = "LAN: Receive Error";
7499 break;
7500
7501 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7502 desc = "LAN: Receive Aborted";
7503 break;
7504
7505 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7506 desc = "LAN: Partial Packet";
7507 break;
7508
7509 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7510 desc = "LAN: Canceled";
7511 break;
7512
7513/****************************************************************************/
7514/* Serial Attached SCSI values */
7515/****************************************************************************/
7516
7517 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7518 desc = "SAS: SMP Request Failed";
7519 break;
7520
7521 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7522 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007523 break;
7524
7525 default:
7526 desc = "Others";
7527 break;
7528 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007529
7530 if (!desc)
7531 return;
7532
Eric Moore29dd3602007-09-14 18:46:51 -06007533 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7534 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007535}
7536
7537/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007538EXPORT_SYMBOL(mpt_attach);
7539EXPORT_SYMBOL(mpt_detach);
7540#ifdef CONFIG_PM
7541EXPORT_SYMBOL(mpt_resume);
7542EXPORT_SYMBOL(mpt_suspend);
7543#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007544EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007545EXPORT_SYMBOL(mpt_register);
7546EXPORT_SYMBOL(mpt_deregister);
7547EXPORT_SYMBOL(mpt_event_register);
7548EXPORT_SYMBOL(mpt_event_deregister);
7549EXPORT_SYMBOL(mpt_reset_register);
7550EXPORT_SYMBOL(mpt_reset_deregister);
7551EXPORT_SYMBOL(mpt_device_driver_register);
7552EXPORT_SYMBOL(mpt_device_driver_deregister);
7553EXPORT_SYMBOL(mpt_get_msg_frame);
7554EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307555EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007556EXPORT_SYMBOL(mpt_free_msg_frame);
7557EXPORT_SYMBOL(mpt_add_sge);
7558EXPORT_SYMBOL(mpt_send_handshake_request);
7559EXPORT_SYMBOL(mpt_verify_adapter);
7560EXPORT_SYMBOL(mpt_GetIocState);
7561EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007562EXPORT_SYMBOL(mpt_HardResetHandler);
7563EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007564EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007565EXPORT_SYMBOL(mpt_alloc_fw_memory);
7566EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007567EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007568EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007569
Linus Torvalds1da177e2005-04-16 15:20:36 -07007570/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007571/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007572 * fusion_init - Fusion MPT base driver initialization routine.
7573 *
7574 * Returns 0 for success, non-zero for failure.
7575 */
7576static int __init
7577fusion_init(void)
7578{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307579 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007580
7581 show_mptmod_ver(my_NAME, my_VERSION);
7582 printk(KERN_INFO COPYRIGHT "\n");
7583
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307584 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7585 MptCallbacks[cb_idx] = NULL;
7586 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7587 MptEvHandlers[cb_idx] = NULL;
7588 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007589 }
7590
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007591 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007592 * EventNotification handling.
7593 */
7594 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7595
7596 /* Register for hard reset handling callbacks.
7597 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307598 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007599
7600#ifdef CONFIG_PROC_FS
7601 (void) procmpt_create();
7602#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007603 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007604}
7605
7606/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007607/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007608 * fusion_exit - Perform driver unload cleanup.
7609 *
7610 * This routine frees all resources associated with each MPT adapter
7611 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7612 */
7613static void __exit
7614fusion_exit(void)
7615{
7616
Linus Torvalds1da177e2005-04-16 15:20:36 -07007617 mpt_reset_deregister(mpt_base_index);
7618
7619#ifdef CONFIG_PROC_FS
7620 procmpt_destroy();
7621#endif
7622}
7623
Linus Torvalds1da177e2005-04-16 15:20:36 -07007624module_init(fusion_init);
7625module_exit(fusion_exit);