blob: d6a0074b9dc3b34c239fc8582fc3ef7a45dfc85c [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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700276 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530277 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700278 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530279 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
280 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700281 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530282 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",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700359 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600360 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",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700423 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600424 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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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
Kay Sieversaab0de22008-05-02 06:02:41 +02001673 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1674 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301675 ioc->reset_work_q =
1676 create_singlethread_workqueue(ioc->reset_work_q_name);
1677 if (!ioc->reset_work_q) {
1678 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1679 ioc->name);
1680 pci_release_selected_regions(pdev, ioc->bars);
1681 kfree(ioc);
1682 return -ENOMEM;
1683 }
1684
Eric Moore29dd3602007-09-14 18:46:51 -06001685 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1686 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301688 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1689 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1690
1691 switch (pdev->device)
1692 {
1693 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1694 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1695 ioc->errata_flag_1064 = 1;
1696 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1697 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1698 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1699 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301701 break;
1702
1703 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 /* 929X Chip Fix. Set Split transactions level
1706 * for PCIX. Set MOST bits to zero.
1707 */
1708 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1709 pcixcmd &= 0x8F;
1710 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1711 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 /* 929XL Chip Fix. Set MMRBC to 0x08.
1713 */
1714 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1715 pcixcmd |= 0x08;
1716 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301719 break;
1720
1721 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 /* 919X Chip Fix. Set Split transactions level
1723 * for PCIX. Set MOST bits to zero.
1724 */
1725 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1726 pcixcmd &= 0x8F;
1727 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001728 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301729 break;
1730
1731 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 /* 1030 Chip Fix. Disable Split transactions
1733 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1734 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 if (revision < C0_1030) {
1736 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1737 pcixcmd &= 0x8F;
1738 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1739 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301740
1741 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001742 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301743 break;
1744
1745 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1746 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001747 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301748
1749 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1750 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1751 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001752 ioc->bus_type = SAS;
1753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
James Bottomley27898982008-07-10 22:10:55 -05001755 if (mpt_msi_enable == -1) {
1756 /* Enable on SAS, disable on FC and SPI */
1757 if (ioc->bus_type == SAS)
1758 ioc->msi_enable = 1;
1759 else
1760 ioc->msi_enable = 0;
1761 } else
1762 /* follow flag: 0 - disable; 1 - enable */
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301763 ioc->msi_enable = mpt_msi_enable;
1764
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001765 if (ioc->errata_flag_1064)
1766 pci_disable_io_access(pdev);
1767
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 spin_lock_init(&ioc->FreeQlock);
1769
1770 /* Disable all! */
1771 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1772 ioc->active = 0;
1773 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1774
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301775 /* Set IOC ptr in the pcidev's driver data. */
1776 pci_set_drvdata(ioc->pcidev, ioc);
1777
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 /* Set lookup ptr. */
1779 list_add_tail(&ioc->list, &ioc_list);
1780
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001781 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 */
1783 mpt_detect_bound_ports(ioc, pdev);
1784
James Bottomleyc92f2222006-03-01 09:02:49 -06001785 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1786 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001787 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1788 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001789
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001791 if (ioc->alt_ioc)
1792 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301793 iounmap(ioc->memmap);
1794 if (r != -5)
1795 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301796
1797 destroy_workqueue(ioc->reset_work_q);
1798 ioc->reset_work_q = NULL;
1799
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 kfree(ioc);
1801 pci_set_drvdata(pdev, NULL);
1802 return r;
1803 }
1804
1805 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001806 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301807 if(MptDeviceDriverHandlers[cb_idx] &&
1808 MptDeviceDriverHandlers[cb_idx]->probe) {
1809 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 }
1811 }
1812
1813#ifdef CONFIG_PROC_FS
1814 /*
1815 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1816 */
1817 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1818 if (dent) {
1819 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1820 if (ent) {
1821 ent->read_proc = procmpt_iocinfo_read;
1822 ent->data = ioc;
1823 }
1824 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1825 if (ent) {
1826 ent->read_proc = procmpt_summary_read;
1827 ent->data = ioc;
1828 }
1829 }
1830#endif
1831
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301832 if (!ioc->alt_ioc)
1833 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1834 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1835
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 return 0;
1837}
1838
1839/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001840/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001841 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 */
1844
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001845void
1846mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847{
1848 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1849 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301850 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301851 unsigned long flags;
1852 struct workqueue_struct *wq;
1853
1854 /*
1855 * Stop polling ioc for fault condition
1856 */
1857 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
1858 wq = ioc->reset_work_q;
1859 ioc->reset_work_q = NULL;
1860 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
1861 cancel_delayed_work(&ioc->fault_reset_work);
1862 destroy_workqueue(wq);
1863
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1866 remove_proc_entry(pname, NULL);
1867 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1868 remove_proc_entry(pname, NULL);
1869 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1870 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001871
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001873 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301874 if(MptDeviceDriverHandlers[cb_idx] &&
1875 MptDeviceDriverHandlers[cb_idx]->remove) {
1876 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 }
1878 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001879
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 /* Disable interrupts! */
1881 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1882
1883 ioc->active = 0;
1884 synchronize_irq(pdev->irq);
1885
1886 /* Clear any lingering interrupt */
1887 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1888
1889 CHIPREG_READ32(&ioc->chip->IntStatus);
1890
1891 mpt_adapter_dispose(ioc);
1892
1893 pci_set_drvdata(pdev, NULL);
1894}
1895
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896/**************************************************************************
1897 * Power Management
1898 */
1899#ifdef CONFIG_PM
1900/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001901/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001902 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001903 * @pdev: Pointer to pci_dev structure
1904 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001906int
1907mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908{
1909 u32 device_state;
1910 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301912 device_state = pci_choose_state(pdev, state);
1913 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
1914 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1915 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
1917 /* put ioc into READY_STATE */
1918 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1919 printk(MYIOC_s_ERR_FMT
1920 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1921 }
1922
1923 /* disable interrupts */
1924 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1925 ioc->active = 0;
1926
1927 /* Clear any lingering interrupt */
1928 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1929
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301930 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05001931 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301932 pci_disable_msi(ioc->pcidev);
1933 ioc->pci_irq = -1;
1934 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301936 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 return 0;
1939}
1940
1941/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001942/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001943 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001944 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001946int
1947mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948{
1949 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1950 u32 device_state = pdev->current_state;
1951 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301952 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001953
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301954 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
1955 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1956 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301958 pci_set_power_state(pdev, PCI_D0);
1959 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301961 ioc->pcidev = pdev;
1962 err = mpt_mapresources(ioc);
1963 if (err)
1964 return err;
1965
1966 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1967 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1968 CHIPREG_READ32(&ioc->chip->Doorbell));
1969
1970 /*
1971 * Errata workaround for SAS pci express:
1972 * Upon returning to the D0 state, the contents of the doorbell will be
1973 * stale data, and this will incorrectly signal to the host driver that
1974 * the firmware is ready to process mpt commands. The workaround is
1975 * to issue a diagnostic reset.
1976 */
1977 if (ioc->bus_type == SAS && (pdev->device ==
1978 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
1979 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
1980 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
1981 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
1982 ioc->name);
1983 goto out;
1984 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
1987 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301988 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
1989 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1990 CAN_SLEEP);
1991 if (recovery_state != 0)
1992 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
1993 "error:[%x]\n", ioc->name, recovery_state);
1994 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301996 "pci-resume: success\n", ioc->name);
1997 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301999
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000}
2001#endif
2002
James Bottomley4ff42a62006-05-17 18:06:52 -05002003static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302004mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002005{
2006 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2007 ioc->bus_type != SPI) ||
2008 (MptDriverClass[index] == MPTFC_DRIVER &&
2009 ioc->bus_type != FC) ||
2010 (MptDriverClass[index] == MPTSAS_DRIVER &&
2011 ioc->bus_type != SAS))
2012 /* make sure we only call the relevant reset handler
2013 * for the bus */
2014 return 0;
2015 return (MptResetHandlers[index])(ioc, reset_phase);
2016}
2017
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002019/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2021 * @ioc: Pointer to MPT adapter structure
2022 * @reason: Event word / reason
2023 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2024 *
2025 * This routine performs all the steps necessary to bring the IOC
2026 * to a OPERATIONAL state.
2027 *
2028 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2029 * MPT adapter.
2030 *
2031 * Returns:
2032 * 0 for success
2033 * -1 if failed to get board READY
2034 * -2 if READY but IOCFacts Failed
2035 * -3 if READY but PrimeIOCFifos Failed
2036 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302037 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302038 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 */
2040static int
2041mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2042{
2043 int hard_reset_done = 0;
2044 int alt_ioc_ready = 0;
2045 int hard;
2046 int rc=0;
2047 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302048 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 int handlers;
2050 int ret = 0;
2051 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002052 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302053 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054
Eric Moore29dd3602007-09-14 18:46:51 -06002055 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2056 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057
2058 /* Disable reply interrupts (also blocks FreeQ) */
2059 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2060 ioc->active = 0;
2061
2062 if (ioc->alt_ioc) {
2063 if (ioc->alt_ioc->active)
2064 reset_alt_ioc_active = 1;
2065
2066 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2067 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2068 ioc->alt_ioc->active = 0;
2069 }
2070
2071 hard = 1;
2072 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2073 hard = 0;
2074
2075 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2076 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002077 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2078 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
2080 if (reset_alt_ioc_active && ioc->alt_ioc) {
2081 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002082 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2083 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002084 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 ioc->alt_ioc->active = 1;
2086 }
2087
2088 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002089 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 }
2091 return -1;
2092 }
2093
2094 /* hard_reset_done = 0 if a soft reset was performed
2095 * and 1 if a hard reset was performed.
2096 */
2097 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2098 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2099 alt_ioc_ready = 1;
2100 else
Eric Moore29dd3602007-09-14 18:46:51 -06002101 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 }
2103
2104 for (ii=0; ii<5; ii++) {
2105 /* Get IOC facts! Allow 5 retries */
2106 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2107 break;
2108 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002109
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
2111 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002112 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2113 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 ret = -2;
2115 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2116 MptDisplayIocCapabilities(ioc);
2117 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002118
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 if (alt_ioc_ready) {
2120 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302121 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002122 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 /* Retry - alt IOC was initialized once
2124 */
2125 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2126 }
2127 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302128 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002129 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 alt_ioc_ready = 0;
2131 reset_alt_ioc_active = 0;
2132 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2133 MptDisplayIocCapabilities(ioc->alt_ioc);
2134 }
2135 }
2136
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302137 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2138 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2139 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2140 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2141 IORESOURCE_IO);
2142 if (pci_enable_device(ioc->pcidev))
2143 return -5;
2144 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2145 "mpt"))
2146 return -5;
2147 }
2148
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002149 /*
2150 * Device is reset now. It must have de-asserted the interrupt line
2151 * (if it was asserted) and it should be safe to register for the
2152 * interrupt now.
2153 */
2154 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2155 ioc->pci_irq = -1;
2156 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302157 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002158 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002159 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302160 else
2161 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002162 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002163 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002164 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002165 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002166 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302167 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002168 pci_disable_msi(ioc->pcidev);
2169 return -EBUSY;
2170 }
2171 irq_allocated = 1;
2172 ioc->pci_irq = ioc->pcidev->irq;
2173 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002174 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2175 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002176 }
2177 }
2178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 /* Prime reply & request queues!
2180 * (mucho alloc's) Must be done prior to
2181 * init as upper addresses are needed for init.
2182 * If fails, continue with alt-ioc processing
2183 */
2184 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2185 ret = -3;
2186
2187 /* May need to check/upload firmware & data here!
2188 * If fails, continue with alt-ioc processing
2189 */
2190 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2191 ret = -4;
2192// NEW!
2193 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002194 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2195 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 alt_ioc_ready = 0;
2197 reset_alt_ioc_active = 0;
2198 }
2199
2200 if (alt_ioc_ready) {
2201 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2202 alt_ioc_ready = 0;
2203 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002204 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2205 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 }
2207 }
2208
2209 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2210 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302211 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002212 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213
2214 /* Controller is not operational, cannot do upload
2215 */
2216 if (ret == 0) {
2217 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002218 if (rc == 0) {
2219 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2220 /*
2221 * Maintain only one pointer to FW memory
2222 * so there will not be two attempt to
2223 * downloadboot onboard dual function
2224 * chips (mpt_adapter_disable,
2225 * mpt_diag_reset)
2226 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302227 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002228 "mpt_upload: alt_%s has cached_fw=%p \n",
2229 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302230 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002231 }
2232 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002233 printk(MYIOC_s_WARN_FMT
2234 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302235 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 }
2238 }
2239 }
2240
2241 if (ret == 0) {
2242 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002243 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 ioc->active = 1;
2245 }
2246
2247 if (reset_alt_ioc_active && ioc->alt_ioc) {
2248 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002249 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2250 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002251 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 ioc->alt_ioc->active = 1;
2253 }
2254
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002255 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 * and EventAck handling.
2257 */
2258 if ((ret == 0) && (!ioc->facts.EventState))
2259 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2260
2261 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2262 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2263
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002264 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2266 * recursive scenario; GetLanConfigPages times out, timer expired
2267 * routine calls HardResetHandler, which calls into here again,
2268 * and we try GetLanConfigPages again...
2269 */
2270 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002271
2272 /*
2273 * Initalize link list for inactive raid volumes.
2274 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002275 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002276 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2277
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002278 if (ioc->bus_type == SAS) {
2279
2280 /* clear persistency table */
2281 if(ioc->facts.IOCExceptions &
2282 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2283 ret = mptbase_sas_persist_operation(ioc,
2284 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2285 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002286 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002287 }
2288
2289 /* Find IM volumes
2290 */
2291 mpt_findImVolumes(ioc);
2292
2293 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2295 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2296 /*
2297 * Pre-fetch the ports LAN MAC address!
2298 * (LANPage1_t stuff)
2299 */
2300 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302301 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2302 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002303 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2304 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302305
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 }
2307 } else {
2308 /* Get NVRAM and adapter maximums from SPP 0 and 2
2309 */
2310 mpt_GetScsiPortSettings(ioc, 0);
2311
2312 /* Get version and length of SDP 1
2313 */
2314 mpt_readScsiDevicePageHeaders(ioc, 0);
2315
2316 /* Find IM volumes
2317 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002318 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 mpt_findImVolumes(ioc);
2320
2321 /* Check, and possibly reset, the coalescing value
2322 */
2323 mpt_read_ioc_pg_1(ioc);
2324
2325 mpt_read_ioc_pg_4(ioc);
2326 }
2327
2328 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302329 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 }
2331
2332 /*
2333 * Call each currently registered protocol IOC reset handler
2334 * with post-reset indication.
2335 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2336 * MptResetHandlers[] registered yet.
2337 */
2338 if (hard_reset_done) {
2339 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302340 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2341 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302342 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002343 "Calling IOC post_reset handler #%d\n",
2344 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302345 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 handlers++;
2347 }
2348
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302349 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302350 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002351 "Calling IOC post_reset handler #%d\n",
2352 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302353 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 handlers++;
2355 }
2356 }
2357 /* FIXME? Examine results here? */
2358 }
2359
Eric Moore0ccdb002006-07-11 17:33:13 -06002360 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002361 if ((ret != 0) && irq_allocated) {
2362 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302363 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002364 pci_disable_msi(ioc->pcidev);
2365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 return ret;
2367}
2368
2369/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002370/**
2371 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 * @ioc: Pointer to MPT adapter structure
2373 * @pdev: Pointer to (struct pci_dev) structure
2374 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002375 * Search for PCI bus/dev_function which matches
2376 * PCI bus/dev_function (+/-1) for newly discovered 929,
2377 * 929X, 1030 or 1035.
2378 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2380 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2381 */
2382static void
2383mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2384{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002385 struct pci_dev *peer=NULL;
2386 unsigned int slot = PCI_SLOT(pdev->devfn);
2387 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 MPT_ADAPTER *ioc_srch;
2389
Prakash, Sathya436ace72007-07-24 15:42:08 +05302390 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002391 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002392 ioc->name, pci_name(pdev), pdev->bus->number,
2393 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002394
2395 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2396 if (!peer) {
2397 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2398 if (!peer)
2399 return;
2400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
2402 list_for_each_entry(ioc_srch, &ioc_list, list) {
2403 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002404 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 /* Paranoia checks */
2406 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002407 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002408 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 break;
2410 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002411 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002412 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 break;
2414 }
Eric Moore29dd3602007-09-14 18:46:51 -06002415 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002416 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 ioc_srch->alt_ioc = ioc;
2418 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 }
2420 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002421 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422}
2423
2424/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002425/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002427 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 */
2429static void
2430mpt_adapter_disable(MPT_ADAPTER *ioc)
2431{
2432 int sz;
2433 int ret;
2434
2435 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302436 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002437 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302438 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2439 ioc->cached_fw, CAN_SLEEP)) < 0) {
2440 printk(MYIOC_s_WARN_FMT
2441 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002442 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 }
2444 }
2445
2446 /* Disable adapter interrupts! */
2447 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2448 ioc->active = 0;
2449 /* Clear any lingering interrupt */
2450 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2451
2452 if (ioc->alloc != NULL) {
2453 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002454 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2455 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 pci_free_consistent(ioc->pcidev, sz,
2457 ioc->alloc, ioc->alloc_dma);
2458 ioc->reply_frames = NULL;
2459 ioc->req_frames = NULL;
2460 ioc->alloc = NULL;
2461 ioc->alloc_total -= sz;
2462 }
2463
2464 if (ioc->sense_buf_pool != NULL) {
2465 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2466 pci_free_consistent(ioc->pcidev, sz,
2467 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2468 ioc->sense_buf_pool = NULL;
2469 ioc->alloc_total -= sz;
2470 }
2471
2472 if (ioc->events != NULL){
2473 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2474 kfree(ioc->events);
2475 ioc->events = NULL;
2476 ioc->alloc_total -= sz;
2477 }
2478
Prakash, Sathya984621b2008-01-11 14:42:17 +05302479 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002481 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002482 mpt_inactive_raid_list_free(ioc);
2483 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002484 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002485 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002486 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
2488 if (ioc->spi_data.pIocPg4 != NULL) {
2489 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302490 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 ioc->spi_data.pIocPg4,
2492 ioc->spi_data.IocPg4_dma);
2493 ioc->spi_data.pIocPg4 = NULL;
2494 ioc->alloc_total -= sz;
2495 }
2496
2497 if (ioc->ReqToChain != NULL) {
2498 kfree(ioc->ReqToChain);
2499 kfree(ioc->RequestNB);
2500 ioc->ReqToChain = NULL;
2501 }
2502
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002503 kfree(ioc->ChainToChain);
2504 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002505
2506 if (ioc->HostPageBuffer != NULL) {
2507 if((ret = mpt_host_page_access_control(ioc,
2508 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002509 printk(MYIOC_s_ERR_FMT
2510 "host page buffers free failed (%d)!\n",
2511 ioc->name, ret);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002512 }
Eric Moore29dd3602007-09-14 18:46:51 -06002513 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002514 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2515 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002516 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002517 ioc->HostPageBuffer = NULL;
2518 ioc->HostPageBuffer_sz = 0;
2519 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521}
2522
2523/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002524/**
2525 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 * @ioc: Pointer to MPT adapter structure
2527 *
2528 * This routine unregisters h/w resources and frees all alloc'd memory
2529 * associated with a MPT adapter structure.
2530 */
2531static void
2532mpt_adapter_dispose(MPT_ADAPTER *ioc)
2533{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002534 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002536 if (ioc == NULL)
2537 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002539 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002541 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002543 if (ioc->pci_irq != -1) {
2544 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302545 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002546 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002547 ioc->pci_irq = -1;
2548 }
2549
2550 if (ioc->memmap != NULL) {
2551 iounmap(ioc->memmap);
2552 ioc->memmap = NULL;
2553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302555 pci_disable_device(ioc->pcidev);
2556 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2557
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002559 if (ioc->mtrr_reg > 0) {
2560 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002561 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563#endif
2564
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002565 /* Zap the adapter lookup ptr! */
2566 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002568 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002569 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2570 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002571
2572 if (ioc->alt_ioc)
2573 ioc->alt_ioc->alt_ioc = NULL;
2574
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002575 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576}
2577
2578/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002579/**
2580 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 * @ioc: Pointer to MPT adapter structure
2582 */
2583static void
2584MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2585{
2586 int i = 0;
2587
2588 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302589 if (ioc->prod_name)
2590 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 printk("Capabilities={");
2592
2593 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2594 printk("Initiator");
2595 i++;
2596 }
2597
2598 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2599 printk("%sTarget", i ? "," : "");
2600 i++;
2601 }
2602
2603 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2604 printk("%sLAN", i ? "," : "");
2605 i++;
2606 }
2607
2608#if 0
2609 /*
2610 * This would probably evoke more questions than it's worth
2611 */
2612 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2613 printk("%sLogBusAddr", i ? "," : "");
2614 i++;
2615 }
2616#endif
2617
2618 printk("}\n");
2619}
2620
2621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002622/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2624 * @ioc: Pointer to MPT_ADAPTER structure
2625 * @force: Force hard KickStart of IOC
2626 * @sleepFlag: Specifies whether the process can sleep
2627 *
2628 * Returns:
2629 * 1 - DIAG reset and READY
2630 * 0 - READY initially OR soft reset and READY
2631 * -1 - Any failure on KickStart
2632 * -2 - Msg Unit Reset Failed
2633 * -3 - IO Unit Reset Failed
2634 * -4 - IOC owned by a PEER
2635 */
2636static int
2637MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2638{
2639 u32 ioc_state;
2640 int statefault = 0;
2641 int cntdn;
2642 int hard_reset_done = 0;
2643 int r;
2644 int ii;
2645 int whoinit;
2646
2647 /* Get current [raw] IOC state */
2648 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002649 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650
2651 /*
2652 * Check to see if IOC got left/stuck in doorbell handshake
2653 * grip of death. If so, hard reset the IOC.
2654 */
2655 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2656 statefault = 1;
2657 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2658 ioc->name);
2659 }
2660
2661 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002662 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 return 0;
2664
2665 /*
2666 * Check to see if IOC is in FAULT state.
2667 */
2668 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2669 statefault = 2;
2670 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002671 ioc->name);
2672 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2673 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 }
2675
2676 /*
2677 * Hmmm... Did it get left operational?
2678 */
2679 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302680 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 ioc->name));
2682
2683 /* Check WhoInit.
2684 * If PCI Peer, exit.
2685 * Else, if no fault conditions are present, issue a MessageUnitReset
2686 * Else, fall through to KickStart case
2687 */
2688 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002689 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2690 "whoinit 0x%x statefault %d force %d\n",
2691 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 if (whoinit == MPI_WHOINIT_PCI_PEER)
2693 return -4;
2694 else {
2695 if ((statefault == 0 ) && (force == 0)) {
2696 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2697 return 0;
2698 }
2699 statefault = 3;
2700 }
2701 }
2702
2703 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2704 if (hard_reset_done < 0)
2705 return -1;
2706
2707 /*
2708 * Loop here waiting for IOC to come READY.
2709 */
2710 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002711 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
2713 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2714 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2715 /*
2716 * BIOS or previous driver load left IOC in OP state.
2717 * Reset messaging FIFOs.
2718 */
2719 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2720 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2721 return -2;
2722 }
2723 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2724 /*
2725 * Something is wrong. Try to get IOC back
2726 * to a known state.
2727 */
2728 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2729 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2730 return -3;
2731 }
2732 }
2733
2734 ii++; cntdn--;
2735 if (!cntdn) {
2736 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2737 ioc->name, (int)((ii+5)/HZ));
2738 return -ETIME;
2739 }
2740
2741 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002742 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 } else {
2744 mdelay (1); /* 1 msec delay */
2745 }
2746
2747 }
2748
2749 if (statefault < 3) {
2750 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2751 ioc->name,
2752 statefault==1 ? "stuck handshake" : "IOC FAULT");
2753 }
2754
2755 return hard_reset_done;
2756}
2757
2758/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002759/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 * mpt_GetIocState - Get the current state of a MPT adapter.
2761 * @ioc: Pointer to MPT_ADAPTER structure
2762 * @cooked: Request raw or cooked IOC state
2763 *
2764 * Returns all IOC Doorbell register bits if cooked==0, else just the
2765 * Doorbell bits in MPI_IOC_STATE_MASK.
2766 */
2767u32
2768mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2769{
2770 u32 s, sc;
2771
2772 /* Get! */
2773 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 sc = s & MPI_IOC_STATE_MASK;
2775
2776 /* Save! */
2777 ioc->last_state = sc;
2778
2779 return cooked ? sc : s;
2780}
2781
2782/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002783/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 * GetIocFacts - Send IOCFacts request to MPT adapter.
2785 * @ioc: Pointer to MPT_ADAPTER structure
2786 * @sleepFlag: Specifies whether the process can sleep
2787 * @reason: If recovery, only update facts.
2788 *
2789 * Returns 0 for success, non-zero for failure.
2790 */
2791static int
2792GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2793{
2794 IOCFacts_t get_facts;
2795 IOCFactsReply_t *facts;
2796 int r;
2797 int req_sz;
2798 int reply_sz;
2799 int sz;
2800 u32 status, vv;
2801 u8 shiftFactor=1;
2802
2803 /* IOC *must* NOT be in RESET state! */
2804 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002805 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2806 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 return -44;
2808 }
2809
2810 facts = &ioc->facts;
2811
2812 /* Destination (reply area)... */
2813 reply_sz = sizeof(*facts);
2814 memset(facts, 0, reply_sz);
2815
2816 /* Request area (get_facts on the stack right now!) */
2817 req_sz = sizeof(get_facts);
2818 memset(&get_facts, 0, req_sz);
2819
2820 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2821 /* Assert: All other get_facts fields are zero! */
2822
Prakash, Sathya436ace72007-07-24 15:42:08 +05302823 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002824 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 ioc->name, req_sz, reply_sz));
2826
2827 /* No non-zero fields in the get_facts request are greater than
2828 * 1 byte in size, so we can just fire it off as is.
2829 */
2830 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2831 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2832 if (r != 0)
2833 return r;
2834
2835 /*
2836 * Now byte swap (GRRR) the necessary fields before any further
2837 * inspection of reply contents.
2838 *
2839 * But need to do some sanity checks on MsgLength (byte) field
2840 * to make sure we don't zero IOC's req_sz!
2841 */
2842 /* Did we get a valid reply? */
2843 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2844 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2845 /*
2846 * If not been here, done that, save off first WhoInit value
2847 */
2848 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2849 ioc->FirstWhoInit = facts->WhoInit;
2850 }
2851
2852 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2853 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2854 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2855 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2856 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002857 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 /* CHECKME! IOCStatus, IOCLogInfo */
2859
2860 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2861 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2862
2863 /*
2864 * FC f/w version changed between 1.1 and 1.2
2865 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2866 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2867 */
2868 if (facts->MsgVersion < 0x0102) {
2869 /*
2870 * Handle old FC f/w style, convert to new...
2871 */
2872 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2873 facts->FWVersion.Word =
2874 ((oldv<<12) & 0xFF000000) |
2875 ((oldv<<8) & 0x000FFF00);
2876 } else
2877 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2878
2879 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002880 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2881 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2882 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 facts->CurrentHostMfaHighAddr =
2884 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2885 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2886 facts->CurrentSenseBufferHighAddr =
2887 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2888 facts->CurReplyFrameSize =
2889 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002890 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891
2892 /*
2893 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2894 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2895 * to 14 in MPI-1.01.0x.
2896 */
2897 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2898 facts->MsgVersion > 0x0100) {
2899 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2900 }
2901
2902 sz = facts->FWImageSize;
2903 if ( sz & 0x01 )
2904 sz += 1;
2905 if ( sz & 0x02 )
2906 sz += 2;
2907 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002908
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 if (!facts->RequestFrameSize) {
2910 /* Something is wrong! */
2911 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2912 ioc->name);
2913 return -55;
2914 }
2915
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002916 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 vv = ((63 / (sz * 4)) + 1) & 0x03;
2918 ioc->NB_for_64_byte_frame = vv;
2919 while ( sz )
2920 {
2921 shiftFactor++;
2922 sz = sz >> 1;
2923 }
2924 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302925 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002926 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2927 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002928
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2930 /*
2931 * Set values for this IOC's request & reply frame sizes,
2932 * and request & reply queue depths...
2933 */
2934 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2935 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2936 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2937 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2938
Prakash, Sathya436ace72007-07-24 15:42:08 +05302939 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302941 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 ioc->name, ioc->req_sz, ioc->req_depth));
2943
2944 /* Get port facts! */
2945 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2946 return r;
2947 }
2948 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002949 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2951 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2952 RequestFrameSize)/sizeof(u32)));
2953 return -66;
2954 }
2955
2956 return 0;
2957}
2958
2959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002960/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 * GetPortFacts - Send PortFacts request to MPT adapter.
2962 * @ioc: Pointer to MPT_ADAPTER structure
2963 * @portnum: Port number
2964 * @sleepFlag: Specifies whether the process can sleep
2965 *
2966 * Returns 0 for success, non-zero for failure.
2967 */
2968static int
2969GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2970{
2971 PortFacts_t get_pfacts;
2972 PortFactsReply_t *pfacts;
2973 int ii;
2974 int req_sz;
2975 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002976 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
2978 /* IOC *must* NOT be in RESET state! */
2979 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002980 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2981 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 return -4;
2983 }
2984
2985 pfacts = &ioc->pfacts[portnum];
2986
2987 /* Destination (reply area)... */
2988 reply_sz = sizeof(*pfacts);
2989 memset(pfacts, 0, reply_sz);
2990
2991 /* Request area (get_pfacts on the stack right now!) */
2992 req_sz = sizeof(get_pfacts);
2993 memset(&get_pfacts, 0, req_sz);
2994
2995 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2996 get_pfacts.PortNumber = portnum;
2997 /* Assert: All other get_pfacts fields are zero! */
2998
Prakash, Sathya436ace72007-07-24 15:42:08 +05302999 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 ioc->name, portnum));
3001
3002 /* No non-zero fields in the get_pfacts request are greater than
3003 * 1 byte in size, so we can just fire it off as is.
3004 */
3005 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3006 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3007 if (ii != 0)
3008 return ii;
3009
3010 /* Did we get a valid reply? */
3011
3012 /* Now byte swap the necessary fields in the response. */
3013 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3014 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3015 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3016 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3017 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3018 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3019 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3020 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3021 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3022
Eric Moore793955f2007-01-29 09:42:20 -07003023 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3024 pfacts->MaxDevices;
3025 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3026 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3027
3028 /*
3029 * Place all the devices on channels
3030 *
3031 * (for debuging)
3032 */
3033 if (mpt_channel_mapping) {
3034 ioc->devices_per_bus = 1;
3035 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3036 }
3037
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 return 0;
3039}
3040
3041/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003042/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 * SendIocInit - Send IOCInit request to MPT adapter.
3044 * @ioc: Pointer to MPT_ADAPTER structure
3045 * @sleepFlag: Specifies whether the process can sleep
3046 *
3047 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3048 *
3049 * Returns 0 for success, non-zero for failure.
3050 */
3051static int
3052SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3053{
3054 IOCInit_t ioc_init;
3055 MPIDefaultReply_t init_reply;
3056 u32 state;
3057 int r;
3058 int count;
3059 int cntdn;
3060
3061 memset(&ioc_init, 0, sizeof(ioc_init));
3062 memset(&init_reply, 0, sizeof(init_reply));
3063
3064 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3065 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3066
3067 /* If we are in a recovery mode and we uploaded the FW image,
3068 * then this pointer is not NULL. Skip the upload a second time.
3069 * Set this flag if cached_fw set for either IOC.
3070 */
3071 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3072 ioc->upload_fw = 1;
3073 else
3074 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303075 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3077
Eric Moore793955f2007-01-29 09:42:20 -07003078 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3079 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303080 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003081 ioc->name, ioc->facts.MsgVersion));
3082 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3083 // set MsgVersion and HeaderVersion host driver was built with
3084 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3085 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003087 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3088 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3089 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3090 return -99;
3091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3093
3094 if (sizeof(dma_addr_t) == sizeof(u64)) {
3095 /* Save the upper 32-bits of the request
3096 * (reply) and sense buffers.
3097 */
3098 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3099 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3100 } else {
3101 /* Force 32-bit addressing */
3102 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3103 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3104 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003105
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3107 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003108 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3109 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110
Prakash, Sathya436ace72007-07-24 15:42:08 +05303111 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 ioc->name, &ioc_init));
3113
3114 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3115 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003116 if (r != 0) {
3117 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120
3121 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003122 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 */
3124
Prakash, Sathya436ace72007-07-24 15:42:08 +05303125 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003127
3128 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3129 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132
3133 /* YIKES! SUPER IMPORTANT!!!
3134 * Poll IocState until _OPERATIONAL while IOC is doing
3135 * LoopInit and TargetDiscovery!
3136 */
3137 count = 0;
3138 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3139 state = mpt_GetIocState(ioc, 1);
3140 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3141 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003142 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 } else {
3144 mdelay(1);
3145 }
3146
3147 if (!cntdn) {
3148 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3149 ioc->name, (int)((count+5)/HZ));
3150 return -9;
3151 }
3152
3153 state = mpt_GetIocState(ioc, 1);
3154 count++;
3155 }
Eric Moore29dd3602007-09-14 18:46:51 -06003156 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 ioc->name, count));
3158
Eric Mooreba856d32006-07-11 17:34:01 -06003159 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 return r;
3161}
3162
3163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003164/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 * SendPortEnable - Send PortEnable request to MPT adapter port.
3166 * @ioc: Pointer to MPT_ADAPTER structure
3167 * @portnum: Port number to enable
3168 * @sleepFlag: Specifies whether the process can sleep
3169 *
3170 * Send PortEnable to bring IOC to OPERATIONAL state.
3171 *
3172 * Returns 0 for success, non-zero for failure.
3173 */
3174static int
3175SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3176{
3177 PortEnable_t port_enable;
3178 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003179 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 int req_sz;
3181 int reply_sz;
3182
3183 /* Destination... */
3184 reply_sz = sizeof(MPIDefaultReply_t);
3185 memset(&reply_buf, 0, reply_sz);
3186
3187 req_sz = sizeof(PortEnable_t);
3188 memset(&port_enable, 0, req_sz);
3189
3190 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3191 port_enable.PortNumber = portnum;
3192/* port_enable.ChainOffset = 0; */
3193/* port_enable.MsgFlags = 0; */
3194/* port_enable.MsgContext = 0; */
3195
Prakash, Sathya436ace72007-07-24 15:42:08 +05303196 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 ioc->name, portnum, &port_enable));
3198
3199 /* RAID FW may take a long time to enable
3200 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003201 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003202 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3203 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3204 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003205 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003206 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3207 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3208 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003210 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211}
3212
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003213/**
3214 * mpt_alloc_fw_memory - allocate firmware memory
3215 * @ioc: Pointer to MPT_ADAPTER structure
3216 * @size: total FW bytes
3217 *
3218 * If memory has already been allocated, the same (cached) value
3219 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303220 *
3221 * Return 0 if successfull, or non-zero for failure
3222 **/
3223int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3225{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303226 int rc;
3227
3228 if (ioc->cached_fw) {
3229 rc = 0; /* use already allocated memory */
3230 goto out;
3231 }
3232 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3234 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303235 rc = 0;
3236 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303238 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3239 if (!ioc->cached_fw) {
3240 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3241 ioc->name);
3242 rc = -1;
3243 } else {
3244 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3245 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3246 ioc->alloc_total += size;
3247 rc = 0;
3248 }
3249 out:
3250 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303252
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003253/**
3254 * mpt_free_fw_memory - free firmware memory
3255 * @ioc: Pointer to MPT_ADAPTER structure
3256 *
3257 * If alt_img is NULL, delete from ioc structure.
3258 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303259 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260void
3261mpt_free_fw_memory(MPT_ADAPTER *ioc)
3262{
3263 int sz;
3264
Prakash, Sathya984621b2008-01-11 14:42:17 +05303265 if (!ioc->cached_fw)
3266 return;
3267
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303269 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3270 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003271 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303272 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274}
3275
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003277/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3279 * @ioc: Pointer to MPT_ADAPTER structure
3280 * @sleepFlag: Specifies whether the process can sleep
3281 *
3282 * Returns 0 for success, >0 for handshake failure
3283 * <0 for fw upload failure.
3284 *
3285 * Remark: If bound IOC and a successful FWUpload was performed
3286 * on the bound IOC, the second image is discarded
3287 * and memory is free'd. Both channels must upload to prevent
3288 * IOC from running in degraded mode.
3289 */
3290static int
3291mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3292{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 u8 reply[sizeof(FWUploadReply_t)];
3294 FWUpload_t *prequest;
3295 FWUploadReply_t *preply;
3296 FWUploadTCSGE_t *ptcsge;
3297 int sgeoffset;
3298 u32 flagsLength;
3299 int ii, sz, reply_sz;
3300 int cmdStatus;
3301
3302 /* If the image size is 0, we are done.
3303 */
3304 if ((sz = ioc->facts.FWImageSize) == 0)
3305 return 0;
3306
Prakash, Sathya984621b2008-01-11 14:42:17 +05303307 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3308 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309
Eric Moore29dd3602007-09-14 18:46:51 -06003310 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3311 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003312
Eric Moorebc6e0892007-09-29 10:16:28 -06003313 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3314 kzalloc(ioc->req_sz, GFP_KERNEL);
3315 if (!prequest) {
3316 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3317 "while allocating memory \n", ioc->name));
3318 mpt_free_fw_memory(ioc);
3319 return -ENOMEM;
3320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
Eric Moorebc6e0892007-09-29 10:16:28 -06003322 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323
3324 reply_sz = sizeof(reply);
3325 memset(preply, 0, reply_sz);
3326
3327 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3328 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3329
3330 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3331 ptcsge->DetailsLength = 12;
3332 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3333 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003334 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335
3336 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3337
3338 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003339 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340
3341 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003342 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3343 ioc->name, prequest, sgeoffset));
3344 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
3346 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3347 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3348
Eric Moore29dd3602007-09-14 18:46:51 -06003349 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350
3351 cmdStatus = -EFAULT;
3352 if (ii == 0) {
3353 /* Handshake transfer was complete and successful.
3354 * Check the Reply Frame.
3355 */
3356 int status, transfer_sz;
3357 status = le16_to_cpu(preply->IOCStatus);
3358 if (status == MPI_IOCSTATUS_SUCCESS) {
3359 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3360 if (transfer_sz == sz)
3361 cmdStatus = 0;
3362 }
3363 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303364 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 ioc->name, cmdStatus));
3366
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003367
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 if (cmdStatus) {
3369
Prakash, Sathya436ace72007-07-24 15:42:08 +05303370 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 ioc->name));
3372 mpt_free_fw_memory(ioc);
3373 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003374 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375
3376 return cmdStatus;
3377}
3378
3379/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003380/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 * mpt_downloadboot - DownloadBoot code
3382 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003383 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 * @sleepFlag: Specifies whether the process can sleep
3385 *
3386 * FwDownloadBoot requires Programmed IO access.
3387 *
3388 * Returns 0 for success
3389 * -1 FW Image size is 0
3390 * -2 No valid cached_fw Pointer
3391 * <0 for fw upload failure.
3392 */
3393static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003394mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 MpiExtImageHeader_t *pExtImage;
3397 u32 fwSize;
3398 u32 diag0val;
3399 int count;
3400 u32 *ptrFw;
3401 u32 diagRwData;
3402 u32 nextImage;
3403 u32 load_addr;
3404 u32 ioc_state=0;
3405
Prakash, Sathya436ace72007-07-24 15:42:08 +05303406 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003407 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003408
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3410 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3411 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3412 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3413 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3414 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3415
3416 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3417
3418 /* wait 1 msec */
3419 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003420 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 } else {
3422 mdelay (1);
3423 }
3424
3425 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3426 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3427
3428 for (count = 0; count < 30; count ++) {
3429 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3430 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303431 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 ioc->name, count));
3433 break;
3434 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003435 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003437 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003439 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 }
3441 }
3442
3443 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303444 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003445 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 ioc->name, diag0val));
3447 return -3;
3448 }
3449
3450 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3451 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3452 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3453 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3454 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3455 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3456
3457 /* Set the DiagRwEn and Disable ARM bits */
3458 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3459
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 fwSize = (pFwHeader->ImageSize + 3)/4;
3461 ptrFw = (u32 *) pFwHeader;
3462
3463 /* Write the LoadStartAddress to the DiagRw Address Register
3464 * using Programmed IO
3465 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003466 if (ioc->errata_flag_1064)
3467 pci_enable_io_access(ioc->pcidev);
3468
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303470 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 ioc->name, pFwHeader->LoadStartAddress));
3472
Prakash, Sathya436ace72007-07-24 15:42:08 +05303473 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 ioc->name, fwSize*4, ptrFw));
3475 while (fwSize--) {
3476 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3477 }
3478
3479 nextImage = pFwHeader->NextImageHeaderOffset;
3480 while (nextImage) {
3481 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3482
3483 load_addr = pExtImage->LoadStartAddress;
3484
3485 fwSize = (pExtImage->ImageSize + 3) >> 2;
3486 ptrFw = (u32 *)pExtImage;
3487
Prakash, Sathya436ace72007-07-24 15:42:08 +05303488 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 +02003489 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3491
3492 while (fwSize--) {
3493 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3494 }
3495 nextImage = pExtImage->NextImageHeaderOffset;
3496 }
3497
3498 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303499 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3501
3502 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303503 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3505
3506 /* Clear the internal flash bad bit - autoincrementing register,
3507 * so must do two writes.
3508 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003509 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003510 /*
3511 * 1030 and 1035 H/W errata, workaround to access
3512 * the ClearFlashBadSignatureBit
3513 */
3514 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3515 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3516 diagRwData |= 0x40000000;
3517 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3518 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3519
3520 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3521 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3522 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3523 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3524
3525 /* wait 1 msec */
3526 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003527 msleep (1);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003528 } else {
3529 mdelay (1);
3530 }
3531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003533 if (ioc->errata_flag_1064)
3534 pci_disable_io_access(ioc->pcidev);
3535
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303537 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003538 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003540 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303541 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 ioc->name, diag0val));
3543 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3544
3545 /* Write 0xFF to reset the sequencer */
3546 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3547
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003548 if (ioc->bus_type == SAS) {
3549 ioc_state = mpt_GetIocState(ioc, 0);
3550 if ( (GetIocFacts(ioc, sleepFlag,
3551 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303552 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003553 ioc->name, ioc_state));
3554 return -EFAULT;
3555 }
3556 }
3557
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 for (count=0; count<HZ*20; count++) {
3559 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303560 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3561 "downloadboot successful! (count=%d) IocState=%x\n",
3562 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003563 if (ioc->bus_type == SAS) {
3564 return 0;
3565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303567 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3568 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 ioc->name));
3570 return -EFAULT;
3571 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303572 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3573 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 ioc->name));
3575 return 0;
3576 }
3577 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003578 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 } else {
3580 mdelay (10);
3581 }
3582 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303583 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3584 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 return -EFAULT;
3586}
3587
3588/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003589/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 * KickStart - Perform hard reset of MPT adapter.
3591 * @ioc: Pointer to MPT_ADAPTER structure
3592 * @force: Force hard reset
3593 * @sleepFlag: Specifies whether the process can sleep
3594 *
3595 * This routine places MPT adapter in diagnostic mode via the
3596 * WriteSequence register, and then performs a hard reset of adapter
3597 * via the Diagnostic register.
3598 *
3599 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3600 * or NO_SLEEP (interrupt thread, use mdelay)
3601 * force - 1 if doorbell active, board fault state
3602 * board operational, IOC_RECOVERY or
3603 * IOC_BRINGUP and there is an alt_ioc.
3604 * 0 else
3605 *
3606 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003607 * 1 - hard reset, READY
3608 * 0 - no reset due to History bit, READY
3609 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 * OR reset but failed to come READY
3611 * -2 - no reset, could not enter DIAG mode
3612 * -3 - reset but bad FW bit
3613 */
3614static int
3615KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3616{
3617 int hard_reset_done = 0;
3618 u32 ioc_state=0;
3619 int cnt,cntdn;
3620
Eric Moore29dd3602007-09-14 18:46:51 -06003621 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003622 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 /* Always issue a Msg Unit Reset first. This will clear some
3624 * SCSI bus hang conditions.
3625 */
3626 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3627
3628 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003629 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 } else {
3631 mdelay (1000);
3632 }
3633 }
3634
3635 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3636 if (hard_reset_done < 0)
3637 return hard_reset_done;
3638
Prakash, Sathya436ace72007-07-24 15:42:08 +05303639 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003640 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
3642 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3643 for (cnt=0; cnt<cntdn; cnt++) {
3644 ioc_state = mpt_GetIocState(ioc, 1);
3645 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303646 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 ioc->name, cnt));
3648 return hard_reset_done;
3649 }
3650 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003651 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 } else {
3653 mdelay (10);
3654 }
3655 }
3656
Eric Moore29dd3602007-09-14 18:46:51 -06003657 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3658 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 return -1;
3660}
3661
3662/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003663/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 * mpt_diag_reset - Perform hard reset of the adapter.
3665 * @ioc: Pointer to MPT_ADAPTER structure
3666 * @ignore: Set if to honor and clear to ignore
3667 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003668 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 * else set to NO_SLEEP (use mdelay instead)
3670 *
3671 * This routine places the adapter in diagnostic mode via the
3672 * WriteSequence register and then performs a hard reset of adapter
3673 * via the Diagnostic register. Adapter should be in ready state
3674 * upon successful completion.
3675 *
3676 * Returns: 1 hard reset successful
3677 * 0 no reset performed because reset history bit set
3678 * -2 enabling diagnostic mode failed
3679 * -3 diagnostic reset failed
3680 */
3681static int
3682mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3683{
3684 u32 diag0val;
3685 u32 doorbell;
3686 int hard_reset_done = 0;
3687 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303689 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690
Eric Moorecd2c6192007-01-29 09:47:47 -07003691 /* Clear any existing interrupts */
3692 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3693
Eric Moore87cf8982006-06-27 16:09:26 -06003694 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303695 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003696 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003697 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3698 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3699 if (sleepFlag == CAN_SLEEP)
3700 msleep(1);
3701 else
3702 mdelay(1);
3703
3704 for (count = 0; count < 60; count ++) {
3705 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3706 doorbell &= MPI_IOC_STATE_MASK;
3707
Prakash, Sathya436ace72007-07-24 15:42:08 +05303708 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003709 "looking for READY STATE: doorbell=%x"
3710 " count=%d\n",
3711 ioc->name, doorbell, count));
3712 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003713 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003714 }
3715
3716 /* wait 1 sec */
3717 if (sleepFlag == CAN_SLEEP)
3718 msleep(1000);
3719 else
3720 mdelay(1000);
3721 }
3722 return -1;
3723 }
3724
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 /* Use "Diagnostic reset" method! (only thing available!) */
3726 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3727
Prakash, Sathya436ace72007-07-24 15:42:08 +05303728 if (ioc->debug_level & MPT_DEBUG) {
3729 if (ioc->alt_ioc)
3730 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3731 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734
3735 /* Do the reset if we are told to ignore the reset history
3736 * or if the reset history is 0
3737 */
3738 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3739 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3740 /* Write magic sequence to WriteSequence register
3741 * Loop until in diagnostic mode
3742 */
3743 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3744 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3745 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3746 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3747 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3748 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3749
3750 /* wait 100 msec */
3751 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003752 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 } else {
3754 mdelay (100);
3755 }
3756
3757 count++;
3758 if (count > 20) {
3759 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3760 ioc->name, diag0val);
3761 return -2;
3762
3763 }
3764
3765 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3766
Prakash, Sathya436ace72007-07-24 15:42:08 +05303767 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 ioc->name, diag0val));
3769 }
3770
Prakash, Sathya436ace72007-07-24 15:42:08 +05303771 if (ioc->debug_level & MPT_DEBUG) {
3772 if (ioc->alt_ioc)
3773 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3774 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 /*
3778 * Disable the ARM (Bug fix)
3779 *
3780 */
3781 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003782 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
3784 /*
3785 * Now hit the reset bit in the Diagnostic register
3786 * (THE BIG HAMMER!) (Clears DRWE bit).
3787 */
3788 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3789 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303790 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 ioc->name));
3792
3793 /*
3794 * Call each currently registered protocol IOC reset handler
3795 * with pre-reset indication.
3796 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3797 * MptResetHandlers[] registered yet.
3798 */
3799 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303800 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 int r = 0;
3802
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303803 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3804 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303805 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3806 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303807 ioc->name, cb_idx));
3808 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303810 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3811 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303812 ioc->name, ioc->alt_ioc->name, cb_idx));
3813 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 }
3815 }
3816 }
3817 /* FIXME? Examine results here? */
3818 }
3819
Eric Moore0ccdb002006-07-11 17:33:13 -06003820 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303821 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003822 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303823 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3824 else
3825 cached_fw = NULL;
3826 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 /* If the DownloadBoot operation fails, the
3828 * IOC will be left unusable. This is a fatal error
3829 * case. _diag_reset will return < 0
3830 */
3831 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303832 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3834 break;
3835 }
3836
Prakash, Sathya436ace72007-07-24 15:42:08 +05303837 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303838 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 /* wait 1 sec */
3840 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003841 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 } else {
3843 mdelay (1000);
3844 }
3845 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303846 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003847 printk(MYIOC_s_WARN_FMT
3848 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 }
3850
3851 } else {
3852 /* Wait for FW to reload and for board
3853 * to go to the READY state.
3854 * Maximum wait is 60 seconds.
3855 * If fail, no error will check again
3856 * with calling program.
3857 */
3858 for (count = 0; count < 60; count ++) {
3859 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3860 doorbell &= MPI_IOC_STATE_MASK;
3861
3862 if (doorbell == MPI_IOC_STATE_READY) {
3863 break;
3864 }
3865
3866 /* wait 1 sec */
3867 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003868 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 } else {
3870 mdelay (1000);
3871 }
3872 }
3873 }
3874 }
3875
3876 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303877 if (ioc->debug_level & MPT_DEBUG) {
3878 if (ioc->alt_ioc)
3879 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3880 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3881 ioc->name, diag0val, diag1val));
3882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883
3884 /* Clear RESET_HISTORY bit! Place board in the
3885 * diagnostic mode to update the diag register.
3886 */
3887 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3888 count = 0;
3889 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3890 /* Write magic sequence to WriteSequence register
3891 * Loop until in diagnostic mode
3892 */
3893 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3894 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3895 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3896 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3897 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3898 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3899
3900 /* wait 100 msec */
3901 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003902 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 } else {
3904 mdelay (100);
3905 }
3906
3907 count++;
3908 if (count > 20) {
3909 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3910 ioc->name, diag0val);
3911 break;
3912 }
3913 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3914 }
3915 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3916 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3917 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3918 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3919 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3920 ioc->name);
3921 }
3922
3923 /* Disable Diagnostic Mode
3924 */
3925 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3926
3927 /* Check FW reload status flags.
3928 */
3929 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3930 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3931 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3932 ioc->name, diag0val);
3933 return -3;
3934 }
3935
Prakash, Sathya436ace72007-07-24 15:42:08 +05303936 if (ioc->debug_level & MPT_DEBUG) {
3937 if (ioc->alt_ioc)
3938 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3939 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942
3943 /*
3944 * Reset flag that says we've enabled event notification
3945 */
3946 ioc->facts.EventState = 0;
3947
3948 if (ioc->alt_ioc)
3949 ioc->alt_ioc->facts.EventState = 0;
3950
3951 return hard_reset_done;
3952}
3953
3954/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003955/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 * SendIocReset - Send IOCReset request to MPT adapter.
3957 * @ioc: Pointer to MPT_ADAPTER structure
3958 * @reset_type: reset type, expected values are
3959 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003960 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 *
3962 * Send IOCReset request to the MPT adapter.
3963 *
3964 * Returns 0 for success, non-zero for failure.
3965 */
3966static int
3967SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3968{
3969 int r;
3970 u32 state;
3971 int cntdn, count;
3972
Prakash, Sathya436ace72007-07-24 15:42:08 +05303973 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 ioc->name, reset_type));
3975 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3976 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3977 return r;
3978
3979 /* FW ACK'd request, wait for READY state
3980 */
3981 count = 0;
3982 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3983
3984 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3985 cntdn--;
3986 count++;
3987 if (!cntdn) {
3988 if (sleepFlag != CAN_SLEEP)
3989 count *= 10;
3990
Eric Moore29dd3602007-09-14 18:46:51 -06003991 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3992 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 return -ETIME;
3994 }
3995
3996 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003997 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 } else {
3999 mdelay (1); /* 1 msec delay */
4000 }
4001 }
4002
4003 /* TODO!
4004 * Cleanup all event stuff for this IOC; re-issue EventNotification
4005 * request if needed.
4006 */
4007 if (ioc->facts.Function)
4008 ioc->facts.EventState = 0;
4009
4010 return 0;
4011}
4012
4013/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004014/**
4015 * initChainBuffers - Allocate memory for and initialize chain buffers
4016 * @ioc: Pointer to MPT_ADAPTER structure
4017 *
4018 * Allocates memory for and initializes chain buffers,
4019 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 */
4021static int
4022initChainBuffers(MPT_ADAPTER *ioc)
4023{
4024 u8 *mem;
4025 int sz, ii, num_chain;
4026 int scale, num_sge, numSGE;
4027
4028 /* ReqToChain size must equal the req_depth
4029 * index = req_idx
4030 */
4031 if (ioc->ReqToChain == NULL) {
4032 sz = ioc->req_depth * sizeof(int);
4033 mem = kmalloc(sz, GFP_ATOMIC);
4034 if (mem == NULL)
4035 return -1;
4036
4037 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304038 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 ioc->name, mem, sz));
4040 mem = kmalloc(sz, GFP_ATOMIC);
4041 if (mem == NULL)
4042 return -1;
4043
4044 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304045 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 ioc->name, mem, sz));
4047 }
4048 for (ii = 0; ii < ioc->req_depth; ii++) {
4049 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4050 }
4051
4052 /* ChainToChain size must equal the total number
4053 * of chain buffers to be allocated.
4054 * index = chain_idx
4055 *
4056 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004057 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 *
4059 * num_sge = num sge in request frame + last chain buffer
4060 * scale = num sge per chain buffer if no chain element
4061 */
4062 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
4063 if (sizeof(dma_addr_t) == sizeof(u64))
4064 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4065 else
4066 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4067
4068 if (sizeof(dma_addr_t) == sizeof(u64)) {
4069 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4070 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4071 } else {
4072 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4073 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4074 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304075 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 ioc->name, num_sge, numSGE));
4077
4078 if ( numSGE > MPT_SCSI_SG_DEPTH )
4079 numSGE = MPT_SCSI_SG_DEPTH;
4080
4081 num_chain = 1;
4082 while (numSGE - num_sge > 0) {
4083 num_chain++;
4084 num_sge += (scale - 1);
4085 }
4086 num_chain++;
4087
Prakash, Sathya436ace72007-07-24 15:42:08 +05304088 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 ioc->name, numSGE, num_sge, num_chain));
4090
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004091 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 num_chain *= MPT_SCSI_CAN_QUEUE;
4093 else
4094 num_chain *= MPT_FC_CAN_QUEUE;
4095
4096 ioc->num_chain = num_chain;
4097
4098 sz = num_chain * sizeof(int);
4099 if (ioc->ChainToChain == NULL) {
4100 mem = kmalloc(sz, GFP_ATOMIC);
4101 if (mem == NULL)
4102 return -1;
4103
4104 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304105 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 ioc->name, mem, sz));
4107 } else {
4108 mem = (u8 *) ioc->ChainToChain;
4109 }
4110 memset(mem, 0xFF, sz);
4111 return num_chain;
4112}
4113
4114/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004115/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4117 * @ioc: Pointer to MPT_ADAPTER structure
4118 *
4119 * This routine allocates memory for the MPT reply and request frame
4120 * pools (if necessary), and primes the IOC reply FIFO with
4121 * reply frames.
4122 *
4123 * Returns 0 for success, non-zero for failure.
4124 */
4125static int
4126PrimeIocFifos(MPT_ADAPTER *ioc)
4127{
4128 MPT_FRAME_HDR *mf;
4129 unsigned long flags;
4130 dma_addr_t alloc_dma;
4131 u8 *mem;
4132 int i, reply_sz, sz, total_size, num_chain;
4133
4134 /* Prime reply FIFO... */
4135
4136 if (ioc->reply_frames == NULL) {
4137 if ( (num_chain = initChainBuffers(ioc)) < 0)
4138 return -1;
4139
4140 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304141 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304143 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 ioc->name, reply_sz, reply_sz));
4145
4146 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304147 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304149 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 ioc->name, sz, sz));
4151 total_size += sz;
4152
4153 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304154 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304156 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 ioc->name, sz, sz, num_chain));
4158
4159 total_size += sz;
4160 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4161 if (mem == NULL) {
4162 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4163 ioc->name);
4164 goto out_fail;
4165 }
4166
Prakash, Sathya436ace72007-07-24 15:42:08 +05304167 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4169
4170 memset(mem, 0, total_size);
4171 ioc->alloc_total += total_size;
4172 ioc->alloc = mem;
4173 ioc->alloc_dma = alloc_dma;
4174 ioc->alloc_sz = total_size;
4175 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4176 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4177
Prakash, Sathya436ace72007-07-24 15:42:08 +05304178 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004179 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4180
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 alloc_dma += reply_sz;
4182 mem += reply_sz;
4183
4184 /* Request FIFO - WE manage this! */
4185
4186 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4187 ioc->req_frames_dma = alloc_dma;
4188
Prakash, Sathya436ace72007-07-24 15:42:08 +05304189 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 ioc->name, mem, (void *)(ulong)alloc_dma));
4191
4192 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4193
4194#if defined(CONFIG_MTRR) && 0
4195 /*
4196 * Enable Write Combining MTRR for IOC's memory region.
4197 * (at least as much as we can; "size and base must be
4198 * multiples of 4 kiB"
4199 */
4200 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4201 sz,
4202 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304203 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 ioc->name, ioc->req_frames_dma, sz));
4205#endif
4206
4207 for (i = 0; i < ioc->req_depth; i++) {
4208 alloc_dma += ioc->req_sz;
4209 mem += ioc->req_sz;
4210 }
4211
4212 ioc->ChainBuffer = mem;
4213 ioc->ChainBufferDMA = alloc_dma;
4214
Prakash, Sathya436ace72007-07-24 15:42:08 +05304215 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4217
4218 /* Initialize the free chain Q.
4219 */
4220
4221 INIT_LIST_HEAD(&ioc->FreeChainQ);
4222
4223 /* Post the chain buffers to the FreeChainQ.
4224 */
4225 mem = (u8 *)ioc->ChainBuffer;
4226 for (i=0; i < num_chain; i++) {
4227 mf = (MPT_FRAME_HDR *) mem;
4228 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4229 mem += ioc->req_sz;
4230 }
4231
4232 /* Initialize Request frames linked list
4233 */
4234 alloc_dma = ioc->req_frames_dma;
4235 mem = (u8 *) ioc->req_frames;
4236
4237 spin_lock_irqsave(&ioc->FreeQlock, flags);
4238 INIT_LIST_HEAD(&ioc->FreeQ);
4239 for (i = 0; i < ioc->req_depth; i++) {
4240 mf = (MPT_FRAME_HDR *) mem;
4241
4242 /* Queue REQUESTs *internally*! */
4243 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4244
4245 mem += ioc->req_sz;
4246 }
4247 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4248
4249 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4250 ioc->sense_buf_pool =
4251 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4252 if (ioc->sense_buf_pool == NULL) {
4253 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4254 ioc->name);
4255 goto out_fail;
4256 }
4257
4258 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4259 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304260 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4262
4263 }
4264
4265 /* Post Reply frames to FIFO
4266 */
4267 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304268 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4270
4271 for (i = 0; i < ioc->reply_depth; i++) {
4272 /* Write each address to the IOC! */
4273 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4274 alloc_dma += ioc->reply_sz;
4275 }
4276
4277 return 0;
4278
4279out_fail:
4280 if (ioc->alloc != NULL) {
4281 sz = ioc->alloc_sz;
4282 pci_free_consistent(ioc->pcidev,
4283 sz,
4284 ioc->alloc, ioc->alloc_dma);
4285 ioc->reply_frames = NULL;
4286 ioc->req_frames = NULL;
4287 ioc->alloc_total -= sz;
4288 }
4289 if (ioc->sense_buf_pool != NULL) {
4290 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4291 pci_free_consistent(ioc->pcidev,
4292 sz,
4293 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4294 ioc->sense_buf_pool = NULL;
4295 }
4296 return -1;
4297}
4298
4299/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4300/**
4301 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4302 * from IOC via doorbell handshake method.
4303 * @ioc: Pointer to MPT_ADAPTER structure
4304 * @reqBytes: Size of the request in bytes
4305 * @req: Pointer to MPT request frame
4306 * @replyBytes: Expected size of the reply in bytes
4307 * @u16reply: Pointer to area where reply should be written
4308 * @maxwait: Max wait time for a reply (in seconds)
4309 * @sleepFlag: Specifies whether the process can sleep
4310 *
4311 * NOTES: It is the callers responsibility to byte-swap fields in the
4312 * request which are greater than 1 byte in size. It is also the
4313 * callers responsibility to byte-swap response fields which are
4314 * greater than 1 byte in size.
4315 *
4316 * Returns 0 for success, non-zero for failure.
4317 */
4318static int
4319mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004320 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321{
4322 MPIDefaultReply_t *mptReply;
4323 int failcnt = 0;
4324 int t;
4325
4326 /*
4327 * Get ready to cache a handshake reply
4328 */
4329 ioc->hs_reply_idx = 0;
4330 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4331 mptReply->MsgLength = 0;
4332
4333 /*
4334 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4335 * then tell IOC that we want to handshake a request of N words.
4336 * (WRITE u32val to Doorbell reg).
4337 */
4338 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4339 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4340 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4341 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4342
4343 /*
4344 * Wait for IOC's doorbell handshake int
4345 */
4346 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4347 failcnt++;
4348
Prakash, Sathya436ace72007-07-24 15:42:08 +05304349 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4351
4352 /* Read doorbell and check for active bit */
4353 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4354 return -1;
4355
4356 /*
4357 * Clear doorbell int (WRITE 0 to IntStatus reg),
4358 * then wait for IOC to ACKnowledge that it's ready for
4359 * our handshake request.
4360 */
4361 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4362 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4363 failcnt++;
4364
4365 if (!failcnt) {
4366 int ii;
4367 u8 *req_as_bytes = (u8 *) req;
4368
4369 /*
4370 * Stuff request words via doorbell handshake,
4371 * with ACK from IOC for each.
4372 */
4373 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4374 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4375 (req_as_bytes[(ii*4) + 1] << 8) |
4376 (req_as_bytes[(ii*4) + 2] << 16) |
4377 (req_as_bytes[(ii*4) + 3] << 24));
4378
4379 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4380 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4381 failcnt++;
4382 }
4383
Prakash, Sathya436ace72007-07-24 15:42:08 +05304384 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004385 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386
Prakash, Sathya436ace72007-07-24 15:42:08 +05304387 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4389
4390 /*
4391 * Wait for completion of doorbell handshake reply from the IOC
4392 */
4393 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4394 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004395
Prakash, Sathya436ace72007-07-24 15:42:08 +05304396 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4398
4399 /*
4400 * Copy out the cached reply...
4401 */
4402 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4403 u16reply[ii] = ioc->hs_reply[ii];
4404 } else {
4405 return -99;
4406 }
4407
4408 return -failcnt;
4409}
4410
4411/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004412/**
4413 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 * @ioc: Pointer to MPT_ADAPTER structure
4415 * @howlong: How long to wait (in seconds)
4416 * @sleepFlag: Specifies whether the process can sleep
4417 *
4418 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004419 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4420 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 *
4422 * Returns a negative value on failure, else wait loop count.
4423 */
4424static int
4425WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4426{
4427 int cntdn;
4428 int count = 0;
4429 u32 intstat=0;
4430
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004431 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432
4433 if (sleepFlag == CAN_SLEEP) {
4434 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004435 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4437 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4438 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 count++;
4440 }
4441 } else {
4442 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004443 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4445 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4446 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 count++;
4448 }
4449 }
4450
4451 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304452 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 ioc->name, count));
4454 return count;
4455 }
4456
4457 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4458 ioc->name, count, intstat);
4459 return -1;
4460}
4461
4462/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004463/**
4464 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 * @ioc: Pointer to MPT_ADAPTER structure
4466 * @howlong: How long to wait (in seconds)
4467 * @sleepFlag: Specifies whether the process can sleep
4468 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004469 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4470 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 *
4472 * Returns a negative value on failure, else wait loop count.
4473 */
4474static int
4475WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4476{
4477 int cntdn;
4478 int count = 0;
4479 u32 intstat=0;
4480
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004481 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 if (sleepFlag == CAN_SLEEP) {
4483 while (--cntdn) {
4484 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4485 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4486 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004487 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 count++;
4489 }
4490 } else {
4491 while (--cntdn) {
4492 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4493 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4494 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004495 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 count++;
4497 }
4498 }
4499
4500 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304501 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 ioc->name, count, howlong));
4503 return count;
4504 }
4505
4506 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4507 ioc->name, count, intstat);
4508 return -1;
4509}
4510
4511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004512/**
4513 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 * @ioc: Pointer to MPT_ADAPTER structure
4515 * @howlong: How long to wait (in seconds)
4516 * @sleepFlag: Specifies whether the process can sleep
4517 *
4518 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4519 * Reply is cached to IOC private area large enough to hold a maximum
4520 * of 128 bytes of reply data.
4521 *
4522 * Returns a negative value on failure, else size of reply in WORDS.
4523 */
4524static int
4525WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4526{
4527 int u16cnt = 0;
4528 int failcnt = 0;
4529 int t;
4530 u16 *hs_reply = ioc->hs_reply;
4531 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4532 u16 hword;
4533
4534 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4535
4536 /*
4537 * Get first two u16's so we can look at IOC's intended reply MsgLength
4538 */
4539 u16cnt=0;
4540 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4541 failcnt++;
4542 } else {
4543 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4544 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4545 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4546 failcnt++;
4547 else {
4548 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4549 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4550 }
4551 }
4552
Prakash, Sathya436ace72007-07-24 15:42:08 +05304553 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004554 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4556
4557 /*
4558 * If no error (and IOC said MsgLength is > 0), piece together
4559 * reply 16 bits at a time.
4560 */
4561 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4562 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4563 failcnt++;
4564 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4565 /* don't overflow our IOC hs_reply[] buffer! */
4566 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4567 hs_reply[u16cnt] = hword;
4568 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4569 }
4570
4571 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4572 failcnt++;
4573 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4574
4575 if (failcnt) {
4576 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4577 ioc->name);
4578 return -failcnt;
4579 }
4580#if 0
4581 else if (u16cnt != (2 * mptReply->MsgLength)) {
4582 return -101;
4583 }
4584 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4585 return -102;
4586 }
4587#endif
4588
Prakash, Sathya436ace72007-07-24 15:42:08 +05304589 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004590 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591
Prakash, Sathya436ace72007-07-24 15:42:08 +05304592 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 ioc->name, t, u16cnt/2));
4594 return u16cnt/2;
4595}
4596
4597/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004598/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 * GetLanConfigPages - Fetch LANConfig pages.
4600 * @ioc: Pointer to MPT_ADAPTER structure
4601 *
4602 * Return: 0 for success
4603 * -ENOMEM if no memory available
4604 * -EPERM if not allowed due to ISR context
4605 * -EAGAIN if no msg frames currently available
4606 * -EFAULT for non-successful reply or no reply (timeout)
4607 */
4608static int
4609GetLanConfigPages(MPT_ADAPTER *ioc)
4610{
4611 ConfigPageHeader_t hdr;
4612 CONFIGPARMS cfg;
4613 LANPage0_t *ppage0_alloc;
4614 dma_addr_t page0_dma;
4615 LANPage1_t *ppage1_alloc;
4616 dma_addr_t page1_dma;
4617 int rc = 0;
4618 int data_sz;
4619 int copy_sz;
4620
4621 /* Get LAN Page 0 header */
4622 hdr.PageVersion = 0;
4623 hdr.PageLength = 0;
4624 hdr.PageNumber = 0;
4625 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004626 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 cfg.physAddr = -1;
4628 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4629 cfg.dir = 0;
4630 cfg.pageAddr = 0;
4631 cfg.timeout = 0;
4632
4633 if ((rc = mpt_config(ioc, &cfg)) != 0)
4634 return rc;
4635
4636 if (hdr.PageLength > 0) {
4637 data_sz = hdr.PageLength * 4;
4638 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4639 rc = -ENOMEM;
4640 if (ppage0_alloc) {
4641 memset((u8 *)ppage0_alloc, 0, data_sz);
4642 cfg.physAddr = page0_dma;
4643 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4644
4645 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4646 /* save the data */
4647 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4648 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4649
4650 }
4651
4652 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4653
4654 /* FIXME!
4655 * Normalize endianness of structure data,
4656 * by byte-swapping all > 1 byte fields!
4657 */
4658
4659 }
4660
4661 if (rc)
4662 return rc;
4663 }
4664
4665 /* Get LAN Page 1 header */
4666 hdr.PageVersion = 0;
4667 hdr.PageLength = 0;
4668 hdr.PageNumber = 1;
4669 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004670 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 cfg.physAddr = -1;
4672 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4673 cfg.dir = 0;
4674 cfg.pageAddr = 0;
4675
4676 if ((rc = mpt_config(ioc, &cfg)) != 0)
4677 return rc;
4678
4679 if (hdr.PageLength == 0)
4680 return 0;
4681
4682 data_sz = hdr.PageLength * 4;
4683 rc = -ENOMEM;
4684 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4685 if (ppage1_alloc) {
4686 memset((u8 *)ppage1_alloc, 0, data_sz);
4687 cfg.physAddr = page1_dma;
4688 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4689
4690 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4691 /* save the data */
4692 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4693 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4694 }
4695
4696 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4697
4698 /* FIXME!
4699 * Normalize endianness of structure data,
4700 * by byte-swapping all > 1 byte fields!
4701 */
4702
4703 }
4704
4705 return rc;
4706}
4707
4708/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004709/**
4710 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004711 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004712 * @persist_opcode: see below
4713 *
4714 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4715 * devices not currently present.
4716 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4717 *
4718 * NOTE: Don't use not this function during interrupt time.
4719 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004720 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004721 */
4722
4723/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4724int
4725mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4726{
4727 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4728 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4729 MPT_FRAME_HDR *mf = NULL;
4730 MPIHeader_t *mpi_hdr;
4731
4732
4733 /* insure garbage is not sent to fw */
4734 switch(persist_opcode) {
4735
4736 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4737 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4738 break;
4739
4740 default:
4741 return -1;
4742 break;
4743 }
4744
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004745 printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004746
4747 /* Get a MF for this command.
4748 */
4749 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004750 printk("%s: no msg frames!\n",__func__);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004751 return -1;
4752 }
4753
4754 mpi_hdr = (MPIHeader_t *) mf;
4755 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4756 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4757 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4758 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4759 sasIoUnitCntrReq->Operation = persist_opcode;
4760
4761 init_timer(&ioc->persist_timer);
4762 ioc->persist_timer.data = (unsigned long) ioc;
4763 ioc->persist_timer.function = mpt_timer_expired;
4764 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4765 ioc->persist_wait_done=0;
4766 add_timer(&ioc->persist_timer);
4767 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4768 wait_event(mpt_waitq, ioc->persist_wait_done);
4769
4770 sasIoUnitCntrReply =
4771 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4772 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4773 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004774 __func__,
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004775 sasIoUnitCntrReply->IOCStatus,
4776 sasIoUnitCntrReply->IOCLogInfo);
4777 return -1;
4778 }
4779
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004780 printk("%s: success\n",__func__);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004781 return 0;
4782}
4783
4784/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004785
4786static void
4787mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4788 MpiEventDataRaid_t * pRaidEventData)
4789{
4790 int volume;
4791 int reason;
4792 int disk;
4793 int status;
4794 int flags;
4795 int state;
4796
4797 volume = pRaidEventData->VolumeID;
4798 reason = pRaidEventData->ReasonCode;
4799 disk = pRaidEventData->PhysDiskNum;
4800 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4801 flags = (status >> 0) & 0xff;
4802 state = (status >> 8) & 0xff;
4803
4804 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4805 return;
4806 }
4807
4808 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4809 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4810 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004811 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4812 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004813 } else {
4814 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4815 ioc->name, volume);
4816 }
4817
4818 switch(reason) {
4819 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4820 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4821 ioc->name);
4822 break;
4823
4824 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4825
4826 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4827 ioc->name);
4828 break;
4829
4830 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4831 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4832 ioc->name);
4833 break;
4834
4835 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4836 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4837 ioc->name,
4838 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4839 ? "optimal"
4840 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4841 ? "degraded"
4842 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4843 ? "failed"
4844 : "state unknown",
4845 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4846 ? ", enabled" : "",
4847 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4848 ? ", quiesced" : "",
4849 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4850 ? ", resync in progress" : "" );
4851 break;
4852
4853 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4854 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4855 ioc->name, disk);
4856 break;
4857
4858 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4859 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4860 ioc->name);
4861 break;
4862
4863 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4864 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4865 ioc->name);
4866 break;
4867
4868 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4869 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4870 ioc->name);
4871 break;
4872
4873 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4874 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4875 ioc->name,
4876 state == MPI_PHYSDISK0_STATUS_ONLINE
4877 ? "online"
4878 : state == MPI_PHYSDISK0_STATUS_MISSING
4879 ? "missing"
4880 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4881 ? "not compatible"
4882 : state == MPI_PHYSDISK0_STATUS_FAILED
4883 ? "failed"
4884 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4885 ? "initializing"
4886 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4887 ? "offline requested"
4888 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4889 ? "failed requested"
4890 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4891 ? "offline"
4892 : "state unknown",
4893 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4894 ? ", out of sync" : "",
4895 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4896 ? ", quiesced" : "" );
4897 break;
4898
4899 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4900 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4901 ioc->name, disk);
4902 break;
4903
4904 case MPI_EVENT_RAID_RC_SMART_DATA:
4905 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4906 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4907 break;
4908
4909 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4910 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4911 ioc->name, disk);
4912 break;
4913 }
4914}
4915
4916/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004917/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4919 * @ioc: Pointer to MPT_ADAPTER structure
4920 *
4921 * Returns: 0 for success
4922 * -ENOMEM if no memory available
4923 * -EPERM if not allowed due to ISR context
4924 * -EAGAIN if no msg frames currently available
4925 * -EFAULT for non-successful reply or no reply (timeout)
4926 */
4927static int
4928GetIoUnitPage2(MPT_ADAPTER *ioc)
4929{
4930 ConfigPageHeader_t hdr;
4931 CONFIGPARMS cfg;
4932 IOUnitPage2_t *ppage_alloc;
4933 dma_addr_t page_dma;
4934 int data_sz;
4935 int rc;
4936
4937 /* Get the page header */
4938 hdr.PageVersion = 0;
4939 hdr.PageLength = 0;
4940 hdr.PageNumber = 2;
4941 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004942 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 cfg.physAddr = -1;
4944 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4945 cfg.dir = 0;
4946 cfg.pageAddr = 0;
4947 cfg.timeout = 0;
4948
4949 if ((rc = mpt_config(ioc, &cfg)) != 0)
4950 return rc;
4951
4952 if (hdr.PageLength == 0)
4953 return 0;
4954
4955 /* Read the config page */
4956 data_sz = hdr.PageLength * 4;
4957 rc = -ENOMEM;
4958 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4959 if (ppage_alloc) {
4960 memset((u8 *)ppage_alloc, 0, data_sz);
4961 cfg.physAddr = page_dma;
4962 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4963
4964 /* If Good, save data */
4965 if ((rc = mpt_config(ioc, &cfg)) == 0)
4966 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4967
4968 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4969 }
4970
4971 return rc;
4972}
4973
4974/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004975/**
4976 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 * @ioc: Pointer to a Adapter Strucutre
4978 * @portnum: IOC port number
4979 *
4980 * Return: -EFAULT if read of config page header fails
4981 * or if no nvram
4982 * If read of SCSI Port Page 0 fails,
4983 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4984 * Adapter settings: async, narrow
4985 * Return 1
4986 * If read of SCSI Port Page 2 fails,
4987 * Adapter settings valid
4988 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4989 * Return 1
4990 * Else
4991 * Both valid
4992 * Return 0
4993 * CHECK - what type of locking mechanisms should be used????
4994 */
4995static int
4996mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4997{
4998 u8 *pbuf;
4999 dma_addr_t buf_dma;
5000 CONFIGPARMS cfg;
5001 ConfigPageHeader_t header;
5002 int ii;
5003 int data, rc = 0;
5004
5005 /* Allocate memory
5006 */
5007 if (!ioc->spi_data.nvram) {
5008 int sz;
5009 u8 *mem;
5010 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5011 mem = kmalloc(sz, GFP_ATOMIC);
5012 if (mem == NULL)
5013 return -EFAULT;
5014
5015 ioc->spi_data.nvram = (int *) mem;
5016
Prakash, Sathya436ace72007-07-24 15:42:08 +05305017 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 ioc->name, ioc->spi_data.nvram, sz));
5019 }
5020
5021 /* Invalidate NVRAM information
5022 */
5023 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5024 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5025 }
5026
5027 /* Read SPP0 header, allocate memory, then read page.
5028 */
5029 header.PageVersion = 0;
5030 header.PageLength = 0;
5031 header.PageNumber = 0;
5032 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005033 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034 cfg.physAddr = -1;
5035 cfg.pageAddr = portnum;
5036 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5037 cfg.dir = 0;
5038 cfg.timeout = 0; /* use default */
5039 if (mpt_config(ioc, &cfg) != 0)
5040 return -EFAULT;
5041
5042 if (header.PageLength > 0) {
5043 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5044 if (pbuf) {
5045 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5046 cfg.physAddr = buf_dma;
5047 if (mpt_config(ioc, &cfg) != 0) {
5048 ioc->spi_data.maxBusWidth = MPT_NARROW;
5049 ioc->spi_data.maxSyncOffset = 0;
5050 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5051 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5052 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305053 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5054 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005055 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 } else {
5057 /* Save the Port Page 0 data
5058 */
5059 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5060 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5061 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5062
5063 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5064 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005065 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5066 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 ioc->name, pPP0->Capabilities));
5068 }
5069 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5070 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5071 if (data) {
5072 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5073 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5074 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305075 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5076 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005077 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 } else {
5079 ioc->spi_data.maxSyncOffset = 0;
5080 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5081 }
5082
5083 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5084
5085 /* Update the minSyncFactor based on bus type.
5086 */
5087 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5088 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5089
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005090 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305092 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5093 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005094 ioc->name, ioc->spi_data.minSyncFactor));
5095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 }
5097 }
5098 if (pbuf) {
5099 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5100 }
5101 }
5102 }
5103
5104 /* SCSI Port Page 2 - Read the header then the page.
5105 */
5106 header.PageVersion = 0;
5107 header.PageLength = 0;
5108 header.PageNumber = 2;
5109 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005110 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 cfg.physAddr = -1;
5112 cfg.pageAddr = portnum;
5113 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5114 cfg.dir = 0;
5115 if (mpt_config(ioc, &cfg) != 0)
5116 return -EFAULT;
5117
5118 if (header.PageLength > 0) {
5119 /* Allocate memory and read SCSI Port Page 2
5120 */
5121 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5122 if (pbuf) {
5123 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5124 cfg.physAddr = buf_dma;
5125 if (mpt_config(ioc, &cfg) != 0) {
5126 /* Nvram data is left with INVALID mark
5127 */
5128 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005129 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5130
5131 /* This is an ATTO adapter, read Page2 accordingly
5132 */
5133 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5134 ATTODeviceInfo_t *pdevice = NULL;
5135 u16 ATTOFlags;
5136
5137 /* Save the Port Page 2 data
5138 * (reformat into a 32bit quantity)
5139 */
5140 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5141 pdevice = &pPP2->DeviceSettings[ii];
5142 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5143 data = 0;
5144
5145 /* Translate ATTO device flags to LSI format
5146 */
5147 if (ATTOFlags & ATTOFLAG_DISC)
5148 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5149 if (ATTOFlags & ATTOFLAG_ID_ENB)
5150 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5151 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5152 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5153 if (ATTOFlags & ATTOFLAG_TAGGED)
5154 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5155 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5156 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5157
5158 data = (data << 16) | (pdevice->Period << 8) | 10;
5159 ioc->spi_data.nvram[ii] = data;
5160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 } else {
5162 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5163 MpiDeviceInfo_t *pdevice = NULL;
5164
Moore, Ericd8e925d2006-01-16 18:53:06 -07005165 /*
5166 * Save "Set to Avoid SCSI Bus Resets" flag
5167 */
5168 ioc->spi_data.bus_reset =
5169 (le32_to_cpu(pPP2->PortFlags) &
5170 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5171 0 : 1 ;
5172
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173 /* Save the Port Page 2 data
5174 * (reformat into a 32bit quantity)
5175 */
5176 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5177 ioc->spi_data.PortFlags = data;
5178 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5179 pdevice = &pPP2->DeviceSettings[ii];
5180 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5181 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5182 ioc->spi_data.nvram[ii] = data;
5183 }
5184 }
5185
5186 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5187 }
5188 }
5189
5190 /* Update Adapter limits with those from NVRAM
5191 * Comment: Don't need to do this. Target performance
5192 * parameters will never exceed the adapters limits.
5193 */
5194
5195 return rc;
5196}
5197
5198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005199/**
5200 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 * @ioc: Pointer to a Adapter Strucutre
5202 * @portnum: IOC port number
5203 *
5204 * Return: -EFAULT if read of config page header fails
5205 * or 0 if success.
5206 */
5207static int
5208mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5209{
5210 CONFIGPARMS cfg;
5211 ConfigPageHeader_t header;
5212
5213 /* Read the SCSI Device Page 1 header
5214 */
5215 header.PageVersion = 0;
5216 header.PageLength = 0;
5217 header.PageNumber = 1;
5218 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005219 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 cfg.physAddr = -1;
5221 cfg.pageAddr = portnum;
5222 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5223 cfg.dir = 0;
5224 cfg.timeout = 0;
5225 if (mpt_config(ioc, &cfg) != 0)
5226 return -EFAULT;
5227
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005228 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5229 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230
5231 header.PageVersion = 0;
5232 header.PageLength = 0;
5233 header.PageNumber = 0;
5234 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5235 if (mpt_config(ioc, &cfg) != 0)
5236 return -EFAULT;
5237
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005238 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5239 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240
Prakash, Sathya436ace72007-07-24 15:42:08 +05305241 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5243
Prakash, Sathya436ace72007-07-24 15:42:08 +05305244 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5246 return 0;
5247}
5248
Eric Mooreb506ade2007-01-29 09:45:37 -07005249/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005250 * mpt_inactive_raid_list_free - This clears this link list.
5251 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005252 **/
5253static void
5254mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5255{
5256 struct inactive_raid_component_info *component_info, *pNext;
5257
5258 if (list_empty(&ioc->raid_data.inactive_list))
5259 return;
5260
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005261 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005262 list_for_each_entry_safe(component_info, pNext,
5263 &ioc->raid_data.inactive_list, list) {
5264 list_del(&component_info->list);
5265 kfree(component_info);
5266 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005267 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005268}
5269
5270/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005271 * 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 -07005272 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005273 * @ioc : pointer to per adapter structure
5274 * @channel : volume channel
5275 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005276 **/
5277static void
5278mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5279{
5280 CONFIGPARMS cfg;
5281 ConfigPageHeader_t hdr;
5282 dma_addr_t dma_handle;
5283 pRaidVolumePage0_t buffer = NULL;
5284 int i;
5285 RaidPhysDiskPage0_t phys_disk;
5286 struct inactive_raid_component_info *component_info;
5287 int handle_inactive_volumes;
5288
5289 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5290 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5291 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5292 cfg.pageAddr = (channel << 8) + id;
5293 cfg.cfghdr.hdr = &hdr;
5294 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5295
5296 if (mpt_config(ioc, &cfg) != 0)
5297 goto out;
5298
5299 if (!hdr.PageLength)
5300 goto out;
5301
5302 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5303 &dma_handle);
5304
5305 if (!buffer)
5306 goto out;
5307
5308 cfg.physAddr = dma_handle;
5309 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5310
5311 if (mpt_config(ioc, &cfg) != 0)
5312 goto out;
5313
5314 if (!buffer->NumPhysDisks)
5315 goto out;
5316
5317 handle_inactive_volumes =
5318 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5319 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5320 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5321 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5322
5323 if (!handle_inactive_volumes)
5324 goto out;
5325
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005326 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005327 for (i = 0; i < buffer->NumPhysDisks; i++) {
5328 if(mpt_raid_phys_disk_pg0(ioc,
5329 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5330 continue;
5331
5332 if ((component_info = kmalloc(sizeof (*component_info),
5333 GFP_KERNEL)) == NULL)
5334 continue;
5335
5336 component_info->volumeID = id;
5337 component_info->volumeBus = channel;
5338 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5339 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5340 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5341 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5342
5343 list_add_tail(&component_info->list,
5344 &ioc->raid_data.inactive_list);
5345 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005346 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005347
5348 out:
5349 if (buffer)
5350 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5351 dma_handle);
5352}
5353
5354/**
5355 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5356 * @ioc: Pointer to a Adapter Structure
5357 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5358 * @phys_disk: requested payload data returned
5359 *
5360 * Return:
5361 * 0 on success
5362 * -EFAULT if read of config page header fails or data pointer not NULL
5363 * -ENOMEM if pci_alloc failed
5364 **/
5365int
5366mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5367{
5368 CONFIGPARMS cfg;
5369 ConfigPageHeader_t hdr;
5370 dma_addr_t dma_handle;
5371 pRaidPhysDiskPage0_t buffer = NULL;
5372 int rc;
5373
5374 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5375 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5376
5377 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5378 cfg.cfghdr.hdr = &hdr;
5379 cfg.physAddr = -1;
5380 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5381
5382 if (mpt_config(ioc, &cfg) != 0) {
5383 rc = -EFAULT;
5384 goto out;
5385 }
5386
5387 if (!hdr.PageLength) {
5388 rc = -EFAULT;
5389 goto out;
5390 }
5391
5392 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5393 &dma_handle);
5394
5395 if (!buffer) {
5396 rc = -ENOMEM;
5397 goto out;
5398 }
5399
5400 cfg.physAddr = dma_handle;
5401 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5402 cfg.pageAddr = phys_disk_num;
5403
5404 if (mpt_config(ioc, &cfg) != 0) {
5405 rc = -EFAULT;
5406 goto out;
5407 }
5408
5409 rc = 0;
5410 memcpy(phys_disk, buffer, sizeof(*buffer));
5411 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5412
5413 out:
5414
5415 if (buffer)
5416 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5417 dma_handle);
5418
5419 return rc;
5420}
5421
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422/**
5423 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5424 * @ioc: Pointer to a Adapter Strucutre
5425 * @portnum: IOC port number
5426 *
5427 * Return:
5428 * 0 on success
5429 * -EFAULT if read of config page header fails or data pointer not NULL
5430 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005431 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432int
5433mpt_findImVolumes(MPT_ADAPTER *ioc)
5434{
5435 IOCPage2_t *pIoc2;
5436 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 dma_addr_t ioc2_dma;
5438 CONFIGPARMS cfg;
5439 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 int rc = 0;
5441 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005442 int i;
5443
5444 if (!ioc->ir_firmware)
5445 return 0;
5446
5447 /* Free the old page
5448 */
5449 kfree(ioc->raid_data.pIocPg2);
5450 ioc->raid_data.pIocPg2 = NULL;
5451 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452
5453 /* Read IOCP2 header then the page.
5454 */
5455 header.PageVersion = 0;
5456 header.PageLength = 0;
5457 header.PageNumber = 2;
5458 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005459 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 cfg.physAddr = -1;
5461 cfg.pageAddr = 0;
5462 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5463 cfg.dir = 0;
5464 cfg.timeout = 0;
5465 if (mpt_config(ioc, &cfg) != 0)
5466 return -EFAULT;
5467
5468 if (header.PageLength == 0)
5469 return -EFAULT;
5470
5471 iocpage2sz = header.PageLength * 4;
5472 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5473 if (!pIoc2)
5474 return -ENOMEM;
5475
5476 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5477 cfg.physAddr = ioc2_dma;
5478 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005479 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
Eric Mooreb506ade2007-01-29 09:45:37 -07005481 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5482 if (!mem)
5483 goto out;
5484
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005486 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487
Eric Mooreb506ade2007-01-29 09:45:37 -07005488 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489
Eric Mooreb506ade2007-01-29 09:45:37 -07005490 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5491 mpt_inactive_raid_volumes(ioc,
5492 pIoc2->RaidVolume[i].VolumeBus,
5493 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494
Eric Mooreb506ade2007-01-29 09:45:37 -07005495 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5497
5498 return rc;
5499}
5500
Moore, Ericc972c702006-03-14 09:14:06 -07005501static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5503{
5504 IOCPage3_t *pIoc3;
5505 u8 *mem;
5506 CONFIGPARMS cfg;
5507 ConfigPageHeader_t header;
5508 dma_addr_t ioc3_dma;
5509 int iocpage3sz = 0;
5510
5511 /* Free the old page
5512 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005513 kfree(ioc->raid_data.pIocPg3);
5514 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515
5516 /* There is at least one physical disk.
5517 * Read and save IOC Page 3
5518 */
5519 header.PageVersion = 0;
5520 header.PageLength = 0;
5521 header.PageNumber = 3;
5522 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005523 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 cfg.physAddr = -1;
5525 cfg.pageAddr = 0;
5526 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5527 cfg.dir = 0;
5528 cfg.timeout = 0;
5529 if (mpt_config(ioc, &cfg) != 0)
5530 return 0;
5531
5532 if (header.PageLength == 0)
5533 return 0;
5534
5535 /* Read Header good, alloc memory
5536 */
5537 iocpage3sz = header.PageLength * 4;
5538 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5539 if (!pIoc3)
5540 return 0;
5541
5542 /* Read the Page and save the data
5543 * into malloc'd memory.
5544 */
5545 cfg.physAddr = ioc3_dma;
5546 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5547 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005548 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 if (mem) {
5550 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005551 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 }
5553 }
5554
5555 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5556
5557 return 0;
5558}
5559
5560static void
5561mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5562{
5563 IOCPage4_t *pIoc4;
5564 CONFIGPARMS cfg;
5565 ConfigPageHeader_t header;
5566 dma_addr_t ioc4_dma;
5567 int iocpage4sz;
5568
5569 /* Read and save IOC Page 4
5570 */
5571 header.PageVersion = 0;
5572 header.PageLength = 0;
5573 header.PageNumber = 4;
5574 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005575 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 cfg.physAddr = -1;
5577 cfg.pageAddr = 0;
5578 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5579 cfg.dir = 0;
5580 cfg.timeout = 0;
5581 if (mpt_config(ioc, &cfg) != 0)
5582 return;
5583
5584 if (header.PageLength == 0)
5585 return;
5586
5587 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5588 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5589 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5590 if (!pIoc4)
5591 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005592 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 } else {
5594 ioc4_dma = ioc->spi_data.IocPg4_dma;
5595 iocpage4sz = ioc->spi_data.IocPg4Sz;
5596 }
5597
5598 /* Read the Page into dma memory.
5599 */
5600 cfg.physAddr = ioc4_dma;
5601 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5602 if (mpt_config(ioc, &cfg) == 0) {
5603 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5604 ioc->spi_data.IocPg4_dma = ioc4_dma;
5605 ioc->spi_data.IocPg4Sz = iocpage4sz;
5606 } else {
5607 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5608 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005609 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 }
5611}
5612
5613static void
5614mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5615{
5616 IOCPage1_t *pIoc1;
5617 CONFIGPARMS cfg;
5618 ConfigPageHeader_t header;
5619 dma_addr_t ioc1_dma;
5620 int iocpage1sz = 0;
5621 u32 tmp;
5622
5623 /* Check the Coalescing Timeout in IOC Page 1
5624 */
5625 header.PageVersion = 0;
5626 header.PageLength = 0;
5627 header.PageNumber = 1;
5628 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005629 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 cfg.physAddr = -1;
5631 cfg.pageAddr = 0;
5632 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5633 cfg.dir = 0;
5634 cfg.timeout = 0;
5635 if (mpt_config(ioc, &cfg) != 0)
5636 return;
5637
5638 if (header.PageLength == 0)
5639 return;
5640
5641 /* Read Header good, alloc memory
5642 */
5643 iocpage1sz = header.PageLength * 4;
5644 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5645 if (!pIoc1)
5646 return;
5647
5648 /* Read the Page and check coalescing timeout
5649 */
5650 cfg.physAddr = ioc1_dma;
5651 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5652 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305653
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5655 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5656 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5657
Prakash, Sathya436ace72007-07-24 15:42:08 +05305658 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 ioc->name, tmp));
5660
5661 if (tmp > MPT_COALESCING_TIMEOUT) {
5662 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5663
5664 /* Write NVRAM and current
5665 */
5666 cfg.dir = 1;
5667 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5668 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305669 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 ioc->name, MPT_COALESCING_TIMEOUT));
5671
5672 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5673 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305674 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5675 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 ioc->name, MPT_COALESCING_TIMEOUT));
5677 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305678 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5679 "Reset NVRAM Coalescing Timeout Failed\n",
5680 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 }
5682
5683 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305684 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5685 "Reset of Current Coalescing Timeout Failed!\n",
5686 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 }
5688 }
5689
5690 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305691 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 }
5693 }
5694
5695 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5696
5697 return;
5698}
5699
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305700static void
5701mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5702{
5703 CONFIGPARMS cfg;
5704 ConfigPageHeader_t hdr;
5705 dma_addr_t buf_dma;
5706 ManufacturingPage0_t *pbuf = NULL;
5707
5708 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5709 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5710
5711 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5712 cfg.cfghdr.hdr = &hdr;
5713 cfg.physAddr = -1;
5714 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5715 cfg.timeout = 10;
5716
5717 if (mpt_config(ioc, &cfg) != 0)
5718 goto out;
5719
5720 if (!cfg.cfghdr.hdr->PageLength)
5721 goto out;
5722
5723 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5724 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5725 if (!pbuf)
5726 goto out;
5727
5728 cfg.physAddr = buf_dma;
5729
5730 if (mpt_config(ioc, &cfg) != 0)
5731 goto out;
5732
5733 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5734 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5735 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5736
5737 out:
5738
5739 if (pbuf)
5740 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5741}
5742
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005744/**
5745 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 * @ioc: Pointer to MPT_ADAPTER structure
5747 * @EvSwitch: Event switch flags
5748 */
5749static int
5750SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5751{
5752 EventNotification_t *evnp;
5753
5754 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5755 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305756 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 ioc->name));
5758 return 0;
5759 }
5760 memset(evnp, 0, sizeof(*evnp));
5761
Prakash, Sathya436ace72007-07-24 15:42:08 +05305762 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763
5764 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5765 evnp->ChainOffset = 0;
5766 evnp->MsgFlags = 0;
5767 evnp->Switch = EvSwitch;
5768
5769 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5770
5771 return 0;
5772}
5773
5774/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5775/**
5776 * SendEventAck - Send EventAck request to MPT adapter.
5777 * @ioc: Pointer to MPT_ADAPTER structure
5778 * @evnp: Pointer to original EventNotification request
5779 */
5780static int
5781SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5782{
5783 EventAck_t *pAck;
5784
5785 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305786 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005787 ioc->name,__func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 return -1;
5789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790
Prakash, Sathya436ace72007-07-24 15:42:08 +05305791 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792
5793 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5794 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005795 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005797 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 pAck->Event = evnp->Event;
5799 pAck->EventContext = evnp->EventContext;
5800
5801 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5802
5803 return 0;
5804}
5805
5806/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5807/**
5808 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005809 * @ioc: Pointer to an adapter structure
5810 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 * action, page address, direction, physical address
5812 * and pointer to a configuration page header
5813 * Page header is updated.
5814 *
5815 * Returns 0 for success
5816 * -EPERM if not allowed due to ISR context
5817 * -EAGAIN if no msg frames currently available
5818 * -EFAULT for non-successful reply or no reply (timeout)
5819 */
5820int
5821mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5822{
5823 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005824 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825 MPT_FRAME_HDR *mf;
5826 unsigned long flags;
5827 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005828 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829 int in_isr;
5830
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005831 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832 * to be in ISR context, because that is fatal!
5833 */
5834 in_isr = in_interrupt();
5835 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305836 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837 ioc->name));
5838 return -EPERM;
5839 }
5840
5841 /* Get and Populate a free Frame
5842 */
5843 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305844 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845 ioc->name));
5846 return -EAGAIN;
5847 }
5848 pReq = (Config_t *)mf;
5849 pReq->Action = pCfg->action;
5850 pReq->Reserved = 0;
5851 pReq->ChainOffset = 0;
5852 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005853
5854 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005855 pReq->ExtPageLength = 0;
5856 pReq->ExtPageType = 0;
5857 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005858
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859 for (ii=0; ii < 8; ii++)
5860 pReq->Reserved2[ii] = 0;
5861
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005862 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5863 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5864 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5865 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5866
5867 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5868 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5869 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5870 pReq->ExtPageType = pExtHdr->ExtPageType;
5871 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5872
5873 /* Page Length must be treated as a reserved field for the extended header. */
5874 pReq->Header.PageLength = 0;
5875 }
5876
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5878
5879 /* Add a SGE to the config request.
5880 */
5881 if (pCfg->dir)
5882 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5883 else
5884 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5885
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005886 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5887 flagsLength |= pExtHdr->ExtPageLength * 4;
5888
Prakash, Sathya436ace72007-07-24 15:42:08 +05305889 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 +02005890 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5891 }
5892 else {
5893 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5894
Prakash, Sathya436ace72007-07-24 15:42:08 +05305895 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 +02005896 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898
5899 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5900
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 /* Append pCfg pointer to end of mf
5902 */
5903 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5904
5905 /* Initalize the timer
5906 */
5907 init_timer(&pCfg->timer);
5908 pCfg->timer.data = (unsigned long) ioc;
5909 pCfg->timer.function = mpt_timer_expired;
5910 pCfg->wait_done = 0;
5911
5912 /* Set the timer; ensure 10 second minimum */
5913 if (pCfg->timeout < 10)
5914 pCfg->timer.expires = jiffies + HZ*10;
5915 else
5916 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5917
5918 /* Add to end of Q, set timer and then issue this command */
5919 spin_lock_irqsave(&ioc->FreeQlock, flags);
5920 list_add_tail(&pCfg->linkage, &ioc->configQ);
5921 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5922
5923 add_timer(&pCfg->timer);
5924 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5925 wait_event(mpt_waitq, pCfg->wait_done);
5926
5927 /* mf has been freed - do not access */
5928
5929 rc = pCfg->status;
5930
5931 return rc;
5932}
5933
5934/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005935/**
5936 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937 * Used only internal config functionality.
5938 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5939 */
5940static void
5941mpt_timer_expired(unsigned long data)
5942{
5943 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5944
Prakash, Sathya436ace72007-07-24 15:42:08 +05305945 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946
5947 /* Perform a FW reload */
5948 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5949 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5950
5951 /* No more processing.
5952 * Hard reset clean-up will wake up
5953 * process and free all resources.
5954 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305955 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956
5957 return;
5958}
5959
5960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005961/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962 * mpt_ioc_reset - Base cleanup for hard reset
5963 * @ioc: Pointer to the adapter structure
5964 * @reset_phase: Indicates pre- or post-reset functionality
5965 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005966 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 */
5968static int
5969mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5970{
5971 CONFIGPARMS *pCfg;
5972 unsigned long flags;
5973
Eric Moore29dd3602007-09-14 18:46:51 -06005974 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5975 ": IOC %s_reset routed to MPT base driver!\n",
5976 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5977 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978
5979 if (reset_phase == MPT_IOC_SETUP_RESET) {
5980 ;
5981 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5982 /* If the internal config Q is not empty -
5983 * delete timer. MF resources will be freed when
5984 * the FIFO's are primed.
5985 */
5986 spin_lock_irqsave(&ioc->FreeQlock, flags);
5987 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5988 del_timer(&pCfg->timer);
5989 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5990
5991 } else {
5992 CONFIGPARMS *pNext;
5993
5994 /* Search the configQ for internal commands.
5995 * Flush the Q, and wake up all suspended threads.
5996 */
5997 spin_lock_irqsave(&ioc->FreeQlock, flags);
5998 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5999 list_del(&pCfg->linkage);
6000
6001 pCfg->status = MPT_CONFIG_ERROR;
6002 pCfg->wait_done = 1;
6003 wake_up(&mpt_waitq);
6004 }
6005 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6006 }
6007
6008 return 1; /* currently means nothing really */
6009}
6010
6011
6012#ifdef CONFIG_PROC_FS /* { */
6013/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6014/*
6015 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6016 */
6017/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006018/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6020 *
6021 * Returns 0 for success, non-zero for failure.
6022 */
6023static int
6024procmpt_create(void)
6025{
6026 struct proc_dir_entry *ent;
6027
6028 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6029 if (mpt_proc_root_dir == NULL)
6030 return -ENOTDIR;
6031
6032 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6033 if (ent)
6034 ent->read_proc = procmpt_summary_read;
6035
6036 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6037 if (ent)
6038 ent->read_proc = procmpt_version_read;
6039
6040 return 0;
6041}
6042
6043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006044/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6046 *
6047 * Returns 0 for success, non-zero for failure.
6048 */
6049static void
6050procmpt_destroy(void)
6051{
6052 remove_proc_entry("version", mpt_proc_root_dir);
6053 remove_proc_entry("summary", mpt_proc_root_dir);
6054 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6055}
6056
6057/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006058/**
6059 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 * @buf: Pointer to area to write information
6061 * @start: Pointer to start pointer
6062 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006063 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 * @eof: Pointer to EOF integer
6065 * @data: Pointer
6066 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006067 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068 * Returns number of characters written to process performing the read.
6069 */
6070static int
6071procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6072{
6073 MPT_ADAPTER *ioc;
6074 char *out = buf;
6075 int len;
6076
6077 if (data) {
6078 int more = 0;
6079
6080 ioc = data;
6081 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6082
6083 out += more;
6084 } else {
6085 list_for_each_entry(ioc, &ioc_list, list) {
6086 int more = 0;
6087
6088 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6089
6090 out += more;
6091 if ((out-buf) >= request)
6092 break;
6093 }
6094 }
6095
6096 len = out - buf;
6097
6098 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6099}
6100
6101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006102/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 * procmpt_version_read - Handle read request from /proc/mpt/version.
6104 * @buf: Pointer to area to write information
6105 * @start: Pointer to start pointer
6106 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006107 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 * @eof: Pointer to EOF integer
6109 * @data: Pointer
6110 *
6111 * Returns number of characters written to process performing the read.
6112 */
6113static int
6114procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6115{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306116 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006117 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 char *drvname;
6119 int len;
6120
6121 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6122 len += sprintf(buf+len, " Fusion MPT base driver\n");
6123
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006124 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006125 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306127 if (MptCallbacks[cb_idx]) {
6128 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006129 case MPTSPI_DRIVER:
6130 if (!scsi++) drvname = "SPI host";
6131 break;
6132 case MPTFC_DRIVER:
6133 if (!fc++) drvname = "FC host";
6134 break;
6135 case MPTSAS_DRIVER:
6136 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137 break;
6138 case MPTLAN_DRIVER:
6139 if (!lan++) drvname = "LAN";
6140 break;
6141 case MPTSTM_DRIVER:
6142 if (!targ++) drvname = "SCSI target";
6143 break;
6144 case MPTCTL_DRIVER:
6145 if (!ctl++) drvname = "ioctl";
6146 break;
6147 }
6148
6149 if (drvname)
6150 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6151 }
6152 }
6153
6154 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6155}
6156
6157/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006158/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6160 * @buf: Pointer to area to write information
6161 * @start: Pointer to start pointer
6162 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006163 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006164 * @eof: Pointer to EOF integer
6165 * @data: Pointer
6166 *
6167 * Returns number of characters written to process performing the read.
6168 */
6169static int
6170procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6171{
6172 MPT_ADAPTER *ioc = data;
6173 int len;
6174 char expVer[32];
6175 int sz;
6176 int p;
6177
6178 mpt_get_fw_exp_ver(expVer, ioc);
6179
6180 len = sprintf(buf, "%s:", ioc->name);
6181 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6182 len += sprintf(buf+len, " (f/w download boot flag set)");
6183// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6184// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6185
6186 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6187 ioc->facts.ProductID,
6188 ioc->prod_name);
6189 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6190 if (ioc->facts.FWImageSize)
6191 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6192 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6193 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6194 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6195
6196 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6197 ioc->facts.CurrentHostMfaHighAddr);
6198 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6199 ioc->facts.CurrentSenseBufferHighAddr);
6200
6201 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6202 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6203
6204 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6205 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6206 /*
6207 * Rounding UP to nearest 4-kB boundary here...
6208 */
6209 sz = (ioc->req_sz * ioc->req_depth) + 128;
6210 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6211 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6212 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6213 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6214 4*ioc->facts.RequestFrameSize,
6215 ioc->facts.GlobalCredits);
6216
6217 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6218 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6219 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6220 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6221 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6222 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6223 ioc->facts.CurReplyFrameSize,
6224 ioc->facts.ReplyQueueDepth);
6225
6226 len += sprintf(buf+len, " MaxDevices = %d\n",
6227 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6228 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6229
6230 /* per-port info */
6231 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6232 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6233 p+1,
6234 ioc->facts.NumberOfPorts);
6235 if (ioc->bus_type == FC) {
6236 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6237 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6238 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6239 a[5], a[4], a[3], a[2], a[1], a[0]);
6240 }
6241 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6242 ioc->fc_port_page0[p].WWNN.High,
6243 ioc->fc_port_page0[p].WWNN.Low,
6244 ioc->fc_port_page0[p].WWPN.High,
6245 ioc->fc_port_page0[p].WWPN.Low);
6246 }
6247 }
6248
6249 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6250}
6251
6252#endif /* CONFIG_PROC_FS } */
6253
6254/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6255static void
6256mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6257{
6258 buf[0] ='\0';
6259 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6260 sprintf(buf, " (Exp %02d%02d)",
6261 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6262 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6263
6264 /* insider hack! */
6265 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6266 strcat(buf, " [MDBG]");
6267 }
6268}
6269
6270/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6271/**
6272 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6273 * @ioc: Pointer to MPT_ADAPTER structure
6274 * @buffer: Pointer to buffer where IOC summary info should be written
6275 * @size: Pointer to number of bytes we wrote (set by this routine)
6276 * @len: Offset at which to start writing in buffer
6277 * @showlan: Display LAN stuff?
6278 *
6279 * This routine writes (english readable) ASCII text, which represents
6280 * a summary of IOC information, to a buffer.
6281 */
6282void
6283mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6284{
6285 char expVer[32];
6286 int y;
6287
6288 mpt_get_fw_exp_ver(expVer, ioc);
6289
6290 /*
6291 * Shorter summary of attached ioc's...
6292 */
6293 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6294 ioc->name,
6295 ioc->prod_name,
6296 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6297 ioc->facts.FWVersion.Word,
6298 expVer,
6299 ioc->facts.NumberOfPorts,
6300 ioc->req_depth);
6301
6302 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6303 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6304 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6305 a[5], a[4], a[3], a[2], a[1], a[0]);
6306 }
6307
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309
6310 if (!ioc->active)
6311 y += sprintf(buffer+len+y, " (disabled)");
6312
6313 y += sprintf(buffer+len+y, "\n");
6314
6315 *size = y;
6316}
6317
6318/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6319/*
6320 * Reset Handling
6321 */
6322/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6323/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006324 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325 * @ioc: Pointer to MPT_ADAPTER structure
6326 * @sleepFlag: Indicates if sleep or schedule must be called.
6327 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006328 * Issues SCSI Task Management call based on input arg values.
6329 * If TaskMgmt fails, returns associated SCSI request.
6330 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6332 * or a non-interrupt thread. In the former, must not call schedule().
6333 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006334 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335 * FW reload/initialization failed.
6336 *
6337 * Returns 0 for SUCCESS or -1 if FAILED.
6338 */
6339int
6340mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6341{
6342 int rc;
6343 unsigned long flags;
6344
Prakash, Sathya436ace72007-07-24 15:42:08 +05306345 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346#ifdef MFCNT
6347 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6348 printk("MF count 0x%x !\n", ioc->mfcnt);
6349#endif
6350
6351 /* Reset the adapter. Prevent more than 1 call to
6352 * mpt_do_ioc_recovery at any instant in time.
6353 */
6354 spin_lock_irqsave(&ioc->diagLock, flags);
6355 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6356 spin_unlock_irqrestore(&ioc->diagLock, flags);
6357 return 0;
6358 } else {
6359 ioc->diagPending = 1;
6360 }
6361 spin_unlock_irqrestore(&ioc->diagLock, flags);
6362
6363 /* FIXME: If do_ioc_recovery fails, repeat....
6364 */
6365
6366 /* The SCSI driver needs to adjust timeouts on all current
6367 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006368 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 * For all other protocol drivers, this is a no-op.
6370 */
6371 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306372 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373 int r = 0;
6374
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306375 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6376 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306377 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306378 ioc->name, cb_idx));
6379 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306381 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306382 ioc->name, ioc->alt_ioc->name, cb_idx));
6383 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384 }
6385 }
6386 }
6387 }
6388
6389 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006390 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391 }
6392 ioc->reload_fw = 0;
6393 if (ioc->alt_ioc)
6394 ioc->alt_ioc->reload_fw = 0;
6395
6396 spin_lock_irqsave(&ioc->diagLock, flags);
6397 ioc->diagPending = 0;
6398 if (ioc->alt_ioc)
6399 ioc->alt_ioc->diagPending = 0;
6400 spin_unlock_irqrestore(&ioc->diagLock, flags);
6401
Prakash, Sathya436ace72007-07-24 15:42:08 +05306402 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403
6404 return rc;
6405}
6406
6407/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006408static void
6409EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410{
Eric Moore509e5e52006-04-26 13:22:37 -06006411 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006412
6413 switch(event) {
6414 case MPI_EVENT_NONE:
6415 ds = "None";
6416 break;
6417 case MPI_EVENT_LOG_DATA:
6418 ds = "Log Data";
6419 break;
6420 case MPI_EVENT_STATE_CHANGE:
6421 ds = "State Change";
6422 break;
6423 case MPI_EVENT_UNIT_ATTENTION:
6424 ds = "Unit Attention";
6425 break;
6426 case MPI_EVENT_IOC_BUS_RESET:
6427 ds = "IOC Bus Reset";
6428 break;
6429 case MPI_EVENT_EXT_BUS_RESET:
6430 ds = "External Bus Reset";
6431 break;
6432 case MPI_EVENT_RESCAN:
6433 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434 break;
6435 case MPI_EVENT_LINK_STATUS_CHANGE:
6436 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6437 ds = "Link Status(FAILURE) Change";
6438 else
6439 ds = "Link Status(ACTIVE) Change";
6440 break;
6441 case MPI_EVENT_LOOP_STATE_CHANGE:
6442 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6443 ds = "Loop State(LIP) Change";
6444 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006445 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446 else
Eric Moore509e5e52006-04-26 13:22:37 -06006447 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448 break;
6449 case MPI_EVENT_LOGOUT:
6450 ds = "Logout";
6451 break;
6452 case MPI_EVENT_EVENT_CHANGE:
6453 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006454 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006455 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006456 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006457 break;
6458 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006459 {
6460 u8 ReasonCode = (u8)(evData0 >> 16);
6461 switch (ReasonCode) {
6462 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6463 ds = "Integrated Raid: Volume Created";
6464 break;
6465 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6466 ds = "Integrated Raid: Volume Deleted";
6467 break;
6468 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6469 ds = "Integrated Raid: Volume Settings Changed";
6470 break;
6471 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6472 ds = "Integrated Raid: Volume Status Changed";
6473 break;
6474 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6475 ds = "Integrated Raid: Volume Physdisk Changed";
6476 break;
6477 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6478 ds = "Integrated Raid: Physdisk Created";
6479 break;
6480 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6481 ds = "Integrated Raid: Physdisk Deleted";
6482 break;
6483 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6484 ds = "Integrated Raid: Physdisk Settings Changed";
6485 break;
6486 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6487 ds = "Integrated Raid: Physdisk Status Changed";
6488 break;
6489 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6490 ds = "Integrated Raid: Domain Validation Needed";
6491 break;
6492 case MPI_EVENT_RAID_RC_SMART_DATA :
6493 ds = "Integrated Raid; Smart Data";
6494 break;
6495 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6496 ds = "Integrated Raid: Replace Action Started";
6497 break;
6498 default:
6499 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006500 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006501 }
6502 break;
6503 }
6504 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6505 ds = "SCSI Device Status Change";
6506 break;
6507 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6508 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006509 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006510 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006511 u8 ReasonCode = (u8)(evData0 >> 16);
6512 switch (ReasonCode) {
6513 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006514 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006515 "SAS Device Status Change: Added: "
6516 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006517 break;
6518 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006519 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006520 "SAS Device Status Change: Deleted: "
6521 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006522 break;
6523 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006524 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006525 "SAS Device Status Change: SMART Data: "
6526 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006527 break;
6528 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006529 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006530 "SAS Device Status Change: No Persistancy: "
6531 "id=%d channel=%d", id, channel);
6532 break;
6533 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6534 snprintf(evStr, EVENT_DESCR_STR_SZ,
6535 "SAS Device Status Change: Unsupported Device "
6536 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006537 break;
6538 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6539 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006540 "SAS Device Status Change: Internal Device "
6541 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006542 break;
6543 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6544 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006545 "SAS Device Status Change: Internal Task "
6546 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006547 break;
6548 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6549 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006550 "SAS Device Status Change: Internal Abort "
6551 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006552 break;
6553 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6554 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006555 "SAS Device Status Change: Internal Clear "
6556 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006557 break;
6558 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6559 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006560 "SAS Device Status Change: Internal Query "
6561 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006562 break;
6563 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006564 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006565 "SAS Device Status Change: Unknown: "
6566 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006567 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006568 }
6569 break;
6570 }
6571 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6572 ds = "Bus Timer Expired";
6573 break;
6574 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006575 {
6576 u16 curr_depth = (u16)(evData0 >> 16);
6577 u8 channel = (u8)(evData0 >> 8);
6578 u8 id = (u8)(evData0);
6579
6580 snprintf(evStr, EVENT_DESCR_STR_SZ,
6581 "Queue Full: channel=%d id=%d depth=%d",
6582 channel, id, curr_depth);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006583 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006584 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006585 case MPI_EVENT_SAS_SES:
6586 ds = "SAS SES Event";
6587 break;
6588 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6589 ds = "Persistent Table Full";
6590 break;
6591 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006592 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006593 u8 LinkRates = (u8)(evData0 >> 8);
6594 u8 PhyNumber = (u8)(evData0);
6595 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6596 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6597 switch (LinkRates) {
6598 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006599 snprintf(evStr, EVENT_DESCR_STR_SZ,
6600 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006601 " Rate Unknown",PhyNumber);
6602 break;
6603 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006604 snprintf(evStr, EVENT_DESCR_STR_SZ,
6605 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006606 " Phy Disabled",PhyNumber);
6607 break;
6608 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006609 snprintf(evStr, EVENT_DESCR_STR_SZ,
6610 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006611 " Failed Speed Nego",PhyNumber);
6612 break;
6613 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006614 snprintf(evStr, EVENT_DESCR_STR_SZ,
6615 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006616 " Sata OOB Completed",PhyNumber);
6617 break;
6618 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006619 snprintf(evStr, EVENT_DESCR_STR_SZ,
6620 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006621 " Rate 1.5 Gbps",PhyNumber);
6622 break;
6623 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006624 snprintf(evStr, EVENT_DESCR_STR_SZ,
6625 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006626 " Rate 3.0 Gpbs",PhyNumber);
6627 break;
6628 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006629 snprintf(evStr, EVENT_DESCR_STR_SZ,
6630 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006631 break;
6632 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006633 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006634 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006635 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6636 ds = "SAS Discovery Error";
6637 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006638 case MPI_EVENT_IR_RESYNC_UPDATE:
6639 {
6640 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006641 snprintf(evStr, EVENT_DESCR_STR_SZ,
6642 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006643 break;
6644 }
6645 case MPI_EVENT_IR2:
6646 {
6647 u8 ReasonCode = (u8)(evData0 >> 16);
6648 switch (ReasonCode) {
6649 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6650 ds = "IR2: LD State Changed";
6651 break;
6652 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6653 ds = "IR2: PD State Changed";
6654 break;
6655 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6656 ds = "IR2: Bad Block Table Full";
6657 break;
6658 case MPI_EVENT_IR2_RC_PD_INSERTED:
6659 ds = "IR2: PD Inserted";
6660 break;
6661 case MPI_EVENT_IR2_RC_PD_REMOVED:
6662 ds = "IR2: PD Removed";
6663 break;
6664 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6665 ds = "IR2: Foreign CFG Detected";
6666 break;
6667 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6668 ds = "IR2: Rebuild Medium Error";
6669 break;
6670 default:
6671 ds = "IR2";
6672 break;
6673 }
6674 break;
6675 }
6676 case MPI_EVENT_SAS_DISCOVERY:
6677 {
6678 if (evData0)
6679 ds = "SAS Discovery: Start";
6680 else
6681 ds = "SAS Discovery: Stop";
6682 break;
6683 }
6684 case MPI_EVENT_LOG_ENTRY_ADDED:
6685 ds = "SAS Log Entry Added";
6686 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006687
Eric Moorec6c727a2007-01-29 09:44:54 -07006688 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6689 {
6690 u8 phy_num = (u8)(evData0);
6691 u8 port_num = (u8)(evData0 >> 8);
6692 u8 port_width = (u8)(evData0 >> 16);
6693 u8 primative = (u8)(evData0 >> 24);
6694 snprintf(evStr, EVENT_DESCR_STR_SZ,
6695 "SAS Broadcase Primative: phy=%d port=%d "
6696 "width=%d primative=0x%02x",
6697 phy_num, port_num, port_width, primative);
6698 break;
6699 }
6700
6701 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6702 {
6703 u8 reason = (u8)(evData0);
6704 u8 port_num = (u8)(evData0 >> 8);
6705 u16 handle = le16_to_cpu(evData0 >> 16);
6706
6707 snprintf(evStr, EVENT_DESCR_STR_SZ,
6708 "SAS Initiator Device Status Change: reason=0x%02x "
6709 "port=%d handle=0x%04x",
6710 reason, port_num, handle);
6711 break;
6712 }
6713
6714 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6715 {
6716 u8 max_init = (u8)(evData0);
6717 u8 current_init = (u8)(evData0 >> 8);
6718
6719 snprintf(evStr, EVENT_DESCR_STR_SZ,
6720 "SAS Initiator Device Table Overflow: max initiators=%02d "
6721 "current initators=%02d",
6722 max_init, current_init);
6723 break;
6724 }
6725 case MPI_EVENT_SAS_SMP_ERROR:
6726 {
6727 u8 status = (u8)(evData0);
6728 u8 port_num = (u8)(evData0 >> 8);
6729 u8 result = (u8)(evData0 >> 16);
6730
6731 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6732 snprintf(evStr, EVENT_DESCR_STR_SZ,
6733 "SAS SMP Error: port=%d result=0x%02x",
6734 port_num, result);
6735 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6736 snprintf(evStr, EVENT_DESCR_STR_SZ,
6737 "SAS SMP Error: port=%d : CRC Error",
6738 port_num);
6739 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6740 snprintf(evStr, EVENT_DESCR_STR_SZ,
6741 "SAS SMP Error: port=%d : Timeout",
6742 port_num);
6743 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6744 snprintf(evStr, EVENT_DESCR_STR_SZ,
6745 "SAS SMP Error: port=%d : No Destination",
6746 port_num);
6747 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6748 snprintf(evStr, EVENT_DESCR_STR_SZ,
6749 "SAS SMP Error: port=%d : Bad Destination",
6750 port_num);
6751 else
6752 snprintf(evStr, EVENT_DESCR_STR_SZ,
6753 "SAS SMP Error: port=%d : status=0x%02x",
6754 port_num, status);
6755 break;
6756 }
6757
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758 /*
6759 * MPT base "custom" events may be added here...
6760 */
6761 default:
6762 ds = "Unknown";
6763 break;
6764 }
Eric Moore509e5e52006-04-26 13:22:37 -06006765 if (ds)
6766 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767}
6768
6769/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006770/**
6771 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772 * @ioc: Pointer to MPT_ADAPTER structure
6773 * @pEventReply: Pointer to EventNotification reply frame
6774 * @evHandlers: Pointer to integer, number of event handlers
6775 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006776 * Routes a received EventNotificationReply to all currently registered
6777 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006778 * Returns sum of event handlers return values.
6779 */
6780static int
6781ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6782{
6783 u16 evDataLen;
6784 u32 evData0 = 0;
6785// u32 evCtx;
6786 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306787 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006788 int r = 0;
6789 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006790 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006791 u8 event;
6792
6793 /*
6794 * Do platform normalization of values
6795 */
6796 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6797// evCtx = le32_to_cpu(pEventReply->EventContext);
6798 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6799 if (evDataLen) {
6800 evData0 = le32_to_cpu(pEventReply->Data[0]);
6801 }
6802
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006803 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306804 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006805 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006806 event,
6807 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006808
Prakash, Sathya436ace72007-07-24 15:42:08 +05306809#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006810 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6811 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006812 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306813 devtverboseprintk(ioc, printk(" %08x",
6814 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006815 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816#endif
6817
6818 /*
6819 * Do general / base driver event processing
6820 */
6821 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006822 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6823 if (evDataLen) {
6824 u8 evState = evData0 & 0xFF;
6825
6826 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6827
6828 /* Update EventState field in cached IocFacts */
6829 if (ioc->facts.Function) {
6830 ioc->facts.EventState = evState;
6831 }
6832 }
6833 break;
Moore, Ericece50912006-01-16 18:53:19 -07006834 case MPI_EVENT_INTEGRATED_RAID:
6835 mptbase_raid_process_event_data(ioc,
6836 (MpiEventDataRaid_t *)pEventReply->Data);
6837 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006838 default:
6839 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006840 }
6841
6842 /*
6843 * Should this event be logged? Events are written sequentially.
6844 * When buffer is full, start again at the top.
6845 */
6846 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6847 int idx;
6848
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006849 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850
6851 ioc->events[idx].event = event;
6852 ioc->events[idx].eventContext = ioc->eventContext;
6853
6854 for (ii = 0; ii < 2; ii++) {
6855 if (ii < evDataLen)
6856 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6857 else
6858 ioc->events[idx].data[ii] = 0;
6859 }
6860
6861 ioc->eventContext++;
6862 }
6863
6864
6865 /*
6866 * Call each currently registered protocol event handler.
6867 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006868 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306869 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306870 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306871 ioc->name, cb_idx));
6872 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006873 handlers++;
6874 }
6875 }
6876 /* FIXME? Examine results here? */
6877
6878 /*
6879 * If needed, send (a single) EventAck.
6880 */
6881 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306882 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006883 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006884 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306885 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006886 ioc->name, ii));
6887 }
6888 }
6889
6890 *evHandlers = handlers;
6891 return r;
6892}
6893
6894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006895/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006896 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6897 * @ioc: Pointer to MPT_ADAPTER structure
6898 * @log_info: U32 LogInfo reply word from the IOC
6899 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006900 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006901 */
6902static void
6903mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6904{
Eric Moore7c431e52007-06-13 16:34:36 -06006905 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006906
Eric Moore7c431e52007-06-13 16:34:36 -06006907 switch (log_info & 0xFF000000) {
6908 case MPI_IOCLOGINFO_FC_INIT_BASE:
6909 desc = "FCP Initiator";
6910 break;
6911 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6912 desc = "FCP Target";
6913 break;
6914 case MPI_IOCLOGINFO_FC_LAN_BASE:
6915 desc = "LAN";
6916 break;
6917 case MPI_IOCLOGINFO_FC_MSG_BASE:
6918 desc = "MPI Message Layer";
6919 break;
6920 case MPI_IOCLOGINFO_FC_LINK_BASE:
6921 desc = "FC Link";
6922 break;
6923 case MPI_IOCLOGINFO_FC_CTX_BASE:
6924 desc = "Context Manager";
6925 break;
6926 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6927 desc = "Invalid Field Offset";
6928 break;
6929 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6930 desc = "State Change Info";
6931 break;
6932 }
6933
6934 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6935 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006936}
6937
6938/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006939/**
Moore, Eric335a9412006-01-17 17:06:23 -07006940 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006941 * @ioc: Pointer to MPT_ADAPTER structure
6942 * @mr: Pointer to MPT reply frame
6943 * @log_info: U32 LogInfo word from the IOC
6944 *
6945 * Refer to lsi/sp_log.h.
6946 */
6947static void
Moore, Eric335a9412006-01-17 17:06:23 -07006948mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006949{
6950 u32 info = log_info & 0x00FF0000;
6951 char *desc = "unknown";
6952
6953 switch (info) {
6954 case 0x00010000:
6955 desc = "bug! MID not found";
6956 if (ioc->reload_fw == 0)
6957 ioc->reload_fw++;
6958 break;
6959
6960 case 0x00020000:
6961 desc = "Parity Error";
6962 break;
6963
6964 case 0x00030000:
6965 desc = "ASYNC Outbound Overrun";
6966 break;
6967
6968 case 0x00040000:
6969 desc = "SYNC Offset Error";
6970 break;
6971
6972 case 0x00050000:
6973 desc = "BM Change";
6974 break;
6975
6976 case 0x00060000:
6977 desc = "Msg In Overflow";
6978 break;
6979
6980 case 0x00070000:
6981 desc = "DMA Error";
6982 break;
6983
6984 case 0x00080000:
6985 desc = "Outbound DMA Overrun";
6986 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006987
Linus Torvalds1da177e2005-04-16 15:20:36 -07006988 case 0x00090000:
6989 desc = "Task Management";
6990 break;
6991
6992 case 0x000A0000:
6993 desc = "Device Problem";
6994 break;
6995
6996 case 0x000B0000:
6997 desc = "Invalid Phase Change";
6998 break;
6999
7000 case 0x000C0000:
7001 desc = "Untagged Table Size";
7002 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007003
Linus Torvalds1da177e2005-04-16 15:20:36 -07007004 }
7005
7006 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7007}
7008
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007009/* strings for sas loginfo */
7010 static char *originator_str[] = {
7011 "IOP", /* 00h */
7012 "PL", /* 01h */
7013 "IR" /* 02h */
7014 };
7015 static char *iop_code_str[] = {
7016 NULL, /* 00h */
7017 "Invalid SAS Address", /* 01h */
7018 NULL, /* 02h */
7019 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007020 "Diag Message Error", /* 04h */
7021 "Task Terminated", /* 05h */
7022 "Enclosure Management", /* 06h */
7023 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007024 };
7025 static char *pl_code_str[] = {
7026 NULL, /* 00h */
7027 "Open Failure", /* 01h */
7028 "Invalid Scatter Gather List", /* 02h */
7029 "Wrong Relative Offset or Frame Length", /* 03h */
7030 "Frame Transfer Error", /* 04h */
7031 "Transmit Frame Connected Low", /* 05h */
7032 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7033 "SATA Read Log Receive Data Error", /* 07h */
7034 "SATA NCQ Fail All Commands After Error", /* 08h */
7035 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7036 "Receive Frame Invalid Message", /* 0Ah */
7037 "Receive Context Message Valid Error", /* 0Bh */
7038 "Receive Frame Current Frame Error", /* 0Ch */
7039 "SATA Link Down", /* 0Dh */
7040 "Discovery SATA Init W IOS", /* 0Eh */
7041 "Config Invalid Page", /* 0Fh */
7042 "Discovery SATA Init Timeout", /* 10h */
7043 "Reset", /* 11h */
7044 "Abort", /* 12h */
7045 "IO Not Yet Executed", /* 13h */
7046 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007047 "Persistent Reservation Out Not Affiliation "
7048 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007049 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007050 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007051 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007052 NULL, /* 19h */
7053 NULL, /* 1Ah */
7054 NULL, /* 1Bh */
7055 NULL, /* 1Ch */
7056 NULL, /* 1Dh */
7057 NULL, /* 1Eh */
7058 NULL, /* 1Fh */
7059 "Enclosure Management" /* 20h */
7060 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007061 static char *ir_code_str[] = {
7062 "Raid Action Error", /* 00h */
7063 NULL, /* 00h */
7064 NULL, /* 01h */
7065 NULL, /* 02h */
7066 NULL, /* 03h */
7067 NULL, /* 04h */
7068 NULL, /* 05h */
7069 NULL, /* 06h */
7070 NULL /* 07h */
7071 };
7072 static char *raid_sub_code_str[] = {
7073 NULL, /* 00h */
7074 "Volume Creation Failed: Data Passed too "
7075 "Large", /* 01h */
7076 "Volume Creation Failed: Duplicate Volumes "
7077 "Attempted", /* 02h */
7078 "Volume Creation Failed: Max Number "
7079 "Supported Volumes Exceeded", /* 03h */
7080 "Volume Creation Failed: DMA Error", /* 04h */
7081 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7082 "Volume Creation Failed: Error Reading "
7083 "MFG Page 4", /* 06h */
7084 "Volume Creation Failed: Creating Internal "
7085 "Structures", /* 07h */
7086 NULL, /* 08h */
7087 NULL, /* 09h */
7088 NULL, /* 0Ah */
7089 NULL, /* 0Bh */
7090 NULL, /* 0Ch */
7091 NULL, /* 0Dh */
7092 NULL, /* 0Eh */
7093 NULL, /* 0Fh */
7094 "Activation failed: Already Active Volume", /* 10h */
7095 "Activation failed: Unsupported Volume Type", /* 11h */
7096 "Activation failed: Too Many Active Volumes", /* 12h */
7097 "Activation failed: Volume ID in Use", /* 13h */
7098 "Activation failed: Reported Failure", /* 14h */
7099 "Activation failed: Importing a Volume", /* 15h */
7100 NULL, /* 16h */
7101 NULL, /* 17h */
7102 NULL, /* 18h */
7103 NULL, /* 19h */
7104 NULL, /* 1Ah */
7105 NULL, /* 1Bh */
7106 NULL, /* 1Ch */
7107 NULL, /* 1Dh */
7108 NULL, /* 1Eh */
7109 NULL, /* 1Fh */
7110 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7111 "Phys Disk failed: Data Passed too Large", /* 21h */
7112 "Phys Disk failed: DMA Error", /* 22h */
7113 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7114 "Phys Disk failed: Creating Phys Disk Config "
7115 "Page", /* 24h */
7116 NULL, /* 25h */
7117 NULL, /* 26h */
7118 NULL, /* 27h */
7119 NULL, /* 28h */
7120 NULL, /* 29h */
7121 NULL, /* 2Ah */
7122 NULL, /* 2Bh */
7123 NULL, /* 2Ch */
7124 NULL, /* 2Dh */
7125 NULL, /* 2Eh */
7126 NULL, /* 2Fh */
7127 "Compatibility Error: IR Disabled", /* 30h */
7128 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7129 "Compatibility Error: Device not Direct Access "
7130 "Device ", /* 32h */
7131 "Compatibility Error: Removable Device Found", /* 33h */
7132 "Compatibility Error: Device SCSI Version not "
7133 "2 or Higher", /* 34h */
7134 "Compatibility Error: SATA Device, 48 BIT LBA "
7135 "not Supported", /* 35h */
7136 "Compatibility Error: Device doesn't have "
7137 "512 Byte Block Sizes", /* 36h */
7138 "Compatibility Error: Volume Type Check Failed", /* 37h */
7139 "Compatibility Error: Volume Type is "
7140 "Unsupported by FW", /* 38h */
7141 "Compatibility Error: Disk Drive too Small for "
7142 "use in Volume", /* 39h */
7143 "Compatibility Error: Phys Disk for Create "
7144 "Volume not Found", /* 3Ah */
7145 "Compatibility Error: Too Many or too Few "
7146 "Disks for Volume Type", /* 3Bh */
7147 "Compatibility Error: Disk stripe Sizes "
7148 "Must be 64KB", /* 3Ch */
7149 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7150 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007151
7152/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007153/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007154 * mpt_sas_log_info - Log information returned from SAS IOC.
7155 * @ioc: Pointer to MPT_ADAPTER structure
7156 * @log_info: U32 LogInfo reply word from the IOC
7157 *
7158 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007159 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007160static void
7161mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7162{
7163union loginfo_type {
7164 u32 loginfo;
7165 struct {
7166 u32 subcode:16;
7167 u32 code:8;
7168 u32 originator:4;
7169 u32 bus_type:4;
7170 }dw;
7171};
7172 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007173 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007174 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007175 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007176
7177 sas_loginfo.loginfo = log_info;
7178 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
7179 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
7180 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007181
7182 originator_desc = originator_str[sas_loginfo.dw.originator];
7183
7184 switch (sas_loginfo.dw.originator) {
7185
7186 case 0: /* IOP */
7187 if (sas_loginfo.dw.code <
7188 sizeof(iop_code_str)/sizeof(char*))
7189 code_desc = iop_code_str[sas_loginfo.dw.code];
7190 break;
7191 case 1: /* PL */
7192 if (sas_loginfo.dw.code <
7193 sizeof(pl_code_str)/sizeof(char*))
7194 code_desc = pl_code_str[sas_loginfo.dw.code];
7195 break;
7196 case 2: /* IR */
7197 if (sas_loginfo.dw.code >=
7198 sizeof(ir_code_str)/sizeof(char*))
7199 break;
7200 code_desc = ir_code_str[sas_loginfo.dw.code];
7201 if (sas_loginfo.dw.subcode >=
7202 sizeof(raid_sub_code_str)/sizeof(char*))
7203 break;
7204 if (sas_loginfo.dw.code == 0)
7205 sub_code_desc =
7206 raid_sub_code_str[sas_loginfo.dw.subcode];
7207 break;
7208 default:
7209 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007210 }
7211
Eric Moorec6c727a2007-01-29 09:44:54 -07007212 if (sub_code_desc != NULL)
7213 printk(MYIOC_s_INFO_FMT
7214 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7215 " SubCode={%s}\n",
7216 ioc->name, log_info, originator_desc, code_desc,
7217 sub_code_desc);
7218 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007219 printk(MYIOC_s_INFO_FMT
7220 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7221 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007222 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007223 sas_loginfo.dw.subcode);
7224 else
7225 printk(MYIOC_s_INFO_FMT
7226 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7227 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007228 ioc->name, log_info, originator_desc,
7229 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007230}
7231
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007233/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007234 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7235 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007236 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007237 * @mf: Pointer to MPT request frame
7238 *
7239 * Refer to lsi/mpi.h.
7240 **/
7241static void
7242mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7243{
7244 Config_t *pReq = (Config_t *)mf;
7245 char extend_desc[EVENT_DESCR_STR_SZ];
7246 char *desc = NULL;
7247 u32 form;
7248 u8 page_type;
7249
7250 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7251 page_type = pReq->ExtPageType;
7252 else
7253 page_type = pReq->Header.PageType;
7254
7255 /*
7256 * ignore invalid page messages for GET_NEXT_HANDLE
7257 */
7258 form = le32_to_cpu(pReq->PageAddress);
7259 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7260 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7261 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7262 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7263 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7264 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7265 return;
7266 }
7267 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7268 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7269 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7270 return;
7271 }
7272
7273 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7274 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7275 page_type, pReq->Header.PageNumber, pReq->Action, form);
7276
7277 switch (ioc_status) {
7278
7279 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7280 desc = "Config Page Invalid Action";
7281 break;
7282
7283 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7284 desc = "Config Page Invalid Type";
7285 break;
7286
7287 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7288 desc = "Config Page Invalid Page";
7289 break;
7290
7291 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7292 desc = "Config Page Invalid Data";
7293 break;
7294
7295 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7296 desc = "Config Page No Defaults";
7297 break;
7298
7299 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7300 desc = "Config Page Can't Commit";
7301 break;
7302 }
7303
7304 if (!desc)
7305 return;
7306
Eric Moore29dd3602007-09-14 18:46:51 -06007307 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7308 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007309}
7310
7311/**
7312 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007313 * @ioc: Pointer to MPT_ADAPTER structure
7314 * @ioc_status: U32 IOCStatus word from IOC
7315 * @mf: Pointer to MPT request frame
7316 *
7317 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007318 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007319static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007320mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007321{
7322 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007323 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007324
7325 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007326
7327/****************************************************************************/
7328/* Common IOCStatus values for all replies */
7329/****************************************************************************/
7330
Linus Torvalds1da177e2005-04-16 15:20:36 -07007331 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7332 desc = "Invalid Function";
7333 break;
7334
7335 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7336 desc = "Busy";
7337 break;
7338
7339 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7340 desc = "Invalid SGL";
7341 break;
7342
7343 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7344 desc = "Internal Error";
7345 break;
7346
7347 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7348 desc = "Reserved";
7349 break;
7350
7351 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7352 desc = "Insufficient Resources";
7353 break;
7354
7355 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7356 desc = "Invalid Field";
7357 break;
7358
7359 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7360 desc = "Invalid State";
7361 break;
7362
Eric Moorec6c727a2007-01-29 09:44:54 -07007363/****************************************************************************/
7364/* Config IOCStatus values */
7365/****************************************************************************/
7366
Linus Torvalds1da177e2005-04-16 15:20:36 -07007367 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7368 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7369 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7370 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7371 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7372 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007373 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007374 break;
7375
Eric Moorec6c727a2007-01-29 09:44:54 -07007376/****************************************************************************/
7377/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7378/* */
7379/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7380/* */
7381/****************************************************************************/
7382
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007384 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007385 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7386 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7387 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7388 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007389 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007390 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007391 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007392 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007394 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007395 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007396 break;
7397
Eric Moorec6c727a2007-01-29 09:44:54 -07007398/****************************************************************************/
7399/* SCSI Target values */
7400/****************************************************************************/
7401
7402 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7403 desc = "Target: Priority IO";
7404 break;
7405
7406 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7407 desc = "Target: Invalid Port";
7408 break;
7409
7410 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7411 desc = "Target Invalid IO Index:";
7412 break;
7413
7414 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7415 desc = "Target: Aborted";
7416 break;
7417
7418 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7419 desc = "Target: No Conn Retryable";
7420 break;
7421
7422 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7423 desc = "Target: No Connection";
7424 break;
7425
7426 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7427 desc = "Target: Transfer Count Mismatch";
7428 break;
7429
7430 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7431 desc = "Target: STS Data not Sent";
7432 break;
7433
7434 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7435 desc = "Target: Data Offset Error";
7436 break;
7437
7438 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7439 desc = "Target: Too Much Write Data";
7440 break;
7441
7442 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7443 desc = "Target: IU Too Short";
7444 break;
7445
7446 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7447 desc = "Target: ACK NAK Timeout";
7448 break;
7449
7450 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7451 desc = "Target: Nak Received";
7452 break;
7453
7454/****************************************************************************/
7455/* Fibre Channel Direct Access values */
7456/****************************************************************************/
7457
7458 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7459 desc = "FC: Aborted";
7460 break;
7461
7462 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7463 desc = "FC: RX ID Invalid";
7464 break;
7465
7466 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7467 desc = "FC: DID Invalid";
7468 break;
7469
7470 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7471 desc = "FC: Node Logged Out";
7472 break;
7473
7474 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7475 desc = "FC: Exchange Canceled";
7476 break;
7477
7478/****************************************************************************/
7479/* LAN values */
7480/****************************************************************************/
7481
7482 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7483 desc = "LAN: Device not Found";
7484 break;
7485
7486 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7487 desc = "LAN: Device Failure";
7488 break;
7489
7490 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7491 desc = "LAN: Transmit Error";
7492 break;
7493
7494 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7495 desc = "LAN: Transmit Aborted";
7496 break;
7497
7498 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7499 desc = "LAN: Receive Error";
7500 break;
7501
7502 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7503 desc = "LAN: Receive Aborted";
7504 break;
7505
7506 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7507 desc = "LAN: Partial Packet";
7508 break;
7509
7510 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7511 desc = "LAN: Canceled";
7512 break;
7513
7514/****************************************************************************/
7515/* Serial Attached SCSI values */
7516/****************************************************************************/
7517
7518 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7519 desc = "SAS: SMP Request Failed";
7520 break;
7521
7522 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7523 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007524 break;
7525
7526 default:
7527 desc = "Others";
7528 break;
7529 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007530
7531 if (!desc)
7532 return;
7533
Eric Moore29dd3602007-09-14 18:46:51 -06007534 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7535 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007536}
7537
7538/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007539EXPORT_SYMBOL(mpt_attach);
7540EXPORT_SYMBOL(mpt_detach);
7541#ifdef CONFIG_PM
7542EXPORT_SYMBOL(mpt_resume);
7543EXPORT_SYMBOL(mpt_suspend);
7544#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007545EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007546EXPORT_SYMBOL(mpt_register);
7547EXPORT_SYMBOL(mpt_deregister);
7548EXPORT_SYMBOL(mpt_event_register);
7549EXPORT_SYMBOL(mpt_event_deregister);
7550EXPORT_SYMBOL(mpt_reset_register);
7551EXPORT_SYMBOL(mpt_reset_deregister);
7552EXPORT_SYMBOL(mpt_device_driver_register);
7553EXPORT_SYMBOL(mpt_device_driver_deregister);
7554EXPORT_SYMBOL(mpt_get_msg_frame);
7555EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307556EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007557EXPORT_SYMBOL(mpt_free_msg_frame);
7558EXPORT_SYMBOL(mpt_add_sge);
7559EXPORT_SYMBOL(mpt_send_handshake_request);
7560EXPORT_SYMBOL(mpt_verify_adapter);
7561EXPORT_SYMBOL(mpt_GetIocState);
7562EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007563EXPORT_SYMBOL(mpt_HardResetHandler);
7564EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007565EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007566EXPORT_SYMBOL(mpt_alloc_fw_memory);
7567EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007568EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007569EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007570
Linus Torvalds1da177e2005-04-16 15:20:36 -07007571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007572/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007573 * fusion_init - Fusion MPT base driver initialization routine.
7574 *
7575 * Returns 0 for success, non-zero for failure.
7576 */
7577static int __init
7578fusion_init(void)
7579{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307580 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007581
7582 show_mptmod_ver(my_NAME, my_VERSION);
7583 printk(KERN_INFO COPYRIGHT "\n");
7584
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307585 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7586 MptCallbacks[cb_idx] = NULL;
7587 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7588 MptEvHandlers[cb_idx] = NULL;
7589 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007590 }
7591
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007592 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007593 * EventNotification handling.
7594 */
7595 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7596
7597 /* Register for hard reset handling callbacks.
7598 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307599 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007600
7601#ifdef CONFIG_PROC_FS
7602 (void) procmpt_create();
7603#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007604 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605}
7606
7607/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007608/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007609 * fusion_exit - Perform driver unload cleanup.
7610 *
7611 * This routine frees all resources associated with each MPT adapter
7612 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7613 */
7614static void __exit
7615fusion_exit(void)
7616{
7617
Linus Torvalds1da177e2005-04-16 15:20:36 -07007618 mpt_reset_deregister(mpt_base_index);
7619
7620#ifdef CONFIG_PROC_FS
7621 procmpt_destroy();
7622#endif
7623}
7624
Linus Torvalds1da177e2005-04-16 15:20:36 -07007625module_init(fusion_init);
7626module_exit(fusion_exit);