blob: 9bc35617b8719beb84b8acf542fd79754c4eca98 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05308 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Prakash, Sathya23a274c2008-03-07 15:53:21 +053082static int mpt_msi_enable = -1;
Christoph Hellwig4ddce142006-01-17 13:44:29 +000083module_param(mpt_msi_enable, int, 0);
84MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086static int mpt_channel_mapping;
87module_param(mpt_channel_mapping, int, 0);
88MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
89
Prakash, Sathya436ace72007-07-24 15:42:08 +053090static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -040091static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
92module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
93 &mpt_debug_level, 0600);
Prakash, Sathya436ace72007-07-24 15:42:08 +053094MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifdef MFCNT
97static int mfcounter = 0;
98#define PRINT_MF_COUNT 20000
99#endif
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Public data...
104 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Adrian Bunk15424922008-04-22 00:31:51 +0300106static struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108#define WHOINIT_UNKNOWN 0xAA
109
110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
111/*
112 * Private data...
113 */
114 /* Adapter link list */
115LIST_HEAD(ioc_list);
116 /* Callback lookup table */
117static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
118 /* Protocol driver class lookup table */
119static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
120 /* Event handler lookup table */
121static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
122 /* Reset handler lookup table */
123static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
124static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
127
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530128/*
129 * Driver Callback Index's
130 */
131static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
132static u8 last_drv_idx;
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
135/*
136 * Forward protos...
137 */
David Howells7d12e782006-10-05 14:55:46 +0100138static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
140static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
141 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
142 int sleepFlag);
143static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
144static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
145static void mpt_adapter_disable(MPT_ADAPTER *ioc);
146static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
147
148static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
149static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
151static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
152static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
153static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
154static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200155static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
157static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
158static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
159static int PrimeIocFifos(MPT_ADAPTER *ioc);
160static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
161static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
162static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
163static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200165int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
167static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
168static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
169static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
170static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530171static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
173static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200174static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
175static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177#ifdef CONFIG_PROC_FS
178static int procmpt_summary_read(char *buf, char **start, off_t offset,
179 int request, int *eof, void *data);
180static int procmpt_version_read(char *buf, char **start, off_t offset,
181 int request, int *eof, void *data);
182static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
183 int request, int *eof, void *data);
184#endif
185static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
186
187//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
188static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700189static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700191static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600192static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700193static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700194static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int __init fusion_init (void);
198static void __exit fusion_exit (void);
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define CHIPREG_READ32(addr) readl_relaxed(addr)
201#define CHIPREG_READ32_dmasync(addr) readl(addr)
202#define CHIPREG_WRITE32(addr,val) writel(val, addr)
203#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
204#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
205
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600206static void
207pci_disable_io_access(struct pci_dev *pdev)
208{
209 u16 command_reg;
210
211 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
212 command_reg &= ~1;
213 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
214}
215
216static void
217pci_enable_io_access(struct pci_dev *pdev)
218{
219 u16 command_reg;
220
221 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
222 command_reg |= 1;
223 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
224}
225
James Bottomleydb47c2d2007-07-28 13:40:21 -0400226static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
227{
228 int ret = param_set_int(val, kp);
229 MPT_ADAPTER *ioc;
230
231 if (ret)
232 return ret;
233
234 list_for_each_entry(ioc, &ioc_list, list)
235 ioc->debug_level = mpt_debug_level;
236 return 0;
237}
238
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530239/**
240 * mpt_get_cb_idx - obtain cb_idx for registered driver
241 * @dclass: class driver enum
242 *
243 * Returns cb_idx, or zero means it wasn't found
244 **/
245static u8
246mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
247{
248 u8 cb_idx;
249
250 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
251 if (MptDriverClass[cb_idx] == dclass)
252 return cb_idx;
253 return 0;
254}
255
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530256/**
257 * mpt_fault_reset_work - work performed on workq after ioc fault
258 * @work: input argument, used to derive ioc
259 *
260**/
261static void
262mpt_fault_reset_work(struct work_struct *work)
263{
264 MPT_ADAPTER *ioc =
265 container_of(work, MPT_ADAPTER, fault_reset_work.work);
266 u32 ioc_raw_state;
267 int rc;
268 unsigned long flags;
269
270 if (ioc->diagPending || !ioc->active)
271 goto out;
272
273 ioc_raw_state = mpt_GetIocState(ioc, 0);
274 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
275 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
276 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
277 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
278 ioc->name, __FUNCTION__);
279 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
280 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
281 __FUNCTION__, (rc == 0) ? "success" : "failed");
282 ioc_raw_state = mpt_GetIocState(ioc, 0);
283 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
284 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
285 "reset (%04xh)\n", ioc->name, ioc_raw_state &
286 MPI_DOORBELL_DATA_MASK);
287 }
288
289 out:
290 /*
291 * Take turns polling alternate controller
292 */
293 if (ioc->alt_ioc)
294 ioc = ioc->alt_ioc;
295
296 /* rearm the timer */
297 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
298 if (ioc->reset_work_q)
299 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
300 msecs_to_jiffies(MPT_POLLING_INTERVAL));
301 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
302}
303
304
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600305/*
306 * Process turbo (context) reply...
307 */
308static void
309mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
310{
311 MPT_FRAME_HDR *mf = NULL;
312 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530313 u16 req_idx = 0;
314 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600315
Prakash, Sathya436ace72007-07-24 15:42:08 +0530316 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600317 ioc->name, pa));
318
319 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
320 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
321 req_idx = pa & 0x0000FFFF;
322 cb_idx = (pa & 0x00FF0000) >> 16;
323 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
324 break;
325 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530326 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600327 /*
328 * Blind set of mf to NULL here was fatal
329 * after lan_reply says "freeme"
330 * Fix sort of combined with an optimization here;
331 * added explicit check for case where lan_reply
332 * was just returning 1 and doing nothing else.
333 * For this case skip the callback, but set up
334 * proper mf value first here:-)
335 */
336 if ((pa & 0x58000000) == 0x58000000) {
337 req_idx = pa & 0x0000FFFF;
338 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
339 mpt_free_msg_frame(ioc, mf);
340 mb();
341 return;
342 break;
343 }
344 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
345 break;
346 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530347 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600348 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
349 break;
350 default:
351 cb_idx = 0;
352 BUG();
353 }
354
355 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530356 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600357 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600358 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
359 __FUNCTION__, ioc->name, cb_idx);
360 goto out;
361 }
362
363 if (MptCallbacks[cb_idx](ioc, mf, mr))
364 mpt_free_msg_frame(ioc, mf);
365 out:
366 mb();
367}
368
369static void
370mpt_reply(MPT_ADAPTER *ioc, u32 pa)
371{
372 MPT_FRAME_HDR *mf;
373 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530374 u16 req_idx;
375 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600376 int freeme;
377
378 u32 reply_dma_low;
379 u16 ioc_stat;
380
381 /* non-TURBO reply! Hmmm, something may be up...
382 * Newest turbo reply mechanism; get address
383 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
384 */
385
386 /* Map DMA address of reply header to cpu address.
387 * pa is 32 bits - but the dma address may be 32 or 64 bits
388 * get offset based only only the low addresses
389 */
390
391 reply_dma_low = (pa <<= 1);
392 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
393 (reply_dma_low - ioc->reply_frames_low_dma));
394
395 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
396 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
397 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
398
Prakash, Sathya436ace72007-07-24 15:42:08 +0530399 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600400 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600401 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600402
403 /* Check/log IOC log info
404 */
405 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
406 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
407 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
408 if (ioc->bus_type == FC)
409 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700410 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700411 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600412 else if (ioc->bus_type == SAS)
413 mpt_sas_log_info(ioc, log_info);
414 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600415
Eric Moorec6c727a2007-01-29 09:44:54 -0700416 if (ioc_stat & MPI_IOCSTATUS_MASK)
417 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600418
419 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530420 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600421 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600422 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
423 __FUNCTION__, ioc->name, cb_idx);
424 freeme = 0;
425 goto out;
426 }
427
428 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
429
430 out:
431 /* Flush (non-TURBO) reply with a WRITE! */
432 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
433
434 if (freeme)
435 mpt_free_msg_frame(ioc, mf);
436 mb();
437}
438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800440/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
442 * @irq: irq number (not used)
443 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 *
445 * This routine is registered via the request_irq() kernel API call,
446 * and handles all interrupts generated from a specific MPT adapter
447 * (also referred to as a IO Controller or IOC).
448 * This routine must clear the interrupt from the adapter and does
449 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200450 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 *
452 * This routine handles register-level access of the adapter but
453 * dispatches (calls) a protocol-specific callback routine to handle
454 * the protocol-specific details of the MPT request completion.
455 */
456static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100457mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600459 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600460 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
461
462 if (pa == 0xFFFFFFFF)
463 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 /*
466 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600468 do {
469 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600470 mpt_reply(ioc, pa);
471 else
472 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600473 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
474 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
476 return IRQ_HANDLED;
477}
478
479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800480/**
481 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 * @ioc: Pointer to MPT_ADAPTER structure
483 * @mf: Pointer to original MPT request frame
484 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
485 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800486 * MPT base driver's callback routine; all base driver
487 * "internal" request/reply processing is routed here.
488 * Currently used for EventNotification and EventAck handling.
489 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200490 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 * should be freed, or 0 if it shouldn't.
492 */
493static int
494mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
495{
496 int freereq = 1;
497 u8 func;
498
Prakash, Sathya436ace72007-07-24 15:42:08 +0530499 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
500#ifdef CONFIG_FUSION_LOGGING
501 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
502 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600503 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
504 ioc->name, mf));
505 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200507#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530510 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 ioc->name, func));
512
513 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
514 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
515 int evHandlers = 0;
516 int results;
517
518 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
519 if (results != evHandlers) {
520 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530521 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 ioc->name, evHandlers, results));
523 }
524
525 /*
526 * Hmmm... It seems that EventNotificationReply is an exception
527 * to the rule of one reply per request.
528 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200529 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200531 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530532 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200533 ioc->name, pEvReply));
534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536#ifdef CONFIG_PROC_FS
537// LogEvent(ioc, pEvReply);
538#endif
539
540 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530541 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700543 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 CONFIGPARMS *pCfg;
545 unsigned long flags;
546
Prakash, Sathya436ace72007-07-24 15:42:08 +0530547 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 ioc->name, mf, reply));
549
550 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
551
552 if (pCfg) {
553 /* disable timer and remove from linked list */
554 del_timer(&pCfg->timer);
555
556 spin_lock_irqsave(&ioc->FreeQlock, flags);
557 list_del(&pCfg->linkage);
558 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
559
560 /*
561 * If IOC Status is SUCCESS, save the header
562 * and set the status code to GOOD.
563 */
564 pCfg->status = MPT_CONFIG_ERROR;
565 if (reply) {
566 ConfigReply_t *pReply = (ConfigReply_t *)reply;
567 u16 status;
568
569 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600570 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
571 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
573 pCfg->status = status;
574 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200575 if ((pReply->Header.PageType &
576 MPI_CONFIG_PAGETYPE_MASK) ==
577 MPI_CONFIG_PAGETYPE_EXTENDED) {
578 pCfg->cfghdr.ehdr->ExtPageLength =
579 le16_to_cpu(pReply->ExtPageLength);
580 pCfg->cfghdr.ehdr->ExtPageType =
581 pReply->ExtPageType;
582 }
583 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
584
585 /* If this is a regular header, save PageLength. */
586 /* LMP Do this better so not using a reserved field! */
587 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
588 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
589 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
591 }
592
593 /*
594 * Wake up the original calling thread
595 */
596 pCfg->wait_done = 1;
597 wake_up(&mpt_waitq);
598 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200599 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
600 /* we should be always getting a reply frame */
601 memcpy(ioc->persist_reply_frame, reply,
602 min(MPT_DEFAULT_FRAME_SIZE,
603 4*reply->u.reply.MsgLength));
604 del_timer(&ioc->persist_timer);
605 ioc->persist_wait_done = 1;
606 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 } else {
608 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
609 ioc->name, func);
610 }
611
612 /*
613 * Conditionally tell caller to free the original
614 * EventNotification/EventAck/unexpected request frame!
615 */
616 return freereq;
617}
618
619/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
620/**
621 * mpt_register - Register protocol-specific main callback handler.
622 * @cbfunc: callback function pointer
623 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
624 *
625 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800626 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 * protocol-specific driver must do this before it will be able to
628 * use any IOC resources, such as obtaining request frames.
629 *
630 * NOTES: The SCSI protocol driver currently calls this routine thrice
631 * in order to register separate callbacks; one for "normal" SCSI IO;
632 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
633 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530634 * Returns u8 valued "handle" in the range (and S.O.D. order)
635 * {N,...,7,6,5,...,1} if successful.
636 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
637 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530639u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
641{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530642 u8 cb_idx;
643 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
645 /*
646 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
647 * (slot/handle 0 is reserved!)
648 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530649 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
650 if (MptCallbacks[cb_idx] == NULL) {
651 MptCallbacks[cb_idx] = cbfunc;
652 MptDriverClass[cb_idx] = dclass;
653 MptEvHandlers[cb_idx] = NULL;
654 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 break;
656 }
657 }
658
659 return last_drv_idx;
660}
661
662/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
663/**
664 * mpt_deregister - Deregister a protocol drivers resources.
665 * @cb_idx: previously registered callback handle
666 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800667 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 * module is unloaded.
669 */
670void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530671mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600673 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 MptCallbacks[cb_idx] = NULL;
675 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
676 MptEvHandlers[cb_idx] = NULL;
677
678 last_drv_idx++;
679 }
680}
681
682/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
683/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800684 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 * @cb_idx: previously registered (via mpt_register) callback handle
686 * @ev_cbfunc: callback function
687 *
688 * This routine can be called by one or more protocol-specific drivers
689 * if/when they choose to be notified of MPT events.
690 *
691 * Returns 0 for success.
692 */
693int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530694mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600696 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return -1;
698
699 MptEvHandlers[cb_idx] = ev_cbfunc;
700 return 0;
701}
702
703/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
704/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800705 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 * @cb_idx: previously registered callback handle
707 *
708 * Each protocol-specific driver should call this routine
709 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800710 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 */
712void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530713mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600715 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 return;
717
718 MptEvHandlers[cb_idx] = NULL;
719}
720
721/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
722/**
723 * mpt_reset_register - Register protocol-specific IOC reset handler.
724 * @cb_idx: previously registered (via mpt_register) callback handle
725 * @reset_func: reset function
726 *
727 * This routine can be called by one or more protocol-specific drivers
728 * if/when they choose to be notified of IOC resets.
729 *
730 * Returns 0 for success.
731 */
732int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530733mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530735 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return -1;
737
738 MptResetHandlers[cb_idx] = reset_func;
739 return 0;
740}
741
742/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
743/**
744 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
745 * @cb_idx: previously registered callback handle
746 *
747 * Each protocol-specific driver should call this routine
748 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800749 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 */
751void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530752mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530754 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return;
756
757 MptResetHandlers[cb_idx] = NULL;
758}
759
760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
761/**
762 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800763 * @dd_cbfunc: driver callbacks struct
764 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 */
766int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530767mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
769 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600770 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Eric Moore8d6d83e2007-09-14 18:47:40 -0600772 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400773 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
775 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
776
777 /* call per pci device probe entry point */
778 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600779 id = ioc->pcidev->driver ?
780 ioc->pcidev->driver->id_table : NULL;
781 if (dd_cbfunc->probe)
782 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
784
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400785 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786}
787
788/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
789/**
790 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800791 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 */
793void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530794mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
796 struct mpt_pci_driver *dd_cbfunc;
797 MPT_ADAPTER *ioc;
798
Eric Moore8d6d83e2007-09-14 18:47:40 -0600799 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return;
801
802 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
803
804 list_for_each_entry(ioc, &ioc_list, list) {
805 if (dd_cbfunc->remove)
806 dd_cbfunc->remove(ioc->pcidev);
807 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 MptDeviceDriverHandlers[cb_idx] = NULL;
810}
811
812
813/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
814/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800815 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530816 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 * @ioc: Pointer to MPT adapter structure
818 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800819 * Obtain an MPT request frame from the pool (of 1024) that are
820 * allocated per MPT adapter.
821 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 * Returns pointer to a MPT request frame or %NULL if none are available
823 * or IOC is not active.
824 */
825MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530826mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 MPT_FRAME_HDR *mf;
829 unsigned long flags;
830 u16 req_idx; /* Request index */
831
832 /* validate handle and ioc identifier */
833
834#ifdef MFCNT
835 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600836 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
837 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838#endif
839
840 /* If interrupts are not attached, do not return a request frame */
841 if (!ioc->active)
842 return NULL;
843
844 spin_lock_irqsave(&ioc->FreeQlock, flags);
845 if (!list_empty(&ioc->FreeQ)) {
846 int req_offset;
847
848 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
849 u.frame.linkage.list);
850 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200851 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530852 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
854 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500855 req_idx = req_offset / ioc->req_sz;
856 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600858 /* Default, will be changed if necessary in SG generation */
859 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860#ifdef MFCNT
861 ioc->mfcnt++;
862#endif
863 }
864 else
865 mf = NULL;
866 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
867
868#ifdef MFCNT
869 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600870 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
871 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
872 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 mfcounter++;
874 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600875 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
876 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877#endif
878
Eric Moore29dd3602007-09-14 18:46:51 -0600879 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
880 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 return mf;
882}
883
884/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
885/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800886 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530887 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 * @ioc: Pointer to MPT adapter structure
889 * @mf: Pointer to MPT request frame
890 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800891 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 * specific MPT adapter.
893 */
894void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530895mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
897 u32 mf_dma_addr;
898 int req_offset;
899 u16 req_idx; /* Request index */
900
901 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530902 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
904 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500905 req_idx = req_offset / ioc->req_sz;
906 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
908
Prakash, Sathya436ace72007-07-24 15:42:08 +0530909 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200911 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600912 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
913 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
914 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
916}
917
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530918/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800919 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530920 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530921 * @ioc: Pointer to MPT adapter structure
922 * @mf: Pointer to MPT request frame
923 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800924 * Send a protocol-specific MPT request frame to an IOC using
925 * hi-priority request queue.
926 *
927 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530928 * specific MPT adapter.
929 **/
930void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530931mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530932{
933 u32 mf_dma_addr;
934 int req_offset;
935 u16 req_idx; /* Request index */
936
937 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530938 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530939 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
940 req_idx = req_offset / ioc->req_sz;
941 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
942 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
943
944 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
945
946 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
947 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
948 ioc->name, mf_dma_addr, req_idx));
949 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
950}
951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
953/**
954 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
955 * @handle: Handle of registered MPT protocol driver
956 * @ioc: Pointer to MPT adapter structure
957 * @mf: Pointer to MPT request frame
958 *
959 * This routine places a MPT request frame back on the MPT adapter's
960 * FreeQ.
961 */
962void
963mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
964{
965 unsigned long flags;
966
967 /* Put Request back on FreeQ! */
968 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200969 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
971#ifdef MFCNT
972 ioc->mfcnt--;
973#endif
974 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
975}
976
977/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
978/**
979 * mpt_add_sge - Place a simple SGE at address pAddr.
980 * @pAddr: virtual address for SGE
981 * @flagslength: SGE flags and data transfer length
982 * @dma_addr: Physical address
983 *
984 * This routine places a MPT request frame back on the MPT adapter's
985 * FreeQ.
986 */
987void
988mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
989{
990 if (sizeof(dma_addr_t) == sizeof(u64)) {
991 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
992 u32 tmp = dma_addr & 0xFFFFFFFF;
993
994 pSge->FlagsLength = cpu_to_le32(flagslength);
995 pSge->Address.Low = cpu_to_le32(tmp);
996 tmp = (u32) ((u64)dma_addr >> 32);
997 pSge->Address.High = cpu_to_le32(tmp);
998
999 } else {
1000 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1001 pSge->FlagsLength = cpu_to_le32(flagslength);
1002 pSge->Address = cpu_to_le32(dma_addr);
1003 }
1004}
1005
1006/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1007/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001008 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301009 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 * @ioc: Pointer to MPT adapter structure
1011 * @reqBytes: Size of the request in bytes
1012 * @req: Pointer to MPT request frame
1013 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1014 *
1015 * This routine is used exclusively to send MptScsiTaskMgmt
1016 * requests since they are required to be sent via doorbell handshake.
1017 *
1018 * NOTE: It is the callers responsibility to byte-swap fields in the
1019 * request which are greater than 1 byte in size.
1020 *
1021 * Returns 0 for success, non-zero for failure.
1022 */
1023int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301024mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025{
Eric Moorecd2c6192007-01-29 09:47:47 -07001026 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 u8 *req_as_bytes;
1028 int ii;
1029
1030 /* State is known to be good upon entering
1031 * this function so issue the bus reset
1032 * request.
1033 */
1034
1035 /*
1036 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1037 * setting cb_idx/req_idx. But ONLY if this request
1038 * is in proper (pre-alloc'd) request buffer range...
1039 */
1040 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1041 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1042 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1043 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301044 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 }
1046
1047 /* Make sure there are no doorbells */
1048 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1051 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1052 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1053
1054 /* Wait for IOC doorbell int */
1055 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1056 return ii;
1057 }
1058
1059 /* Read doorbell and check for active bit */
1060 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1061 return -5;
1062
Eric Moore29dd3602007-09-14 18:46:51 -06001063 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001064 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1067
1068 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1069 return -2;
1070 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 /* Send request via doorbell handshake */
1073 req_as_bytes = (u8 *) req;
1074 for (ii = 0; ii < reqBytes/4; ii++) {
1075 u32 word;
1076
1077 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1078 (req_as_bytes[(ii*4) + 1] << 8) |
1079 (req_as_bytes[(ii*4) + 2] << 16) |
1080 (req_as_bytes[(ii*4) + 3] << 24));
1081 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1082 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1083 r = -3;
1084 break;
1085 }
1086 }
1087
1088 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1089 r = 0;
1090 else
1091 r = -4;
1092
1093 /* Make sure there are no doorbells */
1094 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return r;
1097}
1098
1099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1100/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001101 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001102 * @ioc: Pointer to MPT adapter structure
1103 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001104 * @sleepFlag: Specifies whether the process can sleep
1105 *
1106 * Provides mechanism for the host driver to control the IOC's
1107 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001108 *
1109 * Access Control Value - bits[15:12]
1110 * 0h Reserved
1111 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1112 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1113 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1114 *
1115 * Returns 0 for success, non-zero for failure.
1116 */
1117
1118static int
1119mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1120{
1121 int r = 0;
1122
1123 /* return if in use */
1124 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1125 & MPI_DOORBELL_ACTIVE)
1126 return -1;
1127
1128 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1129
1130 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1131 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1132 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1133 (access_control_value<<12)));
1134
1135 /* Wait for IOC to clear Doorbell Status bit */
1136 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1137 return -2;
1138 }else
1139 return 0;
1140}
1141
1142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1143/**
1144 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001145 * @ioc: Pointer to pointer to IOC adapter
1146 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001147 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001148 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001149 * Returns 0 for success, non-zero for failure.
1150 */
1151static int
1152mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1153{
1154 char *psge;
1155 int flags_length;
1156 u32 host_page_buffer_sz=0;
1157
1158 if(!ioc->HostPageBuffer) {
1159
1160 host_page_buffer_sz =
1161 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1162
1163 if(!host_page_buffer_sz)
1164 return 0; /* fw doesn't need any host buffers */
1165
1166 /* spin till we get enough memory */
1167 while(host_page_buffer_sz > 0) {
1168
1169 if((ioc->HostPageBuffer = pci_alloc_consistent(
1170 ioc->pcidev,
1171 host_page_buffer_sz,
1172 &ioc->HostPageBuffer_dma)) != NULL) {
1173
Prakash, Sathya436ace72007-07-24 15:42:08 +05301174 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001175 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001176 ioc->name, ioc->HostPageBuffer,
1177 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001178 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001179 ioc->alloc_total += host_page_buffer_sz;
1180 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1181 break;
1182 }
1183
1184 host_page_buffer_sz -= (4*1024);
1185 }
1186 }
1187
1188 if(!ioc->HostPageBuffer) {
1189 printk(MYIOC_s_ERR_FMT
1190 "Failed to alloc memory for host_page_buffer!\n",
1191 ioc->name);
1192 return -999;
1193 }
1194
1195 psge = (char *)&ioc_init->HostPageBufferSGE;
1196 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1197 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1198 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1199 MPI_SGE_FLAGS_HOST_TO_IOC |
1200 MPI_SGE_FLAGS_END_OF_BUFFER;
1201 if (sizeof(dma_addr_t) == sizeof(u64)) {
1202 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1203 }
1204 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1205 flags_length |= ioc->HostPageBuffer_sz;
1206 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1207 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1208
1209return 0;
1210}
1211
1212/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1213/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001214 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 * @iocid: IOC unique identifier (integer)
1216 * @iocpp: Pointer to pointer to IOC adapter
1217 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001218 * Given a unique IOC identifier, set pointer to the associated MPT
1219 * adapter structure.
1220 *
1221 * Returns iocid and sets iocpp if iocid is found.
1222 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 */
1224int
1225mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1226{
1227 MPT_ADAPTER *ioc;
1228
1229 list_for_each_entry(ioc,&ioc_list,list) {
1230 if (ioc->id == iocid) {
1231 *iocpp =ioc;
1232 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001235
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 *iocpp = NULL;
1237 return -1;
1238}
1239
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301240/**
1241 * mpt_get_product_name - returns product string
1242 * @vendor: pci vendor id
1243 * @device: pci device id
1244 * @revision: pci revision id
1245 * @prod_name: string returned
1246 *
1247 * Returns product string displayed when driver loads,
1248 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1249 *
1250 **/
1251static void
1252mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1253{
1254 char *product_str = NULL;
1255
1256 if (vendor == PCI_VENDOR_ID_BROCADE) {
1257 switch (device)
1258 {
1259 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1260 switch (revision)
1261 {
1262 case 0x00:
1263 product_str = "BRE040 A0";
1264 break;
1265 case 0x01:
1266 product_str = "BRE040 A1";
1267 break;
1268 default:
1269 product_str = "BRE040";
1270 break;
1271 }
1272 break;
1273 }
1274 goto out;
1275 }
1276
1277 switch (device)
1278 {
1279 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1280 product_str = "LSIFC909 B1";
1281 break;
1282 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1283 product_str = "LSIFC919 B0";
1284 break;
1285 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1286 product_str = "LSIFC929 B0";
1287 break;
1288 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1289 if (revision < 0x80)
1290 product_str = "LSIFC919X A0";
1291 else
1292 product_str = "LSIFC919XL A1";
1293 break;
1294 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1295 if (revision < 0x80)
1296 product_str = "LSIFC929X A0";
1297 else
1298 product_str = "LSIFC929XL A1";
1299 break;
1300 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1301 product_str = "LSIFC939X A1";
1302 break;
1303 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1304 product_str = "LSIFC949X A1";
1305 break;
1306 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1307 switch (revision)
1308 {
1309 case 0x00:
1310 product_str = "LSIFC949E A0";
1311 break;
1312 case 0x01:
1313 product_str = "LSIFC949E A1";
1314 break;
1315 default:
1316 product_str = "LSIFC949E";
1317 break;
1318 }
1319 break;
1320 case MPI_MANUFACTPAGE_DEVID_53C1030:
1321 switch (revision)
1322 {
1323 case 0x00:
1324 product_str = "LSI53C1030 A0";
1325 break;
1326 case 0x01:
1327 product_str = "LSI53C1030 B0";
1328 break;
1329 case 0x03:
1330 product_str = "LSI53C1030 B1";
1331 break;
1332 case 0x07:
1333 product_str = "LSI53C1030 B2";
1334 break;
1335 case 0x08:
1336 product_str = "LSI53C1030 C0";
1337 break;
1338 case 0x80:
1339 product_str = "LSI53C1030T A0";
1340 break;
1341 case 0x83:
1342 product_str = "LSI53C1030T A2";
1343 break;
1344 case 0x87:
1345 product_str = "LSI53C1030T A3";
1346 break;
1347 case 0xc1:
1348 product_str = "LSI53C1020A A1";
1349 break;
1350 default:
1351 product_str = "LSI53C1030";
1352 break;
1353 }
1354 break;
1355 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1356 switch (revision)
1357 {
1358 case 0x03:
1359 product_str = "LSI53C1035 A2";
1360 break;
1361 case 0x04:
1362 product_str = "LSI53C1035 B0";
1363 break;
1364 default:
1365 product_str = "LSI53C1035";
1366 break;
1367 }
1368 break;
1369 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1370 switch (revision)
1371 {
1372 case 0x00:
1373 product_str = "LSISAS1064 A1";
1374 break;
1375 case 0x01:
1376 product_str = "LSISAS1064 A2";
1377 break;
1378 case 0x02:
1379 product_str = "LSISAS1064 A3";
1380 break;
1381 case 0x03:
1382 product_str = "LSISAS1064 A4";
1383 break;
1384 default:
1385 product_str = "LSISAS1064";
1386 break;
1387 }
1388 break;
1389 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1390 switch (revision)
1391 {
1392 case 0x00:
1393 product_str = "LSISAS1064E A0";
1394 break;
1395 case 0x01:
1396 product_str = "LSISAS1064E B0";
1397 break;
1398 case 0x02:
1399 product_str = "LSISAS1064E B1";
1400 break;
1401 case 0x04:
1402 product_str = "LSISAS1064E B2";
1403 break;
1404 case 0x08:
1405 product_str = "LSISAS1064E B3";
1406 break;
1407 default:
1408 product_str = "LSISAS1064E";
1409 break;
1410 }
1411 break;
1412 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1413 switch (revision)
1414 {
1415 case 0x00:
1416 product_str = "LSISAS1068 A0";
1417 break;
1418 case 0x01:
1419 product_str = "LSISAS1068 B0";
1420 break;
1421 case 0x02:
1422 product_str = "LSISAS1068 B1";
1423 break;
1424 default:
1425 product_str = "LSISAS1068";
1426 break;
1427 }
1428 break;
1429 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1430 switch (revision)
1431 {
1432 case 0x00:
1433 product_str = "LSISAS1068E A0";
1434 break;
1435 case 0x01:
1436 product_str = "LSISAS1068E B0";
1437 break;
1438 case 0x02:
1439 product_str = "LSISAS1068E B1";
1440 break;
1441 case 0x04:
1442 product_str = "LSISAS1068E B2";
1443 break;
1444 case 0x08:
1445 product_str = "LSISAS1068E B3";
1446 break;
1447 default:
1448 product_str = "LSISAS1068E";
1449 break;
1450 }
1451 break;
1452 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1453 switch (revision)
1454 {
1455 case 0x00:
1456 product_str = "LSISAS1078 A0";
1457 break;
1458 case 0x01:
1459 product_str = "LSISAS1078 B0";
1460 break;
1461 case 0x02:
1462 product_str = "LSISAS1078 C0";
1463 break;
1464 case 0x03:
1465 product_str = "LSISAS1078 C1";
1466 break;
1467 case 0x04:
1468 product_str = "LSISAS1078 C2";
1469 break;
1470 default:
1471 product_str = "LSISAS1078";
1472 break;
1473 }
1474 break;
1475 }
1476
1477 out:
1478 if (product_str)
1479 sprintf(prod_name, "%s", product_str);
1480}
1481
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301482/**
1483 * mpt_mapresources - map in memory mapped io
1484 * @ioc: Pointer to pointer to IOC adapter
1485 *
1486 **/
1487static int
1488mpt_mapresources(MPT_ADAPTER *ioc)
1489{
1490 u8 __iomem *mem;
1491 int ii;
1492 unsigned long mem_phys;
1493 unsigned long port;
1494 u32 msize;
1495 u32 psize;
1496 u8 revision;
1497 int r = -ENODEV;
1498 struct pci_dev *pdev;
1499
1500 pdev = ioc->pcidev;
1501 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1502 if (pci_enable_device_mem(pdev)) {
1503 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1504 "failed\n", ioc->name);
1505 return r;
1506 }
1507 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1508 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1509 "MEM failed\n", ioc->name);
1510 return r;
1511 }
1512
1513 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1514
1515 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
1516 && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
1517 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1518 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1519 ioc->name));
1520 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
1521 && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
1522 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1523 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1524 ioc->name));
1525 } else {
1526 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1527 ioc->name, pci_name(pdev));
1528 pci_release_selected_regions(pdev, ioc->bars);
1529 return r;
1530 }
1531
1532 mem_phys = msize = 0;
1533 port = psize = 0;
1534 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1535 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1536 if (psize)
1537 continue;
1538 /* Get I/O space! */
1539 port = pci_resource_start(pdev, ii);
1540 psize = pci_resource_len(pdev, ii);
1541 } else {
1542 if (msize)
1543 continue;
1544 /* Get memmap */
1545 mem_phys = pci_resource_start(pdev, ii);
1546 msize = pci_resource_len(pdev, ii);
1547 }
1548 }
1549 ioc->mem_size = msize;
1550
1551 mem = NULL;
1552 /* Get logical ptr for PciMem0 space */
1553 /*mem = ioremap(mem_phys, msize);*/
1554 mem = ioremap(mem_phys, msize);
1555 if (mem == NULL) {
1556 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1557 " memory!\n", ioc->name);
1558 return -EINVAL;
1559 }
1560 ioc->memmap = mem;
1561 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1562 ioc->name, mem, mem_phys));
1563
1564 ioc->mem_phys = mem_phys;
1565 ioc->chip = (SYSIF_REGS __iomem *)mem;
1566
1567 /* Save Port IO values in case we need to do downloadboot */
1568 ioc->pio_mem_phys = port;
1569 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1570
1571 return 0;
1572}
1573
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001575/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001576 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001578 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 *
1580 * This routine performs all the steps necessary to bring the IOC of
1581 * a MPT adapter to a OPERATIONAL state. This includes registering
1582 * memory regions, registering the interrupt, and allocating request
1583 * and reply memory pools.
1584 *
1585 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1586 * MPT adapter.
1587 *
1588 * Returns 0 for success, non-zero for failure.
1589 *
1590 * TODO: Add support for polled controllers
1591 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001592int
1593mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594{
1595 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301596 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 u8 revision;
1599 u8 pcixcmd;
1600 static int mpt_ids = 0;
1601#ifdef CONFIG_PROC_FS
1602 struct proc_dir_entry *dent, *ent;
1603#endif
1604
Jesper Juhl56876192007-08-10 14:50:51 -07001605 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1606 if (ioc == NULL) {
1607 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1608 return -ENOMEM;
1609 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301610
Eric Moore29dd3602007-09-14 18:46:51 -06001611 ioc->id = mpt_ids++;
1612 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001613
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301614 /*
1615 * set initial debug level
1616 * (refer to mptdebug.h)
1617 *
1618 */
1619 ioc->debug_level = mpt_debug_level;
1620 if (mpt_debug_level)
1621 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301622
Eric Moore29dd3602007-09-14 18:46:51 -06001623 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001624
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301625 ioc->pcidev = pdev;
1626 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001627 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 return r;
1629 }
1630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 ioc->alloc_total = sizeof(MPT_ADAPTER);
1632 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1633 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001634
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 ioc->pcidev = pdev;
1636 ioc->diagPending = 0;
1637 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001638 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
1640 /* Initialize the event logging.
1641 */
1642 ioc->eventTypes = 0; /* None */
1643 ioc->eventContext = 0;
1644 ioc->eventLogSize = 0;
1645 ioc->events = NULL;
1646
1647#ifdef MFCNT
1648 ioc->mfcnt = 0;
1649#endif
1650
1651 ioc->cached_fw = NULL;
1652
1653 /* Initilize SCSI Config Data structure
1654 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001655 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
1657 /* Initialize the running configQ head.
1658 */
1659 INIT_LIST_HEAD(&ioc->configQ);
1660
Michael Reed05e8ec12006-01-13 14:31:54 -06001661 /* Initialize the fc rport list head.
1662 */
1663 INIT_LIST_HEAD(&ioc->fc_rports);
1664
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 /* Find lookup slot. */
1666 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001667
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301668
1669 /* Initialize workqueue */
1670 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1671 spin_lock_init(&ioc->fault_reset_work_lock);
1672
1673 snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id);
1674 ioc->reset_work_q =
1675 create_singlethread_workqueue(ioc->reset_work_q_name);
1676 if (!ioc->reset_work_q) {
1677 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1678 ioc->name);
1679 pci_release_selected_regions(pdev, ioc->bars);
1680 kfree(ioc);
1681 return -ENOMEM;
1682 }
1683
Eric Moore29dd3602007-09-14 18:46:51 -06001684 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1685 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301687 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1688 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1689
1690 switch (pdev->device)
1691 {
1692 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1693 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1694 ioc->errata_flag_1064 = 1;
1695 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1696 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1697 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1698 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301700 break;
1701
1702 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 /* 929X Chip Fix. Set Split transactions level
1705 * for PCIX. Set MOST bits to zero.
1706 */
1707 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1708 pcixcmd &= 0x8F;
1709 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1710 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 /* 929XL Chip Fix. Set MMRBC to 0x08.
1712 */
1713 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1714 pcixcmd |= 0x08;
1715 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1716 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301718 break;
1719
1720 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 /* 919X Chip Fix. Set Split transactions level
1722 * for PCIX. Set MOST bits to zero.
1723 */
1724 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1725 pcixcmd &= 0x8F;
1726 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001727 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301728 break;
1729
1730 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 /* 1030 Chip Fix. Disable Split transactions
1732 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1733 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 if (revision < C0_1030) {
1735 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1736 pcixcmd &= 0x8F;
1737 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1738 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301739
1740 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001741 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301742 break;
1743
1744 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1745 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001746 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301747
1748 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1749 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1750 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001751 ioc->bus_type = SAS;
1752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301754 if (ioc->bus_type == SAS && mpt_msi_enable == -1)
1755 ioc->msi_enable = 1;
1756 else
1757 ioc->msi_enable = mpt_msi_enable;
1758
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001759 if (ioc->errata_flag_1064)
1760 pci_disable_io_access(pdev);
1761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 spin_lock_init(&ioc->FreeQlock);
1763
1764 /* Disable all! */
1765 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1766 ioc->active = 0;
1767 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1768
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301769 /* Set IOC ptr in the pcidev's driver data. */
1770 pci_set_drvdata(ioc->pcidev, ioc);
1771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 /* Set lookup ptr. */
1773 list_add_tail(&ioc->list, &ioc_list);
1774
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001775 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 */
1777 mpt_detect_bound_ports(ioc, pdev);
1778
James Bottomleyc92f2222006-03-01 09:02:49 -06001779 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1780 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001781 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1782 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001783
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001785 if (ioc->alt_ioc)
1786 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301787 iounmap(ioc->memmap);
1788 if (r != -5)
1789 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301790
1791 destroy_workqueue(ioc->reset_work_q);
1792 ioc->reset_work_q = NULL;
1793
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 kfree(ioc);
1795 pci_set_drvdata(pdev, NULL);
1796 return r;
1797 }
1798
1799 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001800 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301801 if(MptDeviceDriverHandlers[cb_idx] &&
1802 MptDeviceDriverHandlers[cb_idx]->probe) {
1803 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 }
1805 }
1806
1807#ifdef CONFIG_PROC_FS
1808 /*
1809 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1810 */
1811 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1812 if (dent) {
1813 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1814 if (ent) {
1815 ent->read_proc = procmpt_iocinfo_read;
1816 ent->data = ioc;
1817 }
1818 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1819 if (ent) {
1820 ent->read_proc = procmpt_summary_read;
1821 ent->data = ioc;
1822 }
1823 }
1824#endif
1825
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301826 if (!ioc->alt_ioc)
1827 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1828 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1829
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 return 0;
1831}
1832
1833/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001834/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001835 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 */
1838
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001839void
1840mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841{
1842 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1843 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301844 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301845 unsigned long flags;
1846 struct workqueue_struct *wq;
1847
1848 /*
1849 * Stop polling ioc for fault condition
1850 */
1851 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
1852 wq = ioc->reset_work_q;
1853 ioc->reset_work_q = NULL;
1854 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
1855 cancel_delayed_work(&ioc->fault_reset_work);
1856 destroy_workqueue(wq);
1857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
1859 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1860 remove_proc_entry(pname, NULL);
1861 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1862 remove_proc_entry(pname, NULL);
1863 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1864 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001865
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001867 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301868 if(MptDeviceDriverHandlers[cb_idx] &&
1869 MptDeviceDriverHandlers[cb_idx]->remove) {
1870 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 }
1872 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001873
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 /* Disable interrupts! */
1875 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1876
1877 ioc->active = 0;
1878 synchronize_irq(pdev->irq);
1879
1880 /* Clear any lingering interrupt */
1881 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1882
1883 CHIPREG_READ32(&ioc->chip->IntStatus);
1884
1885 mpt_adapter_dispose(ioc);
1886
1887 pci_set_drvdata(pdev, NULL);
1888}
1889
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890/**************************************************************************
1891 * Power Management
1892 */
1893#ifdef CONFIG_PM
1894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001895/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001896 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001897 * @pdev: Pointer to pci_dev structure
1898 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001900int
1901mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902{
1903 u32 device_state;
1904 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301906 device_state = pci_choose_state(pdev, state);
1907 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
1908 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1909 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
1911 /* put ioc into READY_STATE */
1912 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1913 printk(MYIOC_s_ERR_FMT
1914 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1915 }
1916
1917 /* disable interrupts */
1918 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1919 ioc->active = 0;
1920
1921 /* Clear any lingering interrupt */
1922 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1923
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301924 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05001925 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301926 pci_disable_msi(ioc->pcidev);
1927 ioc->pci_irq = -1;
1928 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301930 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 return 0;
1933}
1934
1935/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001936/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001937 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001938 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001940int
1941mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942{
1943 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1944 u32 device_state = pdev->current_state;
1945 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301946 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001947
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301948 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
1949 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1950 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301952 pci_set_power_state(pdev, PCI_D0);
1953 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301955 ioc->pcidev = pdev;
1956 err = mpt_mapresources(ioc);
1957 if (err)
1958 return err;
1959
1960 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1961 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1962 CHIPREG_READ32(&ioc->chip->Doorbell));
1963
1964 /*
1965 * Errata workaround for SAS pci express:
1966 * Upon returning to the D0 state, the contents of the doorbell will be
1967 * stale data, and this will incorrectly signal to the host driver that
1968 * the firmware is ready to process mpt commands. The workaround is
1969 * to issue a diagnostic reset.
1970 */
1971 if (ioc->bus_type == SAS && (pdev->device ==
1972 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
1973 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
1974 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
1975 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
1976 ioc->name);
1977 goto out;
1978 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
1981 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301982 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
1983 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1984 CAN_SLEEP);
1985 if (recovery_state != 0)
1986 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
1987 "error:[%x]\n", ioc->name, recovery_state);
1988 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301990 "pci-resume: success\n", ioc->name);
1991 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301993
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994}
1995#endif
1996
James Bottomley4ff42a62006-05-17 18:06:52 -05001997static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301998mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001999{
2000 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2001 ioc->bus_type != SPI) ||
2002 (MptDriverClass[index] == MPTFC_DRIVER &&
2003 ioc->bus_type != FC) ||
2004 (MptDriverClass[index] == MPTSAS_DRIVER &&
2005 ioc->bus_type != SAS))
2006 /* make sure we only call the relevant reset handler
2007 * for the bus */
2008 return 0;
2009 return (MptResetHandlers[index])(ioc, reset_phase);
2010}
2011
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002013/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2015 * @ioc: Pointer to MPT adapter structure
2016 * @reason: Event word / reason
2017 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2018 *
2019 * This routine performs all the steps necessary to bring the IOC
2020 * to a OPERATIONAL state.
2021 *
2022 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2023 * MPT adapter.
2024 *
2025 * Returns:
2026 * 0 for success
2027 * -1 if failed to get board READY
2028 * -2 if READY but IOCFacts Failed
2029 * -3 if READY but PrimeIOCFifos Failed
2030 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302031 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302032 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 */
2034static int
2035mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2036{
2037 int hard_reset_done = 0;
2038 int alt_ioc_ready = 0;
2039 int hard;
2040 int rc=0;
2041 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302042 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 int handlers;
2044 int ret = 0;
2045 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002046 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302047 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048
Eric Moore29dd3602007-09-14 18:46:51 -06002049 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2050 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051
2052 /* Disable reply interrupts (also blocks FreeQ) */
2053 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2054 ioc->active = 0;
2055
2056 if (ioc->alt_ioc) {
2057 if (ioc->alt_ioc->active)
2058 reset_alt_ioc_active = 1;
2059
2060 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2061 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2062 ioc->alt_ioc->active = 0;
2063 }
2064
2065 hard = 1;
2066 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2067 hard = 0;
2068
2069 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2070 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002071 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2072 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
2074 if (reset_alt_ioc_active && ioc->alt_ioc) {
2075 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002076 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2077 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002078 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 ioc->alt_ioc->active = 1;
2080 }
2081
2082 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002083 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 }
2085 return -1;
2086 }
2087
2088 /* hard_reset_done = 0 if a soft reset was performed
2089 * and 1 if a hard reset was performed.
2090 */
2091 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2092 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2093 alt_ioc_ready = 1;
2094 else
Eric Moore29dd3602007-09-14 18:46:51 -06002095 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 }
2097
2098 for (ii=0; ii<5; ii++) {
2099 /* Get IOC facts! Allow 5 retries */
2100 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2101 break;
2102 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002103
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
2105 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002106 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2107 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 ret = -2;
2109 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2110 MptDisplayIocCapabilities(ioc);
2111 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002112
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 if (alt_ioc_ready) {
2114 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302115 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002116 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 /* Retry - alt IOC was initialized once
2118 */
2119 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2120 }
2121 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302122 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002123 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 alt_ioc_ready = 0;
2125 reset_alt_ioc_active = 0;
2126 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2127 MptDisplayIocCapabilities(ioc->alt_ioc);
2128 }
2129 }
2130
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302131 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2132 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2133 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2134 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2135 IORESOURCE_IO);
2136 if (pci_enable_device(ioc->pcidev))
2137 return -5;
2138 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2139 "mpt"))
2140 return -5;
2141 }
2142
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002143 /*
2144 * Device is reset now. It must have de-asserted the interrupt line
2145 * (if it was asserted) and it should be safe to register for the
2146 * interrupt now.
2147 */
2148 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2149 ioc->pci_irq = -1;
2150 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302151 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002152 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002153 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302154 else
2155 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002156 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002157 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002158 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002159 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002160 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302161 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002162 pci_disable_msi(ioc->pcidev);
2163 return -EBUSY;
2164 }
2165 irq_allocated = 1;
2166 ioc->pci_irq = ioc->pcidev->irq;
2167 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002168 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2169 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002170 }
2171 }
2172
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 /* Prime reply & request queues!
2174 * (mucho alloc's) Must be done prior to
2175 * init as upper addresses are needed for init.
2176 * If fails, continue with alt-ioc processing
2177 */
2178 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2179 ret = -3;
2180
2181 /* May need to check/upload firmware & data here!
2182 * If fails, continue with alt-ioc processing
2183 */
2184 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2185 ret = -4;
2186// NEW!
2187 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002188 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2189 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 alt_ioc_ready = 0;
2191 reset_alt_ioc_active = 0;
2192 }
2193
2194 if (alt_ioc_ready) {
2195 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2196 alt_ioc_ready = 0;
2197 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002198 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2199 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 }
2201 }
2202
2203 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2204 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302205 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002206 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
2208 /* Controller is not operational, cannot do upload
2209 */
2210 if (ret == 0) {
2211 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002212 if (rc == 0) {
2213 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2214 /*
2215 * Maintain only one pointer to FW memory
2216 * so there will not be two attempt to
2217 * downloadboot onboard dual function
2218 * chips (mpt_adapter_disable,
2219 * mpt_diag_reset)
2220 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302221 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002222 "mpt_upload: alt_%s has cached_fw=%p \n",
2223 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302224 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002225 }
2226 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002227 printk(MYIOC_s_WARN_FMT
2228 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302229 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 }
2232 }
2233 }
2234
2235 if (ret == 0) {
2236 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002237 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 ioc->active = 1;
2239 }
2240
2241 if (reset_alt_ioc_active && ioc->alt_ioc) {
2242 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002243 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2244 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002245 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 ioc->alt_ioc->active = 1;
2247 }
2248
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002249 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 * and EventAck handling.
2251 */
2252 if ((ret == 0) && (!ioc->facts.EventState))
2253 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2254
2255 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2256 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2257
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002258 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2260 * recursive scenario; GetLanConfigPages times out, timer expired
2261 * routine calls HardResetHandler, which calls into here again,
2262 * and we try GetLanConfigPages again...
2263 */
2264 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002265
2266 /*
2267 * Initalize link list for inactive raid volumes.
2268 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002269 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002270 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2271
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002272 if (ioc->bus_type == SAS) {
2273
2274 /* clear persistency table */
2275 if(ioc->facts.IOCExceptions &
2276 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2277 ret = mptbase_sas_persist_operation(ioc,
2278 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2279 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002280 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002281 }
2282
2283 /* Find IM volumes
2284 */
2285 mpt_findImVolumes(ioc);
2286
2287 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2289 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2290 /*
2291 * Pre-fetch the ports LAN MAC address!
2292 * (LANPage1_t stuff)
2293 */
2294 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302295 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2296 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002297 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2298 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302299
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 }
2301 } else {
2302 /* Get NVRAM and adapter maximums from SPP 0 and 2
2303 */
2304 mpt_GetScsiPortSettings(ioc, 0);
2305
2306 /* Get version and length of SDP 1
2307 */
2308 mpt_readScsiDevicePageHeaders(ioc, 0);
2309
2310 /* Find IM volumes
2311 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002312 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 mpt_findImVolumes(ioc);
2314
2315 /* Check, and possibly reset, the coalescing value
2316 */
2317 mpt_read_ioc_pg_1(ioc);
2318
2319 mpt_read_ioc_pg_4(ioc);
2320 }
2321
2322 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302323 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 }
2325
2326 /*
2327 * Call each currently registered protocol IOC reset handler
2328 * with post-reset indication.
2329 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2330 * MptResetHandlers[] registered yet.
2331 */
2332 if (hard_reset_done) {
2333 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302334 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2335 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302336 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002337 "Calling IOC post_reset handler #%d\n",
2338 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302339 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 handlers++;
2341 }
2342
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302343 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302344 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002345 "Calling IOC post_reset handler #%d\n",
2346 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302347 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 handlers++;
2349 }
2350 }
2351 /* FIXME? Examine results here? */
2352 }
2353
Eric Moore0ccdb002006-07-11 17:33:13 -06002354 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002355 if ((ret != 0) && irq_allocated) {
2356 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302357 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002358 pci_disable_msi(ioc->pcidev);
2359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 return ret;
2361}
2362
2363/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002364/**
2365 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 * @ioc: Pointer to MPT adapter structure
2367 * @pdev: Pointer to (struct pci_dev) structure
2368 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002369 * Search for PCI bus/dev_function which matches
2370 * PCI bus/dev_function (+/-1) for newly discovered 929,
2371 * 929X, 1030 or 1035.
2372 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2374 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2375 */
2376static void
2377mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2378{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002379 struct pci_dev *peer=NULL;
2380 unsigned int slot = PCI_SLOT(pdev->devfn);
2381 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 MPT_ADAPTER *ioc_srch;
2383
Prakash, Sathya436ace72007-07-24 15:42:08 +05302384 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002385 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002386 ioc->name, pci_name(pdev), pdev->bus->number,
2387 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002388
2389 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2390 if (!peer) {
2391 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2392 if (!peer)
2393 return;
2394 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
2396 list_for_each_entry(ioc_srch, &ioc_list, list) {
2397 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002398 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 /* Paranoia checks */
2400 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002401 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002402 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 break;
2404 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002405 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002406 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 break;
2408 }
Eric Moore29dd3602007-09-14 18:46:51 -06002409 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002410 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 ioc_srch->alt_ioc = ioc;
2412 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 }
2414 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002415 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416}
2417
2418/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002419/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002421 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 */
2423static void
2424mpt_adapter_disable(MPT_ADAPTER *ioc)
2425{
2426 int sz;
2427 int ret;
2428
2429 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302430 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
2431 "adapter\n", __FUNCTION__, ioc->name));
2432 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2433 ioc->cached_fw, CAN_SLEEP)) < 0) {
2434 printk(MYIOC_s_WARN_FMT
2435 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002436 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 }
2438 }
2439
2440 /* Disable adapter interrupts! */
2441 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2442 ioc->active = 0;
2443 /* Clear any lingering interrupt */
2444 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2445
2446 if (ioc->alloc != NULL) {
2447 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002448 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2449 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 pci_free_consistent(ioc->pcidev, sz,
2451 ioc->alloc, ioc->alloc_dma);
2452 ioc->reply_frames = NULL;
2453 ioc->req_frames = NULL;
2454 ioc->alloc = NULL;
2455 ioc->alloc_total -= sz;
2456 }
2457
2458 if (ioc->sense_buf_pool != NULL) {
2459 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2460 pci_free_consistent(ioc->pcidev, sz,
2461 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2462 ioc->sense_buf_pool = NULL;
2463 ioc->alloc_total -= sz;
2464 }
2465
2466 if (ioc->events != NULL){
2467 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2468 kfree(ioc->events);
2469 ioc->events = NULL;
2470 ioc->alloc_total -= sz;
2471 }
2472
Prakash, Sathya984621b2008-01-11 14:42:17 +05302473 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002475 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002476 mpt_inactive_raid_list_free(ioc);
2477 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002478 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002479 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002480 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 if (ioc->spi_data.pIocPg4 != NULL) {
2483 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302484 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 ioc->spi_data.pIocPg4,
2486 ioc->spi_data.IocPg4_dma);
2487 ioc->spi_data.pIocPg4 = NULL;
2488 ioc->alloc_total -= sz;
2489 }
2490
2491 if (ioc->ReqToChain != NULL) {
2492 kfree(ioc->ReqToChain);
2493 kfree(ioc->RequestNB);
2494 ioc->ReqToChain = NULL;
2495 }
2496
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002497 kfree(ioc->ChainToChain);
2498 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002499
2500 if (ioc->HostPageBuffer != NULL) {
2501 if((ret = mpt_host_page_access_control(ioc,
2502 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002503 printk(MYIOC_s_ERR_FMT
2504 "host page buffers free failed (%d)!\n",
2505 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002506 }
Eric Moore29dd3602007-09-14 18:46:51 -06002507 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002508 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2509 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002510 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002511 ioc->HostPageBuffer = NULL;
2512 ioc->HostPageBuffer_sz = 0;
2513 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515}
2516
2517/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002518/**
2519 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 * @ioc: Pointer to MPT adapter structure
2521 *
2522 * This routine unregisters h/w resources and frees all alloc'd memory
2523 * associated with a MPT adapter structure.
2524 */
2525static void
2526mpt_adapter_dispose(MPT_ADAPTER *ioc)
2527{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002528 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002530 if (ioc == NULL)
2531 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002533 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002535 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002537 if (ioc->pci_irq != -1) {
2538 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302539 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002540 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002541 ioc->pci_irq = -1;
2542 }
2543
2544 if (ioc->memmap != NULL) {
2545 iounmap(ioc->memmap);
2546 ioc->memmap = NULL;
2547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302549 pci_disable_device(ioc->pcidev);
2550 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2551
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002553 if (ioc->mtrr_reg > 0) {
2554 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002555 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557#endif
2558
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002559 /* Zap the adapter lookup ptr! */
2560 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002562 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002563 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2564 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002565
2566 if (ioc->alt_ioc)
2567 ioc->alt_ioc->alt_ioc = NULL;
2568
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002569 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570}
2571
2572/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002573/**
2574 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 * @ioc: Pointer to MPT adapter structure
2576 */
2577static void
2578MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2579{
2580 int i = 0;
2581
2582 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302583 if (ioc->prod_name)
2584 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 printk("Capabilities={");
2586
2587 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2588 printk("Initiator");
2589 i++;
2590 }
2591
2592 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2593 printk("%sTarget", i ? "," : "");
2594 i++;
2595 }
2596
2597 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2598 printk("%sLAN", i ? "," : "");
2599 i++;
2600 }
2601
2602#if 0
2603 /*
2604 * This would probably evoke more questions than it's worth
2605 */
2606 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2607 printk("%sLogBusAddr", i ? "," : "");
2608 i++;
2609 }
2610#endif
2611
2612 printk("}\n");
2613}
2614
2615/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002616/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2618 * @ioc: Pointer to MPT_ADAPTER structure
2619 * @force: Force hard KickStart of IOC
2620 * @sleepFlag: Specifies whether the process can sleep
2621 *
2622 * Returns:
2623 * 1 - DIAG reset and READY
2624 * 0 - READY initially OR soft reset and READY
2625 * -1 - Any failure on KickStart
2626 * -2 - Msg Unit Reset Failed
2627 * -3 - IO Unit Reset Failed
2628 * -4 - IOC owned by a PEER
2629 */
2630static int
2631MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2632{
2633 u32 ioc_state;
2634 int statefault = 0;
2635 int cntdn;
2636 int hard_reset_done = 0;
2637 int r;
2638 int ii;
2639 int whoinit;
2640
2641 /* Get current [raw] IOC state */
2642 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002643 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
2645 /*
2646 * Check to see if IOC got left/stuck in doorbell handshake
2647 * grip of death. If so, hard reset the IOC.
2648 */
2649 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2650 statefault = 1;
2651 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2652 ioc->name);
2653 }
2654
2655 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002656 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 return 0;
2658
2659 /*
2660 * Check to see if IOC is in FAULT state.
2661 */
2662 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2663 statefault = 2;
2664 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002665 ioc->name);
2666 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2667 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 }
2669
2670 /*
2671 * Hmmm... Did it get left operational?
2672 */
2673 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302674 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 ioc->name));
2676
2677 /* Check WhoInit.
2678 * If PCI Peer, exit.
2679 * Else, if no fault conditions are present, issue a MessageUnitReset
2680 * Else, fall through to KickStart case
2681 */
2682 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002683 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2684 "whoinit 0x%x statefault %d force %d\n",
2685 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 if (whoinit == MPI_WHOINIT_PCI_PEER)
2687 return -4;
2688 else {
2689 if ((statefault == 0 ) && (force == 0)) {
2690 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2691 return 0;
2692 }
2693 statefault = 3;
2694 }
2695 }
2696
2697 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2698 if (hard_reset_done < 0)
2699 return -1;
2700
2701 /*
2702 * Loop here waiting for IOC to come READY.
2703 */
2704 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002705 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
2707 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2708 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2709 /*
2710 * BIOS or previous driver load left IOC in OP state.
2711 * Reset messaging FIFOs.
2712 */
2713 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2714 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2715 return -2;
2716 }
2717 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2718 /*
2719 * Something is wrong. Try to get IOC back
2720 * to a known state.
2721 */
2722 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2723 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2724 return -3;
2725 }
2726 }
2727
2728 ii++; cntdn--;
2729 if (!cntdn) {
2730 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2731 ioc->name, (int)((ii+5)/HZ));
2732 return -ETIME;
2733 }
2734
2735 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002736 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 } else {
2738 mdelay (1); /* 1 msec delay */
2739 }
2740
2741 }
2742
2743 if (statefault < 3) {
2744 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2745 ioc->name,
2746 statefault==1 ? "stuck handshake" : "IOC FAULT");
2747 }
2748
2749 return hard_reset_done;
2750}
2751
2752/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002753/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 * mpt_GetIocState - Get the current state of a MPT adapter.
2755 * @ioc: Pointer to MPT_ADAPTER structure
2756 * @cooked: Request raw or cooked IOC state
2757 *
2758 * Returns all IOC Doorbell register bits if cooked==0, else just the
2759 * Doorbell bits in MPI_IOC_STATE_MASK.
2760 */
2761u32
2762mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2763{
2764 u32 s, sc;
2765
2766 /* Get! */
2767 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 sc = s & MPI_IOC_STATE_MASK;
2769
2770 /* Save! */
2771 ioc->last_state = sc;
2772
2773 return cooked ? sc : s;
2774}
2775
2776/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002777/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 * GetIocFacts - Send IOCFacts request to MPT adapter.
2779 * @ioc: Pointer to MPT_ADAPTER structure
2780 * @sleepFlag: Specifies whether the process can sleep
2781 * @reason: If recovery, only update facts.
2782 *
2783 * Returns 0 for success, non-zero for failure.
2784 */
2785static int
2786GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2787{
2788 IOCFacts_t get_facts;
2789 IOCFactsReply_t *facts;
2790 int r;
2791 int req_sz;
2792 int reply_sz;
2793 int sz;
2794 u32 status, vv;
2795 u8 shiftFactor=1;
2796
2797 /* IOC *must* NOT be in RESET state! */
2798 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002799 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2800 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 return -44;
2802 }
2803
2804 facts = &ioc->facts;
2805
2806 /* Destination (reply area)... */
2807 reply_sz = sizeof(*facts);
2808 memset(facts, 0, reply_sz);
2809
2810 /* Request area (get_facts on the stack right now!) */
2811 req_sz = sizeof(get_facts);
2812 memset(&get_facts, 0, req_sz);
2813
2814 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2815 /* Assert: All other get_facts fields are zero! */
2816
Prakash, Sathya436ace72007-07-24 15:42:08 +05302817 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002818 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 ioc->name, req_sz, reply_sz));
2820
2821 /* No non-zero fields in the get_facts request are greater than
2822 * 1 byte in size, so we can just fire it off as is.
2823 */
2824 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2825 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2826 if (r != 0)
2827 return r;
2828
2829 /*
2830 * Now byte swap (GRRR) the necessary fields before any further
2831 * inspection of reply contents.
2832 *
2833 * But need to do some sanity checks on MsgLength (byte) field
2834 * to make sure we don't zero IOC's req_sz!
2835 */
2836 /* Did we get a valid reply? */
2837 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2838 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2839 /*
2840 * If not been here, done that, save off first WhoInit value
2841 */
2842 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2843 ioc->FirstWhoInit = facts->WhoInit;
2844 }
2845
2846 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2847 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2848 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2849 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2850 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002851 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 /* CHECKME! IOCStatus, IOCLogInfo */
2853
2854 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2855 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2856
2857 /*
2858 * FC f/w version changed between 1.1 and 1.2
2859 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2860 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2861 */
2862 if (facts->MsgVersion < 0x0102) {
2863 /*
2864 * Handle old FC f/w style, convert to new...
2865 */
2866 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2867 facts->FWVersion.Word =
2868 ((oldv<<12) & 0xFF000000) |
2869 ((oldv<<8) & 0x000FFF00);
2870 } else
2871 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2872
2873 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002874 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2875 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2876 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 facts->CurrentHostMfaHighAddr =
2878 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2879 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2880 facts->CurrentSenseBufferHighAddr =
2881 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2882 facts->CurReplyFrameSize =
2883 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002884 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885
2886 /*
2887 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2888 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2889 * to 14 in MPI-1.01.0x.
2890 */
2891 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2892 facts->MsgVersion > 0x0100) {
2893 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2894 }
2895
2896 sz = facts->FWImageSize;
2897 if ( sz & 0x01 )
2898 sz += 1;
2899 if ( sz & 0x02 )
2900 sz += 2;
2901 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002902
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 if (!facts->RequestFrameSize) {
2904 /* Something is wrong! */
2905 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2906 ioc->name);
2907 return -55;
2908 }
2909
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002910 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 vv = ((63 / (sz * 4)) + 1) & 0x03;
2912 ioc->NB_for_64_byte_frame = vv;
2913 while ( sz )
2914 {
2915 shiftFactor++;
2916 sz = sz >> 1;
2917 }
2918 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302919 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002920 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2921 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002922
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2924 /*
2925 * Set values for this IOC's request & reply frame sizes,
2926 * and request & reply queue depths...
2927 */
2928 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2929 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2930 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2931 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2932
Prakash, Sathya436ace72007-07-24 15:42:08 +05302933 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302935 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 ioc->name, ioc->req_sz, ioc->req_depth));
2937
2938 /* Get port facts! */
2939 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2940 return r;
2941 }
2942 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002943 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2945 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2946 RequestFrameSize)/sizeof(u32)));
2947 return -66;
2948 }
2949
2950 return 0;
2951}
2952
2953/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002954/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 * GetPortFacts - Send PortFacts request to MPT adapter.
2956 * @ioc: Pointer to MPT_ADAPTER structure
2957 * @portnum: Port number
2958 * @sleepFlag: Specifies whether the process can sleep
2959 *
2960 * Returns 0 for success, non-zero for failure.
2961 */
2962static int
2963GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2964{
2965 PortFacts_t get_pfacts;
2966 PortFactsReply_t *pfacts;
2967 int ii;
2968 int req_sz;
2969 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002970 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
2972 /* IOC *must* NOT be in RESET state! */
2973 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002974 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2975 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 return -4;
2977 }
2978
2979 pfacts = &ioc->pfacts[portnum];
2980
2981 /* Destination (reply area)... */
2982 reply_sz = sizeof(*pfacts);
2983 memset(pfacts, 0, reply_sz);
2984
2985 /* Request area (get_pfacts on the stack right now!) */
2986 req_sz = sizeof(get_pfacts);
2987 memset(&get_pfacts, 0, req_sz);
2988
2989 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2990 get_pfacts.PortNumber = portnum;
2991 /* Assert: All other get_pfacts fields are zero! */
2992
Prakash, Sathya436ace72007-07-24 15:42:08 +05302993 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 ioc->name, portnum));
2995
2996 /* No non-zero fields in the get_pfacts request are greater than
2997 * 1 byte in size, so we can just fire it off as is.
2998 */
2999 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3000 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3001 if (ii != 0)
3002 return ii;
3003
3004 /* Did we get a valid reply? */
3005
3006 /* Now byte swap the necessary fields in the response. */
3007 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3008 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3009 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3010 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3011 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3012 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3013 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3014 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3015 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3016
Eric Moore793955f2007-01-29 09:42:20 -07003017 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3018 pfacts->MaxDevices;
3019 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3020 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3021
3022 /*
3023 * Place all the devices on channels
3024 *
3025 * (for debuging)
3026 */
3027 if (mpt_channel_mapping) {
3028 ioc->devices_per_bus = 1;
3029 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3030 }
3031
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 return 0;
3033}
3034
3035/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003036/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 * SendIocInit - Send IOCInit request to MPT adapter.
3038 * @ioc: Pointer to MPT_ADAPTER structure
3039 * @sleepFlag: Specifies whether the process can sleep
3040 *
3041 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3042 *
3043 * Returns 0 for success, non-zero for failure.
3044 */
3045static int
3046SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3047{
3048 IOCInit_t ioc_init;
3049 MPIDefaultReply_t init_reply;
3050 u32 state;
3051 int r;
3052 int count;
3053 int cntdn;
3054
3055 memset(&ioc_init, 0, sizeof(ioc_init));
3056 memset(&init_reply, 0, sizeof(init_reply));
3057
3058 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3059 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3060
3061 /* If we are in a recovery mode and we uploaded the FW image,
3062 * then this pointer is not NULL. Skip the upload a second time.
3063 * Set this flag if cached_fw set for either IOC.
3064 */
3065 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3066 ioc->upload_fw = 1;
3067 else
3068 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303069 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3071
Eric Moore793955f2007-01-29 09:42:20 -07003072 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3073 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303074 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003075 ioc->name, ioc->facts.MsgVersion));
3076 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3077 // set MsgVersion and HeaderVersion host driver was built with
3078 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3079 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003081 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3082 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3083 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3084 return -99;
3085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3087
3088 if (sizeof(dma_addr_t) == sizeof(u64)) {
3089 /* Save the upper 32-bits of the request
3090 * (reply) and sense buffers.
3091 */
3092 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3093 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3094 } else {
3095 /* Force 32-bit addressing */
3096 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3097 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3098 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003099
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3101 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003102 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3103 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104
Prakash, Sathya436ace72007-07-24 15:42:08 +05303105 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 ioc->name, &ioc_init));
3107
3108 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3109 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003110 if (r != 0) {
3111 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
3115 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003116 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 */
3118
Prakash, Sathya436ace72007-07-24 15:42:08 +05303119 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003121
3122 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3123 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126
3127 /* YIKES! SUPER IMPORTANT!!!
3128 * Poll IocState until _OPERATIONAL while IOC is doing
3129 * LoopInit and TargetDiscovery!
3130 */
3131 count = 0;
3132 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3133 state = mpt_GetIocState(ioc, 1);
3134 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3135 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003136 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 } else {
3138 mdelay(1);
3139 }
3140
3141 if (!cntdn) {
3142 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3143 ioc->name, (int)((count+5)/HZ));
3144 return -9;
3145 }
3146
3147 state = mpt_GetIocState(ioc, 1);
3148 count++;
3149 }
Eric Moore29dd3602007-09-14 18:46:51 -06003150 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 ioc->name, count));
3152
Eric Mooreba856d32006-07-11 17:34:01 -06003153 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 return r;
3155}
3156
3157/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003158/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 * SendPortEnable - Send PortEnable request to MPT adapter port.
3160 * @ioc: Pointer to MPT_ADAPTER structure
3161 * @portnum: Port number to enable
3162 * @sleepFlag: Specifies whether the process can sleep
3163 *
3164 * Send PortEnable to bring IOC to OPERATIONAL state.
3165 *
3166 * Returns 0 for success, non-zero for failure.
3167 */
3168static int
3169SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3170{
3171 PortEnable_t port_enable;
3172 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003173 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 int req_sz;
3175 int reply_sz;
3176
3177 /* Destination... */
3178 reply_sz = sizeof(MPIDefaultReply_t);
3179 memset(&reply_buf, 0, reply_sz);
3180
3181 req_sz = sizeof(PortEnable_t);
3182 memset(&port_enable, 0, req_sz);
3183
3184 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3185 port_enable.PortNumber = portnum;
3186/* port_enable.ChainOffset = 0; */
3187/* port_enable.MsgFlags = 0; */
3188/* port_enable.MsgContext = 0; */
3189
Prakash, Sathya436ace72007-07-24 15:42:08 +05303190 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 ioc->name, portnum, &port_enable));
3192
3193 /* RAID FW may take a long time to enable
3194 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003195 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003196 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3197 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3198 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003199 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003200 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3201 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3202 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003204 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205}
3206
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003207/**
3208 * mpt_alloc_fw_memory - allocate firmware memory
3209 * @ioc: Pointer to MPT_ADAPTER structure
3210 * @size: total FW bytes
3211 *
3212 * If memory has already been allocated, the same (cached) value
3213 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303214 *
3215 * Return 0 if successfull, or non-zero for failure
3216 **/
3217int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3219{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303220 int rc;
3221
3222 if (ioc->cached_fw) {
3223 rc = 0; /* use already allocated memory */
3224 goto out;
3225 }
3226 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3228 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303229 rc = 0;
3230 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303232 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3233 if (!ioc->cached_fw) {
3234 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3235 ioc->name);
3236 rc = -1;
3237 } else {
3238 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3239 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3240 ioc->alloc_total += size;
3241 rc = 0;
3242 }
3243 out:
3244 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303246
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003247/**
3248 * mpt_free_fw_memory - free firmware memory
3249 * @ioc: Pointer to MPT_ADAPTER structure
3250 *
3251 * If alt_img is NULL, delete from ioc structure.
3252 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303253 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254void
3255mpt_free_fw_memory(MPT_ADAPTER *ioc)
3256{
3257 int sz;
3258
Prakash, Sathya984621b2008-01-11 14:42:17 +05303259 if (!ioc->cached_fw)
3260 return;
3261
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303263 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3264 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003265 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303266 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268}
3269
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003271/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3273 * @ioc: Pointer to MPT_ADAPTER structure
3274 * @sleepFlag: Specifies whether the process can sleep
3275 *
3276 * Returns 0 for success, >0 for handshake failure
3277 * <0 for fw upload failure.
3278 *
3279 * Remark: If bound IOC and a successful FWUpload was performed
3280 * on the bound IOC, the second image is discarded
3281 * and memory is free'd. Both channels must upload to prevent
3282 * IOC from running in degraded mode.
3283 */
3284static int
3285mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3286{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 u8 reply[sizeof(FWUploadReply_t)];
3288 FWUpload_t *prequest;
3289 FWUploadReply_t *preply;
3290 FWUploadTCSGE_t *ptcsge;
3291 int sgeoffset;
3292 u32 flagsLength;
3293 int ii, sz, reply_sz;
3294 int cmdStatus;
3295
3296 /* If the image size is 0, we are done.
3297 */
3298 if ((sz = ioc->facts.FWImageSize) == 0)
3299 return 0;
3300
Prakash, Sathya984621b2008-01-11 14:42:17 +05303301 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3302 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303
Eric Moore29dd3602007-09-14 18:46:51 -06003304 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3305 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003306
Eric Moorebc6e0892007-09-29 10:16:28 -06003307 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3308 kzalloc(ioc->req_sz, GFP_KERNEL);
3309 if (!prequest) {
3310 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3311 "while allocating memory \n", ioc->name));
3312 mpt_free_fw_memory(ioc);
3313 return -ENOMEM;
3314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315
Eric Moorebc6e0892007-09-29 10:16:28 -06003316 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317
3318 reply_sz = sizeof(reply);
3319 memset(preply, 0, reply_sz);
3320
3321 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3322 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3323
3324 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3325 ptcsge->DetailsLength = 12;
3326 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3327 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003328 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
3330 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3331
3332 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003333 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334
3335 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003336 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3337 ioc->name, prequest, sgeoffset));
3338 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
3340 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3341 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3342
Eric Moore29dd3602007-09-14 18:46:51 -06003343 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344
3345 cmdStatus = -EFAULT;
3346 if (ii == 0) {
3347 /* Handshake transfer was complete and successful.
3348 * Check the Reply Frame.
3349 */
3350 int status, transfer_sz;
3351 status = le16_to_cpu(preply->IOCStatus);
3352 if (status == MPI_IOCSTATUS_SUCCESS) {
3353 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3354 if (transfer_sz == sz)
3355 cmdStatus = 0;
3356 }
3357 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303358 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 ioc->name, cmdStatus));
3360
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003361
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 if (cmdStatus) {
3363
Prakash, Sathya436ace72007-07-24 15:42:08 +05303364 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 ioc->name));
3366 mpt_free_fw_memory(ioc);
3367 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003368 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369
3370 return cmdStatus;
3371}
3372
3373/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003374/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 * mpt_downloadboot - DownloadBoot code
3376 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003377 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 * @sleepFlag: Specifies whether the process can sleep
3379 *
3380 * FwDownloadBoot requires Programmed IO access.
3381 *
3382 * Returns 0 for success
3383 * -1 FW Image size is 0
3384 * -2 No valid cached_fw Pointer
3385 * <0 for fw upload failure.
3386 */
3387static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003388mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 MpiExtImageHeader_t *pExtImage;
3391 u32 fwSize;
3392 u32 diag0val;
3393 int count;
3394 u32 *ptrFw;
3395 u32 diagRwData;
3396 u32 nextImage;
3397 u32 load_addr;
3398 u32 ioc_state=0;
3399
Prakash, Sathya436ace72007-07-24 15:42:08 +05303400 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003401 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003402
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3404 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3405 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3406 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3407 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3408 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3409
3410 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3411
3412 /* wait 1 msec */
3413 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003414 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 } else {
3416 mdelay (1);
3417 }
3418
3419 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3420 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3421
3422 for (count = 0; count < 30; count ++) {
3423 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3424 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303425 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 ioc->name, count));
3427 break;
3428 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003429 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003431 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003433 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 }
3435 }
3436
3437 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303438 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003439 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 ioc->name, diag0val));
3441 return -3;
3442 }
3443
3444 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3445 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3446 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3447 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3448 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3449 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3450
3451 /* Set the DiagRwEn and Disable ARM bits */
3452 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3453
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 fwSize = (pFwHeader->ImageSize + 3)/4;
3455 ptrFw = (u32 *) pFwHeader;
3456
3457 /* Write the LoadStartAddress to the DiagRw Address Register
3458 * using Programmed IO
3459 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003460 if (ioc->errata_flag_1064)
3461 pci_enable_io_access(ioc->pcidev);
3462
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303464 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 ioc->name, pFwHeader->LoadStartAddress));
3466
Prakash, Sathya436ace72007-07-24 15:42:08 +05303467 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 ioc->name, fwSize*4, ptrFw));
3469 while (fwSize--) {
3470 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3471 }
3472
3473 nextImage = pFwHeader->NextImageHeaderOffset;
3474 while (nextImage) {
3475 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3476
3477 load_addr = pExtImage->LoadStartAddress;
3478
3479 fwSize = (pExtImage->ImageSize + 3) >> 2;
3480 ptrFw = (u32 *)pExtImage;
3481
Prakash, Sathya436ace72007-07-24 15:42:08 +05303482 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 +02003483 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3485
3486 while (fwSize--) {
3487 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3488 }
3489 nextImage = pExtImage->NextImageHeaderOffset;
3490 }
3491
3492 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303493 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3495
3496 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303497 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3499
3500 /* Clear the internal flash bad bit - autoincrementing register,
3501 * so must do two writes.
3502 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003503 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003504 /*
3505 * 1030 and 1035 H/W errata, workaround to access
3506 * the ClearFlashBadSignatureBit
3507 */
3508 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3509 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3510 diagRwData |= 0x40000000;
3511 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3512 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3513
3514 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3515 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3516 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3517 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3518
3519 /* wait 1 msec */
3520 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003521 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003522 } else {
3523 mdelay (1);
3524 }
3525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003527 if (ioc->errata_flag_1064)
3528 pci_disable_io_access(ioc->pcidev);
3529
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303531 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003532 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003534 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303535 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 ioc->name, diag0val));
3537 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3538
3539 /* Write 0xFF to reset the sequencer */
3540 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3541
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003542 if (ioc->bus_type == SAS) {
3543 ioc_state = mpt_GetIocState(ioc, 0);
3544 if ( (GetIocFacts(ioc, sleepFlag,
3545 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303546 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003547 ioc->name, ioc_state));
3548 return -EFAULT;
3549 }
3550 }
3551
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 for (count=0; count<HZ*20; count++) {
3553 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303554 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3555 "downloadboot successful! (count=%d) IocState=%x\n",
3556 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003557 if (ioc->bus_type == SAS) {
3558 return 0;
3559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303561 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3562 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 ioc->name));
3564 return -EFAULT;
3565 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303566 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3567 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 ioc->name));
3569 return 0;
3570 }
3571 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003572 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 } else {
3574 mdelay (10);
3575 }
3576 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303577 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3578 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 return -EFAULT;
3580}
3581
3582/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003583/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 * KickStart - Perform hard reset of MPT adapter.
3585 * @ioc: Pointer to MPT_ADAPTER structure
3586 * @force: Force hard reset
3587 * @sleepFlag: Specifies whether the process can sleep
3588 *
3589 * This routine places MPT adapter in diagnostic mode via the
3590 * WriteSequence register, and then performs a hard reset of adapter
3591 * via the Diagnostic register.
3592 *
3593 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3594 * or NO_SLEEP (interrupt thread, use mdelay)
3595 * force - 1 if doorbell active, board fault state
3596 * board operational, IOC_RECOVERY or
3597 * IOC_BRINGUP and there is an alt_ioc.
3598 * 0 else
3599 *
3600 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003601 * 1 - hard reset, READY
3602 * 0 - no reset due to History bit, READY
3603 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 * OR reset but failed to come READY
3605 * -2 - no reset, could not enter DIAG mode
3606 * -3 - reset but bad FW bit
3607 */
3608static int
3609KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3610{
3611 int hard_reset_done = 0;
3612 u32 ioc_state=0;
3613 int cnt,cntdn;
3614
Eric Moore29dd3602007-09-14 18:46:51 -06003615 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003616 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 /* Always issue a Msg Unit Reset first. This will clear some
3618 * SCSI bus hang conditions.
3619 */
3620 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3621
3622 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003623 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 } else {
3625 mdelay (1000);
3626 }
3627 }
3628
3629 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3630 if (hard_reset_done < 0)
3631 return hard_reset_done;
3632
Prakash, Sathya436ace72007-07-24 15:42:08 +05303633 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003634 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635
3636 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3637 for (cnt=0; cnt<cntdn; cnt++) {
3638 ioc_state = mpt_GetIocState(ioc, 1);
3639 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303640 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 ioc->name, cnt));
3642 return hard_reset_done;
3643 }
3644 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003645 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 } else {
3647 mdelay (10);
3648 }
3649 }
3650
Eric Moore29dd3602007-09-14 18:46:51 -06003651 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3652 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 return -1;
3654}
3655
3656/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003657/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 * mpt_diag_reset - Perform hard reset of the adapter.
3659 * @ioc: Pointer to MPT_ADAPTER structure
3660 * @ignore: Set if to honor and clear to ignore
3661 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003662 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 * else set to NO_SLEEP (use mdelay instead)
3664 *
3665 * This routine places the adapter in diagnostic mode via the
3666 * WriteSequence register and then performs a hard reset of adapter
3667 * via the Diagnostic register. Adapter should be in ready state
3668 * upon successful completion.
3669 *
3670 * Returns: 1 hard reset successful
3671 * 0 no reset performed because reset history bit set
3672 * -2 enabling diagnostic mode failed
3673 * -3 diagnostic reset failed
3674 */
3675static int
3676mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3677{
3678 u32 diag0val;
3679 u32 doorbell;
3680 int hard_reset_done = 0;
3681 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303683 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
Eric Moorecd2c6192007-01-29 09:47:47 -07003685 /* Clear any existing interrupts */
3686 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3687
Eric Moore87cf8982006-06-27 16:09:26 -06003688 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303689 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003690 "address=%p\n", ioc->name, __FUNCTION__,
3691 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3692 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3693 if (sleepFlag == CAN_SLEEP)
3694 msleep(1);
3695 else
3696 mdelay(1);
3697
3698 for (count = 0; count < 60; count ++) {
3699 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3700 doorbell &= MPI_IOC_STATE_MASK;
3701
Prakash, Sathya436ace72007-07-24 15:42:08 +05303702 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003703 "looking for READY STATE: doorbell=%x"
3704 " count=%d\n",
3705 ioc->name, doorbell, count));
3706 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003707 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003708 }
3709
3710 /* wait 1 sec */
3711 if (sleepFlag == CAN_SLEEP)
3712 msleep(1000);
3713 else
3714 mdelay(1000);
3715 }
3716 return -1;
3717 }
3718
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 /* Use "Diagnostic reset" method! (only thing available!) */
3720 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3721
Prakash, Sathya436ace72007-07-24 15:42:08 +05303722 if (ioc->debug_level & MPT_DEBUG) {
3723 if (ioc->alt_ioc)
3724 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3725 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728
3729 /* Do the reset if we are told to ignore the reset history
3730 * or if the reset history is 0
3731 */
3732 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3733 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3734 /* Write magic sequence to WriteSequence register
3735 * Loop until in diagnostic mode
3736 */
3737 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3738 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3739 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3740 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3741 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3742 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3743
3744 /* wait 100 msec */
3745 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003746 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 } else {
3748 mdelay (100);
3749 }
3750
3751 count++;
3752 if (count > 20) {
3753 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3754 ioc->name, diag0val);
3755 return -2;
3756
3757 }
3758
3759 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3760
Prakash, Sathya436ace72007-07-24 15:42:08 +05303761 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 ioc->name, diag0val));
3763 }
3764
Prakash, Sathya436ace72007-07-24 15:42:08 +05303765 if (ioc->debug_level & MPT_DEBUG) {
3766 if (ioc->alt_ioc)
3767 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3768 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 /*
3772 * Disable the ARM (Bug fix)
3773 *
3774 */
3775 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003776 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
3778 /*
3779 * Now hit the reset bit in the Diagnostic register
3780 * (THE BIG HAMMER!) (Clears DRWE bit).
3781 */
3782 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3783 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303784 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 ioc->name));
3786
3787 /*
3788 * Call each currently registered protocol IOC reset handler
3789 * with pre-reset indication.
3790 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3791 * MptResetHandlers[] registered yet.
3792 */
3793 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303794 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 int r = 0;
3796
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303797 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3798 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303799 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3800 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303801 ioc->name, cb_idx));
3802 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303804 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3805 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303806 ioc->name, ioc->alt_ioc->name, cb_idx));
3807 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 }
3809 }
3810 }
3811 /* FIXME? Examine results here? */
3812 }
3813
Eric Moore0ccdb002006-07-11 17:33:13 -06003814 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303815 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003816 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303817 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3818 else
3819 cached_fw = NULL;
3820 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 /* If the DownloadBoot operation fails, the
3822 * IOC will be left unusable. This is a fatal error
3823 * case. _diag_reset will return < 0
3824 */
3825 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303826 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3828 break;
3829 }
3830
Prakash, Sathya436ace72007-07-24 15:42:08 +05303831 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303832 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 /* wait 1 sec */
3834 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003835 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 } else {
3837 mdelay (1000);
3838 }
3839 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303840 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003841 printk(MYIOC_s_WARN_FMT
3842 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 }
3844
3845 } else {
3846 /* Wait for FW to reload and for board
3847 * to go to the READY state.
3848 * Maximum wait is 60 seconds.
3849 * If fail, no error will check again
3850 * with calling program.
3851 */
3852 for (count = 0; count < 60; count ++) {
3853 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3854 doorbell &= MPI_IOC_STATE_MASK;
3855
3856 if (doorbell == MPI_IOC_STATE_READY) {
3857 break;
3858 }
3859
3860 /* wait 1 sec */
3861 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003862 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 } else {
3864 mdelay (1000);
3865 }
3866 }
3867 }
3868 }
3869
3870 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303871 if (ioc->debug_level & MPT_DEBUG) {
3872 if (ioc->alt_ioc)
3873 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3874 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3875 ioc->name, diag0val, diag1val));
3876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877
3878 /* Clear RESET_HISTORY bit! Place board in the
3879 * diagnostic mode to update the diag register.
3880 */
3881 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3882 count = 0;
3883 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3884 /* Write magic sequence to WriteSequence register
3885 * Loop until in diagnostic mode
3886 */
3887 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3888 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3889 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3890 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3891 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3892 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3893
3894 /* wait 100 msec */
3895 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003896 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 } else {
3898 mdelay (100);
3899 }
3900
3901 count++;
3902 if (count > 20) {
3903 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3904 ioc->name, diag0val);
3905 break;
3906 }
3907 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3908 }
3909 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3910 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3911 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3912 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3913 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3914 ioc->name);
3915 }
3916
3917 /* Disable Diagnostic Mode
3918 */
3919 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3920
3921 /* Check FW reload status flags.
3922 */
3923 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3924 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3925 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3926 ioc->name, diag0val);
3927 return -3;
3928 }
3929
Prakash, Sathya436ace72007-07-24 15:42:08 +05303930 if (ioc->debug_level & MPT_DEBUG) {
3931 if (ioc->alt_ioc)
3932 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3933 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936
3937 /*
3938 * Reset flag that says we've enabled event notification
3939 */
3940 ioc->facts.EventState = 0;
3941
3942 if (ioc->alt_ioc)
3943 ioc->alt_ioc->facts.EventState = 0;
3944
3945 return hard_reset_done;
3946}
3947
3948/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003949/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 * SendIocReset - Send IOCReset request to MPT adapter.
3951 * @ioc: Pointer to MPT_ADAPTER structure
3952 * @reset_type: reset type, expected values are
3953 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003954 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 *
3956 * Send IOCReset request to the MPT adapter.
3957 *
3958 * Returns 0 for success, non-zero for failure.
3959 */
3960static int
3961SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3962{
3963 int r;
3964 u32 state;
3965 int cntdn, count;
3966
Prakash, Sathya436ace72007-07-24 15:42:08 +05303967 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 ioc->name, reset_type));
3969 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3970 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3971 return r;
3972
3973 /* FW ACK'd request, wait for READY state
3974 */
3975 count = 0;
3976 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3977
3978 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3979 cntdn--;
3980 count++;
3981 if (!cntdn) {
3982 if (sleepFlag != CAN_SLEEP)
3983 count *= 10;
3984
Eric Moore29dd3602007-09-14 18:46:51 -06003985 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3986 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 return -ETIME;
3988 }
3989
3990 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003991 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 } else {
3993 mdelay (1); /* 1 msec delay */
3994 }
3995 }
3996
3997 /* TODO!
3998 * Cleanup all event stuff for this IOC; re-issue EventNotification
3999 * request if needed.
4000 */
4001 if (ioc->facts.Function)
4002 ioc->facts.EventState = 0;
4003
4004 return 0;
4005}
4006
4007/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004008/**
4009 * initChainBuffers - Allocate memory for and initialize chain buffers
4010 * @ioc: Pointer to MPT_ADAPTER structure
4011 *
4012 * Allocates memory for and initializes chain buffers,
4013 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 */
4015static int
4016initChainBuffers(MPT_ADAPTER *ioc)
4017{
4018 u8 *mem;
4019 int sz, ii, num_chain;
4020 int scale, num_sge, numSGE;
4021
4022 /* ReqToChain size must equal the req_depth
4023 * index = req_idx
4024 */
4025 if (ioc->ReqToChain == NULL) {
4026 sz = ioc->req_depth * sizeof(int);
4027 mem = kmalloc(sz, GFP_ATOMIC);
4028 if (mem == NULL)
4029 return -1;
4030
4031 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304032 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 ioc->name, mem, sz));
4034 mem = kmalloc(sz, GFP_ATOMIC);
4035 if (mem == NULL)
4036 return -1;
4037
4038 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304039 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 ioc->name, mem, sz));
4041 }
4042 for (ii = 0; ii < ioc->req_depth; ii++) {
4043 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4044 }
4045
4046 /* ChainToChain size must equal the total number
4047 * of chain buffers to be allocated.
4048 * index = chain_idx
4049 *
4050 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004051 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 *
4053 * num_sge = num sge in request frame + last chain buffer
4054 * scale = num sge per chain buffer if no chain element
4055 */
4056 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
4057 if (sizeof(dma_addr_t) == sizeof(u64))
4058 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4059 else
4060 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4061
4062 if (sizeof(dma_addr_t) == sizeof(u64)) {
4063 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4064 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
4065 } else {
4066 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
4067 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
4068 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304069 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 ioc->name, num_sge, numSGE));
4071
4072 if ( numSGE > MPT_SCSI_SG_DEPTH )
4073 numSGE = MPT_SCSI_SG_DEPTH;
4074
4075 num_chain = 1;
4076 while (numSGE - num_sge > 0) {
4077 num_chain++;
4078 num_sge += (scale - 1);
4079 }
4080 num_chain++;
4081
Prakash, Sathya436ace72007-07-24 15:42:08 +05304082 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 ioc->name, numSGE, num_sge, num_chain));
4084
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004085 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086 num_chain *= MPT_SCSI_CAN_QUEUE;
4087 else
4088 num_chain *= MPT_FC_CAN_QUEUE;
4089
4090 ioc->num_chain = num_chain;
4091
4092 sz = num_chain * sizeof(int);
4093 if (ioc->ChainToChain == NULL) {
4094 mem = kmalloc(sz, GFP_ATOMIC);
4095 if (mem == NULL)
4096 return -1;
4097
4098 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304099 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 ioc->name, mem, sz));
4101 } else {
4102 mem = (u8 *) ioc->ChainToChain;
4103 }
4104 memset(mem, 0xFF, sz);
4105 return num_chain;
4106}
4107
4108/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004109/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4111 * @ioc: Pointer to MPT_ADAPTER structure
4112 *
4113 * This routine allocates memory for the MPT reply and request frame
4114 * pools (if necessary), and primes the IOC reply FIFO with
4115 * reply frames.
4116 *
4117 * Returns 0 for success, non-zero for failure.
4118 */
4119static int
4120PrimeIocFifos(MPT_ADAPTER *ioc)
4121{
4122 MPT_FRAME_HDR *mf;
4123 unsigned long flags;
4124 dma_addr_t alloc_dma;
4125 u8 *mem;
4126 int i, reply_sz, sz, total_size, num_chain;
4127
4128 /* Prime reply FIFO... */
4129
4130 if (ioc->reply_frames == NULL) {
4131 if ( (num_chain = initChainBuffers(ioc)) < 0)
4132 return -1;
4133
4134 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304135 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304137 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 ioc->name, reply_sz, reply_sz));
4139
4140 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304141 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304143 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 ioc->name, sz, sz));
4145 total_size += sz;
4146
4147 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304148 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304150 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 ioc->name, sz, sz, num_chain));
4152
4153 total_size += sz;
4154 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4155 if (mem == NULL) {
4156 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4157 ioc->name);
4158 goto out_fail;
4159 }
4160
Prakash, Sathya436ace72007-07-24 15:42:08 +05304161 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4163
4164 memset(mem, 0, total_size);
4165 ioc->alloc_total += total_size;
4166 ioc->alloc = mem;
4167 ioc->alloc_dma = alloc_dma;
4168 ioc->alloc_sz = total_size;
4169 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4170 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4171
Prakash, Sathya436ace72007-07-24 15:42:08 +05304172 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004173 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4174
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 alloc_dma += reply_sz;
4176 mem += reply_sz;
4177
4178 /* Request FIFO - WE manage this! */
4179
4180 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4181 ioc->req_frames_dma = alloc_dma;
4182
Prakash, Sathya436ace72007-07-24 15:42:08 +05304183 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 ioc->name, mem, (void *)(ulong)alloc_dma));
4185
4186 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4187
4188#if defined(CONFIG_MTRR) && 0
4189 /*
4190 * Enable Write Combining MTRR for IOC's memory region.
4191 * (at least as much as we can; "size and base must be
4192 * multiples of 4 kiB"
4193 */
4194 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4195 sz,
4196 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304197 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 ioc->name, ioc->req_frames_dma, sz));
4199#endif
4200
4201 for (i = 0; i < ioc->req_depth; i++) {
4202 alloc_dma += ioc->req_sz;
4203 mem += ioc->req_sz;
4204 }
4205
4206 ioc->ChainBuffer = mem;
4207 ioc->ChainBufferDMA = alloc_dma;
4208
Prakash, Sathya436ace72007-07-24 15:42:08 +05304209 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4211
4212 /* Initialize the free chain Q.
4213 */
4214
4215 INIT_LIST_HEAD(&ioc->FreeChainQ);
4216
4217 /* Post the chain buffers to the FreeChainQ.
4218 */
4219 mem = (u8 *)ioc->ChainBuffer;
4220 for (i=0; i < num_chain; i++) {
4221 mf = (MPT_FRAME_HDR *) mem;
4222 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4223 mem += ioc->req_sz;
4224 }
4225
4226 /* Initialize Request frames linked list
4227 */
4228 alloc_dma = ioc->req_frames_dma;
4229 mem = (u8 *) ioc->req_frames;
4230
4231 spin_lock_irqsave(&ioc->FreeQlock, flags);
4232 INIT_LIST_HEAD(&ioc->FreeQ);
4233 for (i = 0; i < ioc->req_depth; i++) {
4234 mf = (MPT_FRAME_HDR *) mem;
4235
4236 /* Queue REQUESTs *internally*! */
4237 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4238
4239 mem += ioc->req_sz;
4240 }
4241 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4242
4243 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4244 ioc->sense_buf_pool =
4245 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4246 if (ioc->sense_buf_pool == NULL) {
4247 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4248 ioc->name);
4249 goto out_fail;
4250 }
4251
4252 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4253 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304254 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4256
4257 }
4258
4259 /* Post Reply frames to FIFO
4260 */
4261 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304262 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4264
4265 for (i = 0; i < ioc->reply_depth; i++) {
4266 /* Write each address to the IOC! */
4267 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4268 alloc_dma += ioc->reply_sz;
4269 }
4270
4271 return 0;
4272
4273out_fail:
4274 if (ioc->alloc != NULL) {
4275 sz = ioc->alloc_sz;
4276 pci_free_consistent(ioc->pcidev,
4277 sz,
4278 ioc->alloc, ioc->alloc_dma);
4279 ioc->reply_frames = NULL;
4280 ioc->req_frames = NULL;
4281 ioc->alloc_total -= sz;
4282 }
4283 if (ioc->sense_buf_pool != NULL) {
4284 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4285 pci_free_consistent(ioc->pcidev,
4286 sz,
4287 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4288 ioc->sense_buf_pool = NULL;
4289 }
4290 return -1;
4291}
4292
4293/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4294/**
4295 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4296 * from IOC via doorbell handshake method.
4297 * @ioc: Pointer to MPT_ADAPTER structure
4298 * @reqBytes: Size of the request in bytes
4299 * @req: Pointer to MPT request frame
4300 * @replyBytes: Expected size of the reply in bytes
4301 * @u16reply: Pointer to area where reply should be written
4302 * @maxwait: Max wait time for a reply (in seconds)
4303 * @sleepFlag: Specifies whether the process can sleep
4304 *
4305 * NOTES: It is the callers responsibility to byte-swap fields in the
4306 * request which are greater than 1 byte in size. It is also the
4307 * callers responsibility to byte-swap response fields which are
4308 * greater than 1 byte in size.
4309 *
4310 * Returns 0 for success, non-zero for failure.
4311 */
4312static int
4313mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004314 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315{
4316 MPIDefaultReply_t *mptReply;
4317 int failcnt = 0;
4318 int t;
4319
4320 /*
4321 * Get ready to cache a handshake reply
4322 */
4323 ioc->hs_reply_idx = 0;
4324 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4325 mptReply->MsgLength = 0;
4326
4327 /*
4328 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4329 * then tell IOC that we want to handshake a request of N words.
4330 * (WRITE u32val to Doorbell reg).
4331 */
4332 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4333 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4334 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4335 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4336
4337 /*
4338 * Wait for IOC's doorbell handshake int
4339 */
4340 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4341 failcnt++;
4342
Prakash, Sathya436ace72007-07-24 15:42:08 +05304343 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4345
4346 /* Read doorbell and check for active bit */
4347 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4348 return -1;
4349
4350 /*
4351 * Clear doorbell int (WRITE 0 to IntStatus reg),
4352 * then wait for IOC to ACKnowledge that it's ready for
4353 * our handshake request.
4354 */
4355 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4356 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4357 failcnt++;
4358
4359 if (!failcnt) {
4360 int ii;
4361 u8 *req_as_bytes = (u8 *) req;
4362
4363 /*
4364 * Stuff request words via doorbell handshake,
4365 * with ACK from IOC for each.
4366 */
4367 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4368 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4369 (req_as_bytes[(ii*4) + 1] << 8) |
4370 (req_as_bytes[(ii*4) + 2] << 16) |
4371 (req_as_bytes[(ii*4) + 3] << 24));
4372
4373 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4374 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4375 failcnt++;
4376 }
4377
Prakash, Sathya436ace72007-07-24 15:42:08 +05304378 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004379 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380
Prakash, Sathya436ace72007-07-24 15:42:08 +05304381 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4383
4384 /*
4385 * Wait for completion of doorbell handshake reply from the IOC
4386 */
4387 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4388 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004389
Prakash, Sathya436ace72007-07-24 15:42:08 +05304390 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4392
4393 /*
4394 * Copy out the cached reply...
4395 */
4396 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4397 u16reply[ii] = ioc->hs_reply[ii];
4398 } else {
4399 return -99;
4400 }
4401
4402 return -failcnt;
4403}
4404
4405/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004406/**
4407 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 * @ioc: Pointer to MPT_ADAPTER structure
4409 * @howlong: How long to wait (in seconds)
4410 * @sleepFlag: Specifies whether the process can sleep
4411 *
4412 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004413 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4414 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 *
4416 * Returns a negative value on failure, else wait loop count.
4417 */
4418static int
4419WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4420{
4421 int cntdn;
4422 int count = 0;
4423 u32 intstat=0;
4424
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004425 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426
4427 if (sleepFlag == CAN_SLEEP) {
4428 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004429 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4431 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4432 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 count++;
4434 }
4435 } else {
4436 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004437 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4439 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4440 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 count++;
4442 }
4443 }
4444
4445 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304446 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 ioc->name, count));
4448 return count;
4449 }
4450
4451 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4452 ioc->name, count, intstat);
4453 return -1;
4454}
4455
4456/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004457/**
4458 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 * @ioc: Pointer to MPT_ADAPTER structure
4460 * @howlong: How long to wait (in seconds)
4461 * @sleepFlag: Specifies whether the process can sleep
4462 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004463 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4464 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 *
4466 * Returns a negative value on failure, else wait loop count.
4467 */
4468static int
4469WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4470{
4471 int cntdn;
4472 int count = 0;
4473 u32 intstat=0;
4474
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004475 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 if (sleepFlag == CAN_SLEEP) {
4477 while (--cntdn) {
4478 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4479 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4480 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004481 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 count++;
4483 }
4484 } else {
4485 while (--cntdn) {
4486 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4487 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4488 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004489 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 count++;
4491 }
4492 }
4493
4494 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304495 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 ioc->name, count, howlong));
4497 return count;
4498 }
4499
4500 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4501 ioc->name, count, intstat);
4502 return -1;
4503}
4504
4505/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004506/**
4507 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 * @ioc: Pointer to MPT_ADAPTER structure
4509 * @howlong: How long to wait (in seconds)
4510 * @sleepFlag: Specifies whether the process can sleep
4511 *
4512 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4513 * Reply is cached to IOC private area large enough to hold a maximum
4514 * of 128 bytes of reply data.
4515 *
4516 * Returns a negative value on failure, else size of reply in WORDS.
4517 */
4518static int
4519WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4520{
4521 int u16cnt = 0;
4522 int failcnt = 0;
4523 int t;
4524 u16 *hs_reply = ioc->hs_reply;
4525 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4526 u16 hword;
4527
4528 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4529
4530 /*
4531 * Get first two u16's so we can look at IOC's intended reply MsgLength
4532 */
4533 u16cnt=0;
4534 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4535 failcnt++;
4536 } else {
4537 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4538 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4539 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4540 failcnt++;
4541 else {
4542 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4543 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4544 }
4545 }
4546
Prakash, Sathya436ace72007-07-24 15:42:08 +05304547 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004548 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4550
4551 /*
4552 * If no error (and IOC said MsgLength is > 0), piece together
4553 * reply 16 bits at a time.
4554 */
4555 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4556 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4557 failcnt++;
4558 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4559 /* don't overflow our IOC hs_reply[] buffer! */
4560 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4561 hs_reply[u16cnt] = hword;
4562 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4563 }
4564
4565 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4566 failcnt++;
4567 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4568
4569 if (failcnt) {
4570 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4571 ioc->name);
4572 return -failcnt;
4573 }
4574#if 0
4575 else if (u16cnt != (2 * mptReply->MsgLength)) {
4576 return -101;
4577 }
4578 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4579 return -102;
4580 }
4581#endif
4582
Prakash, Sathya436ace72007-07-24 15:42:08 +05304583 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004584 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585
Prakash, Sathya436ace72007-07-24 15:42:08 +05304586 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587 ioc->name, t, u16cnt/2));
4588 return u16cnt/2;
4589}
4590
4591/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004592/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 * GetLanConfigPages - Fetch LANConfig pages.
4594 * @ioc: Pointer to MPT_ADAPTER structure
4595 *
4596 * Return: 0 for success
4597 * -ENOMEM if no memory available
4598 * -EPERM if not allowed due to ISR context
4599 * -EAGAIN if no msg frames currently available
4600 * -EFAULT for non-successful reply or no reply (timeout)
4601 */
4602static int
4603GetLanConfigPages(MPT_ADAPTER *ioc)
4604{
4605 ConfigPageHeader_t hdr;
4606 CONFIGPARMS cfg;
4607 LANPage0_t *ppage0_alloc;
4608 dma_addr_t page0_dma;
4609 LANPage1_t *ppage1_alloc;
4610 dma_addr_t page1_dma;
4611 int rc = 0;
4612 int data_sz;
4613 int copy_sz;
4614
4615 /* Get LAN Page 0 header */
4616 hdr.PageVersion = 0;
4617 hdr.PageLength = 0;
4618 hdr.PageNumber = 0;
4619 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004620 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 cfg.physAddr = -1;
4622 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4623 cfg.dir = 0;
4624 cfg.pageAddr = 0;
4625 cfg.timeout = 0;
4626
4627 if ((rc = mpt_config(ioc, &cfg)) != 0)
4628 return rc;
4629
4630 if (hdr.PageLength > 0) {
4631 data_sz = hdr.PageLength * 4;
4632 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4633 rc = -ENOMEM;
4634 if (ppage0_alloc) {
4635 memset((u8 *)ppage0_alloc, 0, data_sz);
4636 cfg.physAddr = page0_dma;
4637 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4638
4639 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4640 /* save the data */
4641 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4642 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4643
4644 }
4645
4646 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4647
4648 /* FIXME!
4649 * Normalize endianness of structure data,
4650 * by byte-swapping all > 1 byte fields!
4651 */
4652
4653 }
4654
4655 if (rc)
4656 return rc;
4657 }
4658
4659 /* Get LAN Page 1 header */
4660 hdr.PageVersion = 0;
4661 hdr.PageLength = 0;
4662 hdr.PageNumber = 1;
4663 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004664 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 cfg.physAddr = -1;
4666 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4667 cfg.dir = 0;
4668 cfg.pageAddr = 0;
4669
4670 if ((rc = mpt_config(ioc, &cfg)) != 0)
4671 return rc;
4672
4673 if (hdr.PageLength == 0)
4674 return 0;
4675
4676 data_sz = hdr.PageLength * 4;
4677 rc = -ENOMEM;
4678 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4679 if (ppage1_alloc) {
4680 memset((u8 *)ppage1_alloc, 0, data_sz);
4681 cfg.physAddr = page1_dma;
4682 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4683
4684 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4685 /* save the data */
4686 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4687 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4688 }
4689
4690 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4691
4692 /* FIXME!
4693 * Normalize endianness of structure data,
4694 * by byte-swapping all > 1 byte fields!
4695 */
4696
4697 }
4698
4699 return rc;
4700}
4701
4702/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004703/**
4704 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004705 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004706 * @persist_opcode: see below
4707 *
4708 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4709 * devices not currently present.
4710 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4711 *
4712 * NOTE: Don't use not this function during interrupt time.
4713 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004714 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004715 */
4716
4717/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4718int
4719mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4720{
4721 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4722 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4723 MPT_FRAME_HDR *mf = NULL;
4724 MPIHeader_t *mpi_hdr;
4725
4726
4727 /* insure garbage is not sent to fw */
4728 switch(persist_opcode) {
4729
4730 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4731 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4732 break;
4733
4734 default:
4735 return -1;
4736 break;
4737 }
4738
4739 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4740
4741 /* Get a MF for this command.
4742 */
4743 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4744 printk("%s: no msg frames!\n",__FUNCTION__);
4745 return -1;
4746 }
4747
4748 mpi_hdr = (MPIHeader_t *) mf;
4749 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4750 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4751 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4752 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4753 sasIoUnitCntrReq->Operation = persist_opcode;
4754
4755 init_timer(&ioc->persist_timer);
4756 ioc->persist_timer.data = (unsigned long) ioc;
4757 ioc->persist_timer.function = mpt_timer_expired;
4758 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4759 ioc->persist_wait_done=0;
4760 add_timer(&ioc->persist_timer);
4761 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4762 wait_event(mpt_waitq, ioc->persist_wait_done);
4763
4764 sasIoUnitCntrReply =
4765 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4766 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4767 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4768 __FUNCTION__,
4769 sasIoUnitCntrReply->IOCStatus,
4770 sasIoUnitCntrReply->IOCLogInfo);
4771 return -1;
4772 }
4773
4774 printk("%s: success\n",__FUNCTION__);
4775 return 0;
4776}
4777
4778/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004779
4780static void
4781mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4782 MpiEventDataRaid_t * pRaidEventData)
4783{
4784 int volume;
4785 int reason;
4786 int disk;
4787 int status;
4788 int flags;
4789 int state;
4790
4791 volume = pRaidEventData->VolumeID;
4792 reason = pRaidEventData->ReasonCode;
4793 disk = pRaidEventData->PhysDiskNum;
4794 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4795 flags = (status >> 0) & 0xff;
4796 state = (status >> 8) & 0xff;
4797
4798 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4799 return;
4800 }
4801
4802 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4803 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4804 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004805 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4806 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004807 } else {
4808 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4809 ioc->name, volume);
4810 }
4811
4812 switch(reason) {
4813 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4814 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4815 ioc->name);
4816 break;
4817
4818 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4819
4820 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4821 ioc->name);
4822 break;
4823
4824 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4825 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4826 ioc->name);
4827 break;
4828
4829 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4830 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4831 ioc->name,
4832 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4833 ? "optimal"
4834 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4835 ? "degraded"
4836 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4837 ? "failed"
4838 : "state unknown",
4839 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4840 ? ", enabled" : "",
4841 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4842 ? ", quiesced" : "",
4843 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4844 ? ", resync in progress" : "" );
4845 break;
4846
4847 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4848 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4849 ioc->name, disk);
4850 break;
4851
4852 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4853 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4854 ioc->name);
4855 break;
4856
4857 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4858 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4859 ioc->name);
4860 break;
4861
4862 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4863 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4864 ioc->name);
4865 break;
4866
4867 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4868 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4869 ioc->name,
4870 state == MPI_PHYSDISK0_STATUS_ONLINE
4871 ? "online"
4872 : state == MPI_PHYSDISK0_STATUS_MISSING
4873 ? "missing"
4874 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4875 ? "not compatible"
4876 : state == MPI_PHYSDISK0_STATUS_FAILED
4877 ? "failed"
4878 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4879 ? "initializing"
4880 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4881 ? "offline requested"
4882 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4883 ? "failed requested"
4884 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4885 ? "offline"
4886 : "state unknown",
4887 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4888 ? ", out of sync" : "",
4889 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4890 ? ", quiesced" : "" );
4891 break;
4892
4893 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4894 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4895 ioc->name, disk);
4896 break;
4897
4898 case MPI_EVENT_RAID_RC_SMART_DATA:
4899 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4900 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4901 break;
4902
4903 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4904 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4905 ioc->name, disk);
4906 break;
4907 }
4908}
4909
4910/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004911/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4913 * @ioc: Pointer to MPT_ADAPTER structure
4914 *
4915 * Returns: 0 for success
4916 * -ENOMEM if no memory available
4917 * -EPERM if not allowed due to ISR context
4918 * -EAGAIN if no msg frames currently available
4919 * -EFAULT for non-successful reply or no reply (timeout)
4920 */
4921static int
4922GetIoUnitPage2(MPT_ADAPTER *ioc)
4923{
4924 ConfigPageHeader_t hdr;
4925 CONFIGPARMS cfg;
4926 IOUnitPage2_t *ppage_alloc;
4927 dma_addr_t page_dma;
4928 int data_sz;
4929 int rc;
4930
4931 /* Get the page header */
4932 hdr.PageVersion = 0;
4933 hdr.PageLength = 0;
4934 hdr.PageNumber = 2;
4935 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004936 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 cfg.physAddr = -1;
4938 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4939 cfg.dir = 0;
4940 cfg.pageAddr = 0;
4941 cfg.timeout = 0;
4942
4943 if ((rc = mpt_config(ioc, &cfg)) != 0)
4944 return rc;
4945
4946 if (hdr.PageLength == 0)
4947 return 0;
4948
4949 /* Read the config page */
4950 data_sz = hdr.PageLength * 4;
4951 rc = -ENOMEM;
4952 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4953 if (ppage_alloc) {
4954 memset((u8 *)ppage_alloc, 0, data_sz);
4955 cfg.physAddr = page_dma;
4956 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4957
4958 /* If Good, save data */
4959 if ((rc = mpt_config(ioc, &cfg)) == 0)
4960 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4961
4962 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4963 }
4964
4965 return rc;
4966}
4967
4968/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004969/**
4970 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 * @ioc: Pointer to a Adapter Strucutre
4972 * @portnum: IOC port number
4973 *
4974 * Return: -EFAULT if read of config page header fails
4975 * or if no nvram
4976 * If read of SCSI Port Page 0 fails,
4977 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4978 * Adapter settings: async, narrow
4979 * Return 1
4980 * If read of SCSI Port Page 2 fails,
4981 * Adapter settings valid
4982 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4983 * Return 1
4984 * Else
4985 * Both valid
4986 * Return 0
4987 * CHECK - what type of locking mechanisms should be used????
4988 */
4989static int
4990mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4991{
4992 u8 *pbuf;
4993 dma_addr_t buf_dma;
4994 CONFIGPARMS cfg;
4995 ConfigPageHeader_t header;
4996 int ii;
4997 int data, rc = 0;
4998
4999 /* Allocate memory
5000 */
5001 if (!ioc->spi_data.nvram) {
5002 int sz;
5003 u8 *mem;
5004 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5005 mem = kmalloc(sz, GFP_ATOMIC);
5006 if (mem == NULL)
5007 return -EFAULT;
5008
5009 ioc->spi_data.nvram = (int *) mem;
5010
Prakash, Sathya436ace72007-07-24 15:42:08 +05305011 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 ioc->name, ioc->spi_data.nvram, sz));
5013 }
5014
5015 /* Invalidate NVRAM information
5016 */
5017 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5018 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5019 }
5020
5021 /* Read SPP0 header, allocate memory, then read page.
5022 */
5023 header.PageVersion = 0;
5024 header.PageLength = 0;
5025 header.PageNumber = 0;
5026 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005027 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 cfg.physAddr = -1;
5029 cfg.pageAddr = portnum;
5030 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5031 cfg.dir = 0;
5032 cfg.timeout = 0; /* use default */
5033 if (mpt_config(ioc, &cfg) != 0)
5034 return -EFAULT;
5035
5036 if (header.PageLength > 0) {
5037 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5038 if (pbuf) {
5039 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5040 cfg.physAddr = buf_dma;
5041 if (mpt_config(ioc, &cfg) != 0) {
5042 ioc->spi_data.maxBusWidth = MPT_NARROW;
5043 ioc->spi_data.maxSyncOffset = 0;
5044 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5045 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5046 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305047 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5048 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005049 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 } else {
5051 /* Save the Port Page 0 data
5052 */
5053 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5054 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5055 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5056
5057 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5058 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005059 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5060 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 ioc->name, pPP0->Capabilities));
5062 }
5063 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5064 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5065 if (data) {
5066 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5067 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5068 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305069 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5070 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005071 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 } else {
5073 ioc->spi_data.maxSyncOffset = 0;
5074 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5075 }
5076
5077 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5078
5079 /* Update the minSyncFactor based on bus type.
5080 */
5081 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5082 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5083
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005084 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305086 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5087 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005088 ioc->name, ioc->spi_data.minSyncFactor));
5089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 }
5091 }
5092 if (pbuf) {
5093 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5094 }
5095 }
5096 }
5097
5098 /* SCSI Port Page 2 - Read the header then the page.
5099 */
5100 header.PageVersion = 0;
5101 header.PageLength = 0;
5102 header.PageNumber = 2;
5103 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005104 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 cfg.physAddr = -1;
5106 cfg.pageAddr = portnum;
5107 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5108 cfg.dir = 0;
5109 if (mpt_config(ioc, &cfg) != 0)
5110 return -EFAULT;
5111
5112 if (header.PageLength > 0) {
5113 /* Allocate memory and read SCSI Port Page 2
5114 */
5115 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5116 if (pbuf) {
5117 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5118 cfg.physAddr = buf_dma;
5119 if (mpt_config(ioc, &cfg) != 0) {
5120 /* Nvram data is left with INVALID mark
5121 */
5122 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005123 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5124
5125 /* This is an ATTO adapter, read Page2 accordingly
5126 */
5127 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5128 ATTODeviceInfo_t *pdevice = NULL;
5129 u16 ATTOFlags;
5130
5131 /* Save the Port Page 2 data
5132 * (reformat into a 32bit quantity)
5133 */
5134 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5135 pdevice = &pPP2->DeviceSettings[ii];
5136 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5137 data = 0;
5138
5139 /* Translate ATTO device flags to LSI format
5140 */
5141 if (ATTOFlags & ATTOFLAG_DISC)
5142 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5143 if (ATTOFlags & ATTOFLAG_ID_ENB)
5144 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5145 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5146 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5147 if (ATTOFlags & ATTOFLAG_TAGGED)
5148 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5149 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5150 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5151
5152 data = (data << 16) | (pdevice->Period << 8) | 10;
5153 ioc->spi_data.nvram[ii] = data;
5154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 } else {
5156 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5157 MpiDeviceInfo_t *pdevice = NULL;
5158
Moore, Ericd8e925d2006-01-16 18:53:06 -07005159 /*
5160 * Save "Set to Avoid SCSI Bus Resets" flag
5161 */
5162 ioc->spi_data.bus_reset =
5163 (le32_to_cpu(pPP2->PortFlags) &
5164 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5165 0 : 1 ;
5166
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 /* Save the Port Page 2 data
5168 * (reformat into a 32bit quantity)
5169 */
5170 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5171 ioc->spi_data.PortFlags = data;
5172 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5173 pdevice = &pPP2->DeviceSettings[ii];
5174 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5175 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5176 ioc->spi_data.nvram[ii] = data;
5177 }
5178 }
5179
5180 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5181 }
5182 }
5183
5184 /* Update Adapter limits with those from NVRAM
5185 * Comment: Don't need to do this. Target performance
5186 * parameters will never exceed the adapters limits.
5187 */
5188
5189 return rc;
5190}
5191
5192/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005193/**
5194 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 * @ioc: Pointer to a Adapter Strucutre
5196 * @portnum: IOC port number
5197 *
5198 * Return: -EFAULT if read of config page header fails
5199 * or 0 if success.
5200 */
5201static int
5202mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5203{
5204 CONFIGPARMS cfg;
5205 ConfigPageHeader_t header;
5206
5207 /* Read the SCSI Device Page 1 header
5208 */
5209 header.PageVersion = 0;
5210 header.PageLength = 0;
5211 header.PageNumber = 1;
5212 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005213 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 cfg.physAddr = -1;
5215 cfg.pageAddr = portnum;
5216 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5217 cfg.dir = 0;
5218 cfg.timeout = 0;
5219 if (mpt_config(ioc, &cfg) != 0)
5220 return -EFAULT;
5221
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005222 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5223 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224
5225 header.PageVersion = 0;
5226 header.PageLength = 0;
5227 header.PageNumber = 0;
5228 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5229 if (mpt_config(ioc, &cfg) != 0)
5230 return -EFAULT;
5231
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005232 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5233 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234
Prakash, Sathya436ace72007-07-24 15:42:08 +05305235 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5237
Prakash, Sathya436ace72007-07-24 15:42:08 +05305238 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5240 return 0;
5241}
5242
Eric Mooreb506ade2007-01-29 09:45:37 -07005243/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005244 * mpt_inactive_raid_list_free - This clears this link list.
5245 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005246 **/
5247static void
5248mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5249{
5250 struct inactive_raid_component_info *component_info, *pNext;
5251
5252 if (list_empty(&ioc->raid_data.inactive_list))
5253 return;
5254
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005255 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005256 list_for_each_entry_safe(component_info, pNext,
5257 &ioc->raid_data.inactive_list, list) {
5258 list_del(&component_info->list);
5259 kfree(component_info);
5260 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005261 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005262}
5263
5264/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005265 * 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 -07005266 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005267 * @ioc : pointer to per adapter structure
5268 * @channel : volume channel
5269 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005270 **/
5271static void
5272mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5273{
5274 CONFIGPARMS cfg;
5275 ConfigPageHeader_t hdr;
5276 dma_addr_t dma_handle;
5277 pRaidVolumePage0_t buffer = NULL;
5278 int i;
5279 RaidPhysDiskPage0_t phys_disk;
5280 struct inactive_raid_component_info *component_info;
5281 int handle_inactive_volumes;
5282
5283 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5284 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5285 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5286 cfg.pageAddr = (channel << 8) + id;
5287 cfg.cfghdr.hdr = &hdr;
5288 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5289
5290 if (mpt_config(ioc, &cfg) != 0)
5291 goto out;
5292
5293 if (!hdr.PageLength)
5294 goto out;
5295
5296 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5297 &dma_handle);
5298
5299 if (!buffer)
5300 goto out;
5301
5302 cfg.physAddr = dma_handle;
5303 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5304
5305 if (mpt_config(ioc, &cfg) != 0)
5306 goto out;
5307
5308 if (!buffer->NumPhysDisks)
5309 goto out;
5310
5311 handle_inactive_volumes =
5312 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5313 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5314 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5315 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5316
5317 if (!handle_inactive_volumes)
5318 goto out;
5319
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005320 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005321 for (i = 0; i < buffer->NumPhysDisks; i++) {
5322 if(mpt_raid_phys_disk_pg0(ioc,
5323 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5324 continue;
5325
5326 if ((component_info = kmalloc(sizeof (*component_info),
5327 GFP_KERNEL)) == NULL)
5328 continue;
5329
5330 component_info->volumeID = id;
5331 component_info->volumeBus = channel;
5332 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5333 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5334 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5335 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5336
5337 list_add_tail(&component_info->list,
5338 &ioc->raid_data.inactive_list);
5339 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005340 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005341
5342 out:
5343 if (buffer)
5344 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5345 dma_handle);
5346}
5347
5348/**
5349 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5350 * @ioc: Pointer to a Adapter Structure
5351 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5352 * @phys_disk: requested payload data returned
5353 *
5354 * Return:
5355 * 0 on success
5356 * -EFAULT if read of config page header fails or data pointer not NULL
5357 * -ENOMEM if pci_alloc failed
5358 **/
5359int
5360mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5361{
5362 CONFIGPARMS cfg;
5363 ConfigPageHeader_t hdr;
5364 dma_addr_t dma_handle;
5365 pRaidPhysDiskPage0_t buffer = NULL;
5366 int rc;
5367
5368 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5369 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5370
5371 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5372 cfg.cfghdr.hdr = &hdr;
5373 cfg.physAddr = -1;
5374 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5375
5376 if (mpt_config(ioc, &cfg) != 0) {
5377 rc = -EFAULT;
5378 goto out;
5379 }
5380
5381 if (!hdr.PageLength) {
5382 rc = -EFAULT;
5383 goto out;
5384 }
5385
5386 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5387 &dma_handle);
5388
5389 if (!buffer) {
5390 rc = -ENOMEM;
5391 goto out;
5392 }
5393
5394 cfg.physAddr = dma_handle;
5395 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5396 cfg.pageAddr = phys_disk_num;
5397
5398 if (mpt_config(ioc, &cfg) != 0) {
5399 rc = -EFAULT;
5400 goto out;
5401 }
5402
5403 rc = 0;
5404 memcpy(phys_disk, buffer, sizeof(*buffer));
5405 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5406
5407 out:
5408
5409 if (buffer)
5410 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5411 dma_handle);
5412
5413 return rc;
5414}
5415
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416/**
5417 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5418 * @ioc: Pointer to a Adapter Strucutre
5419 * @portnum: IOC port number
5420 *
5421 * Return:
5422 * 0 on success
5423 * -EFAULT if read of config page header fails or data pointer not NULL
5424 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005425 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426int
5427mpt_findImVolumes(MPT_ADAPTER *ioc)
5428{
5429 IOCPage2_t *pIoc2;
5430 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 dma_addr_t ioc2_dma;
5432 CONFIGPARMS cfg;
5433 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 int rc = 0;
5435 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005436 int i;
5437
5438 if (!ioc->ir_firmware)
5439 return 0;
5440
5441 /* Free the old page
5442 */
5443 kfree(ioc->raid_data.pIocPg2);
5444 ioc->raid_data.pIocPg2 = NULL;
5445 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446
5447 /* Read IOCP2 header then the page.
5448 */
5449 header.PageVersion = 0;
5450 header.PageLength = 0;
5451 header.PageNumber = 2;
5452 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005453 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 cfg.physAddr = -1;
5455 cfg.pageAddr = 0;
5456 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5457 cfg.dir = 0;
5458 cfg.timeout = 0;
5459 if (mpt_config(ioc, &cfg) != 0)
5460 return -EFAULT;
5461
5462 if (header.PageLength == 0)
5463 return -EFAULT;
5464
5465 iocpage2sz = header.PageLength * 4;
5466 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5467 if (!pIoc2)
5468 return -ENOMEM;
5469
5470 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5471 cfg.physAddr = ioc2_dma;
5472 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005473 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474
Eric Mooreb506ade2007-01-29 09:45:37 -07005475 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5476 if (!mem)
5477 goto out;
5478
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005480 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481
Eric Mooreb506ade2007-01-29 09:45:37 -07005482 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483
Eric Mooreb506ade2007-01-29 09:45:37 -07005484 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5485 mpt_inactive_raid_volumes(ioc,
5486 pIoc2->RaidVolume[i].VolumeBus,
5487 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
Eric Mooreb506ade2007-01-29 09:45:37 -07005489 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5491
5492 return rc;
5493}
5494
Moore, Ericc972c702006-03-14 09:14:06 -07005495static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5497{
5498 IOCPage3_t *pIoc3;
5499 u8 *mem;
5500 CONFIGPARMS cfg;
5501 ConfigPageHeader_t header;
5502 dma_addr_t ioc3_dma;
5503 int iocpage3sz = 0;
5504
5505 /* Free the old page
5506 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005507 kfree(ioc->raid_data.pIocPg3);
5508 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509
5510 /* There is at least one physical disk.
5511 * Read and save IOC Page 3
5512 */
5513 header.PageVersion = 0;
5514 header.PageLength = 0;
5515 header.PageNumber = 3;
5516 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005517 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 cfg.physAddr = -1;
5519 cfg.pageAddr = 0;
5520 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5521 cfg.dir = 0;
5522 cfg.timeout = 0;
5523 if (mpt_config(ioc, &cfg) != 0)
5524 return 0;
5525
5526 if (header.PageLength == 0)
5527 return 0;
5528
5529 /* Read Header good, alloc memory
5530 */
5531 iocpage3sz = header.PageLength * 4;
5532 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5533 if (!pIoc3)
5534 return 0;
5535
5536 /* Read the Page and save the data
5537 * into malloc'd memory.
5538 */
5539 cfg.physAddr = ioc3_dma;
5540 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5541 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005542 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 if (mem) {
5544 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005545 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 }
5547 }
5548
5549 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5550
5551 return 0;
5552}
5553
5554static void
5555mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5556{
5557 IOCPage4_t *pIoc4;
5558 CONFIGPARMS cfg;
5559 ConfigPageHeader_t header;
5560 dma_addr_t ioc4_dma;
5561 int iocpage4sz;
5562
5563 /* Read and save IOC Page 4
5564 */
5565 header.PageVersion = 0;
5566 header.PageLength = 0;
5567 header.PageNumber = 4;
5568 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005569 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 cfg.physAddr = -1;
5571 cfg.pageAddr = 0;
5572 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5573 cfg.dir = 0;
5574 cfg.timeout = 0;
5575 if (mpt_config(ioc, &cfg) != 0)
5576 return;
5577
5578 if (header.PageLength == 0)
5579 return;
5580
5581 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5582 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5583 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5584 if (!pIoc4)
5585 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005586 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 } else {
5588 ioc4_dma = ioc->spi_data.IocPg4_dma;
5589 iocpage4sz = ioc->spi_data.IocPg4Sz;
5590 }
5591
5592 /* Read the Page into dma memory.
5593 */
5594 cfg.physAddr = ioc4_dma;
5595 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5596 if (mpt_config(ioc, &cfg) == 0) {
5597 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5598 ioc->spi_data.IocPg4_dma = ioc4_dma;
5599 ioc->spi_data.IocPg4Sz = iocpage4sz;
5600 } else {
5601 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5602 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005603 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 }
5605}
5606
5607static void
5608mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5609{
5610 IOCPage1_t *pIoc1;
5611 CONFIGPARMS cfg;
5612 ConfigPageHeader_t header;
5613 dma_addr_t ioc1_dma;
5614 int iocpage1sz = 0;
5615 u32 tmp;
5616
5617 /* Check the Coalescing Timeout in IOC Page 1
5618 */
5619 header.PageVersion = 0;
5620 header.PageLength = 0;
5621 header.PageNumber = 1;
5622 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005623 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 cfg.physAddr = -1;
5625 cfg.pageAddr = 0;
5626 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5627 cfg.dir = 0;
5628 cfg.timeout = 0;
5629 if (mpt_config(ioc, &cfg) != 0)
5630 return;
5631
5632 if (header.PageLength == 0)
5633 return;
5634
5635 /* Read Header good, alloc memory
5636 */
5637 iocpage1sz = header.PageLength * 4;
5638 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5639 if (!pIoc1)
5640 return;
5641
5642 /* Read the Page and check coalescing timeout
5643 */
5644 cfg.physAddr = ioc1_dma;
5645 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5646 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305647
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5649 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5650 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5651
Prakash, Sathya436ace72007-07-24 15:42:08 +05305652 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 ioc->name, tmp));
5654
5655 if (tmp > MPT_COALESCING_TIMEOUT) {
5656 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5657
5658 /* Write NVRAM and current
5659 */
5660 cfg.dir = 1;
5661 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5662 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305663 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 ioc->name, MPT_COALESCING_TIMEOUT));
5665
5666 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5667 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305668 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5669 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 ioc->name, MPT_COALESCING_TIMEOUT));
5671 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305672 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5673 "Reset NVRAM Coalescing Timeout Failed\n",
5674 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 }
5676
5677 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305678 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5679 "Reset of Current Coalescing Timeout Failed!\n",
5680 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 }
5682 }
5683
5684 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305685 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 }
5687 }
5688
5689 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5690
5691 return;
5692}
5693
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305694static void
5695mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5696{
5697 CONFIGPARMS cfg;
5698 ConfigPageHeader_t hdr;
5699 dma_addr_t buf_dma;
5700 ManufacturingPage0_t *pbuf = NULL;
5701
5702 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5703 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5704
5705 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5706 cfg.cfghdr.hdr = &hdr;
5707 cfg.physAddr = -1;
5708 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5709 cfg.timeout = 10;
5710
5711 if (mpt_config(ioc, &cfg) != 0)
5712 goto out;
5713
5714 if (!cfg.cfghdr.hdr->PageLength)
5715 goto out;
5716
5717 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5718 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5719 if (!pbuf)
5720 goto out;
5721
5722 cfg.physAddr = buf_dma;
5723
5724 if (mpt_config(ioc, &cfg) != 0)
5725 goto out;
5726
5727 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5728 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5729 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5730
5731 out:
5732
5733 if (pbuf)
5734 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5735}
5736
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005738/**
5739 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740 * @ioc: Pointer to MPT_ADAPTER structure
5741 * @EvSwitch: Event switch flags
5742 */
5743static int
5744SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5745{
5746 EventNotification_t *evnp;
5747
5748 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5749 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305750 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751 ioc->name));
5752 return 0;
5753 }
5754 memset(evnp, 0, sizeof(*evnp));
5755
Prakash, Sathya436ace72007-07-24 15:42:08 +05305756 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757
5758 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5759 evnp->ChainOffset = 0;
5760 evnp->MsgFlags = 0;
5761 evnp->Switch = EvSwitch;
5762
5763 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5764
5765 return 0;
5766}
5767
5768/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5769/**
5770 * SendEventAck - Send EventAck request to MPT adapter.
5771 * @ioc: Pointer to MPT_ADAPTER structure
5772 * @evnp: Pointer to original EventNotification request
5773 */
5774static int
5775SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5776{
5777 EventAck_t *pAck;
5778
5779 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305780 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005781 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 return -1;
5783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784
Prakash, Sathya436ace72007-07-24 15:42:08 +05305785 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786
5787 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5788 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005789 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005791 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 pAck->Event = evnp->Event;
5793 pAck->EventContext = evnp->EventContext;
5794
5795 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5796
5797 return 0;
5798}
5799
5800/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5801/**
5802 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005803 * @ioc: Pointer to an adapter structure
5804 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805 * action, page address, direction, physical address
5806 * and pointer to a configuration page header
5807 * Page header is updated.
5808 *
5809 * Returns 0 for success
5810 * -EPERM if not allowed due to ISR context
5811 * -EAGAIN if no msg frames currently available
5812 * -EFAULT for non-successful reply or no reply (timeout)
5813 */
5814int
5815mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5816{
5817 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005818 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819 MPT_FRAME_HDR *mf;
5820 unsigned long flags;
5821 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005822 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823 int in_isr;
5824
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005825 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 * to be in ISR context, because that is fatal!
5827 */
5828 in_isr = in_interrupt();
5829 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305830 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 ioc->name));
5832 return -EPERM;
5833 }
5834
5835 /* Get and Populate a free Frame
5836 */
5837 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305838 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839 ioc->name));
5840 return -EAGAIN;
5841 }
5842 pReq = (Config_t *)mf;
5843 pReq->Action = pCfg->action;
5844 pReq->Reserved = 0;
5845 pReq->ChainOffset = 0;
5846 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005847
5848 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005849 pReq->ExtPageLength = 0;
5850 pReq->ExtPageType = 0;
5851 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005852
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853 for (ii=0; ii < 8; ii++)
5854 pReq->Reserved2[ii] = 0;
5855
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005856 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5857 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5858 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5859 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5860
5861 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5862 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5863 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5864 pReq->ExtPageType = pExtHdr->ExtPageType;
5865 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5866
5867 /* Page Length must be treated as a reserved field for the extended header. */
5868 pReq->Header.PageLength = 0;
5869 }
5870
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5872
5873 /* Add a SGE to the config request.
5874 */
5875 if (pCfg->dir)
5876 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5877 else
5878 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5879
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005880 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5881 flagsLength |= pExtHdr->ExtPageLength * 4;
5882
Prakash, Sathya436ace72007-07-24 15:42:08 +05305883 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 +02005884 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5885 }
5886 else {
5887 flagsLength |= pCfg->cfghdr.hdr->PageLength * 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->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892
5893 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5894
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895 /* Append pCfg pointer to end of mf
5896 */
5897 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5898
5899 /* Initalize the timer
5900 */
5901 init_timer(&pCfg->timer);
5902 pCfg->timer.data = (unsigned long) ioc;
5903 pCfg->timer.function = mpt_timer_expired;
5904 pCfg->wait_done = 0;
5905
5906 /* Set the timer; ensure 10 second minimum */
5907 if (pCfg->timeout < 10)
5908 pCfg->timer.expires = jiffies + HZ*10;
5909 else
5910 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5911
5912 /* Add to end of Q, set timer and then issue this command */
5913 spin_lock_irqsave(&ioc->FreeQlock, flags);
5914 list_add_tail(&pCfg->linkage, &ioc->configQ);
5915 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5916
5917 add_timer(&pCfg->timer);
5918 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5919 wait_event(mpt_waitq, pCfg->wait_done);
5920
5921 /* mf has been freed - do not access */
5922
5923 rc = pCfg->status;
5924
5925 return rc;
5926}
5927
5928/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005929/**
5930 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 * Used only internal config functionality.
5932 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5933 */
5934static void
5935mpt_timer_expired(unsigned long data)
5936{
5937 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5938
Prakash, Sathya436ace72007-07-24 15:42:08 +05305939 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940
5941 /* Perform a FW reload */
5942 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5943 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5944
5945 /* No more processing.
5946 * Hard reset clean-up will wake up
5947 * process and free all resources.
5948 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305949 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950
5951 return;
5952}
5953
5954/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005955/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 * mpt_ioc_reset - Base cleanup for hard reset
5957 * @ioc: Pointer to the adapter structure
5958 * @reset_phase: Indicates pre- or post-reset functionality
5959 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005960 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 */
5962static int
5963mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5964{
5965 CONFIGPARMS *pCfg;
5966 unsigned long flags;
5967
Eric Moore29dd3602007-09-14 18:46:51 -06005968 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5969 ": IOC %s_reset routed to MPT base driver!\n",
5970 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5971 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972
5973 if (reset_phase == MPT_IOC_SETUP_RESET) {
5974 ;
5975 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5976 /* If the internal config Q is not empty -
5977 * delete timer. MF resources will be freed when
5978 * the FIFO's are primed.
5979 */
5980 spin_lock_irqsave(&ioc->FreeQlock, flags);
5981 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5982 del_timer(&pCfg->timer);
5983 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5984
5985 } else {
5986 CONFIGPARMS *pNext;
5987
5988 /* Search the configQ for internal commands.
5989 * Flush the Q, and wake up all suspended threads.
5990 */
5991 spin_lock_irqsave(&ioc->FreeQlock, flags);
5992 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5993 list_del(&pCfg->linkage);
5994
5995 pCfg->status = MPT_CONFIG_ERROR;
5996 pCfg->wait_done = 1;
5997 wake_up(&mpt_waitq);
5998 }
5999 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6000 }
6001
6002 return 1; /* currently means nothing really */
6003}
6004
6005
6006#ifdef CONFIG_PROC_FS /* { */
6007/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6008/*
6009 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6010 */
6011/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006012/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6014 *
6015 * Returns 0 for success, non-zero for failure.
6016 */
6017static int
6018procmpt_create(void)
6019{
6020 struct proc_dir_entry *ent;
6021
6022 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6023 if (mpt_proc_root_dir == NULL)
6024 return -ENOTDIR;
6025
6026 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6027 if (ent)
6028 ent->read_proc = procmpt_summary_read;
6029
6030 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6031 if (ent)
6032 ent->read_proc = procmpt_version_read;
6033
6034 return 0;
6035}
6036
6037/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006038/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6040 *
6041 * Returns 0 for success, non-zero for failure.
6042 */
6043static void
6044procmpt_destroy(void)
6045{
6046 remove_proc_entry("version", mpt_proc_root_dir);
6047 remove_proc_entry("summary", mpt_proc_root_dir);
6048 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6049}
6050
6051/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006052/**
6053 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054 * @buf: Pointer to area to write information
6055 * @start: Pointer to start pointer
6056 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006057 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058 * @eof: Pointer to EOF integer
6059 * @data: Pointer
6060 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006061 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062 * Returns number of characters written to process performing the read.
6063 */
6064static int
6065procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6066{
6067 MPT_ADAPTER *ioc;
6068 char *out = buf;
6069 int len;
6070
6071 if (data) {
6072 int more = 0;
6073
6074 ioc = data;
6075 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6076
6077 out += more;
6078 } else {
6079 list_for_each_entry(ioc, &ioc_list, list) {
6080 int more = 0;
6081
6082 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6083
6084 out += more;
6085 if ((out-buf) >= request)
6086 break;
6087 }
6088 }
6089
6090 len = out - buf;
6091
6092 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6093}
6094
6095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006096/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097 * procmpt_version_read - Handle read request from /proc/mpt/version.
6098 * @buf: Pointer to area to write information
6099 * @start: Pointer to start pointer
6100 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006101 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 * @eof: Pointer to EOF integer
6103 * @data: Pointer
6104 *
6105 * Returns number of characters written to process performing the read.
6106 */
6107static int
6108procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6109{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306110 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006111 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112 char *drvname;
6113 int len;
6114
6115 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6116 len += sprintf(buf+len, " Fusion MPT base driver\n");
6117
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006118 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006119 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306121 if (MptCallbacks[cb_idx]) {
6122 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006123 case MPTSPI_DRIVER:
6124 if (!scsi++) drvname = "SPI host";
6125 break;
6126 case MPTFC_DRIVER:
6127 if (!fc++) drvname = "FC host";
6128 break;
6129 case MPTSAS_DRIVER:
6130 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131 break;
6132 case MPTLAN_DRIVER:
6133 if (!lan++) drvname = "LAN";
6134 break;
6135 case MPTSTM_DRIVER:
6136 if (!targ++) drvname = "SCSI target";
6137 break;
6138 case MPTCTL_DRIVER:
6139 if (!ctl++) drvname = "ioctl";
6140 break;
6141 }
6142
6143 if (drvname)
6144 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6145 }
6146 }
6147
6148 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6149}
6150
6151/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006152/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6154 * @buf: Pointer to area to write information
6155 * @start: Pointer to start pointer
6156 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006157 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 * @eof: Pointer to EOF integer
6159 * @data: Pointer
6160 *
6161 * Returns number of characters written to process performing the read.
6162 */
6163static int
6164procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6165{
6166 MPT_ADAPTER *ioc = data;
6167 int len;
6168 char expVer[32];
6169 int sz;
6170 int p;
6171
6172 mpt_get_fw_exp_ver(expVer, ioc);
6173
6174 len = sprintf(buf, "%s:", ioc->name);
6175 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6176 len += sprintf(buf+len, " (f/w download boot flag set)");
6177// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6178// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6179
6180 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6181 ioc->facts.ProductID,
6182 ioc->prod_name);
6183 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6184 if (ioc->facts.FWImageSize)
6185 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6186 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6187 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6188 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6189
6190 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6191 ioc->facts.CurrentHostMfaHighAddr);
6192 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6193 ioc->facts.CurrentSenseBufferHighAddr);
6194
6195 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6196 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6197
6198 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6199 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6200 /*
6201 * Rounding UP to nearest 4-kB boundary here...
6202 */
6203 sz = (ioc->req_sz * ioc->req_depth) + 128;
6204 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6205 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6206 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6207 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6208 4*ioc->facts.RequestFrameSize,
6209 ioc->facts.GlobalCredits);
6210
6211 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6212 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6213 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6214 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6215 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6216 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6217 ioc->facts.CurReplyFrameSize,
6218 ioc->facts.ReplyQueueDepth);
6219
6220 len += sprintf(buf+len, " MaxDevices = %d\n",
6221 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6222 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6223
6224 /* per-port info */
6225 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6226 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6227 p+1,
6228 ioc->facts.NumberOfPorts);
6229 if (ioc->bus_type == FC) {
6230 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6231 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6232 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6233 a[5], a[4], a[3], a[2], a[1], a[0]);
6234 }
6235 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6236 ioc->fc_port_page0[p].WWNN.High,
6237 ioc->fc_port_page0[p].WWNN.Low,
6238 ioc->fc_port_page0[p].WWPN.High,
6239 ioc->fc_port_page0[p].WWPN.Low);
6240 }
6241 }
6242
6243 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6244}
6245
6246#endif /* CONFIG_PROC_FS } */
6247
6248/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6249static void
6250mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6251{
6252 buf[0] ='\0';
6253 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6254 sprintf(buf, " (Exp %02d%02d)",
6255 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6256 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6257
6258 /* insider hack! */
6259 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6260 strcat(buf, " [MDBG]");
6261 }
6262}
6263
6264/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6265/**
6266 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6267 * @ioc: Pointer to MPT_ADAPTER structure
6268 * @buffer: Pointer to buffer where IOC summary info should be written
6269 * @size: Pointer to number of bytes we wrote (set by this routine)
6270 * @len: Offset at which to start writing in buffer
6271 * @showlan: Display LAN stuff?
6272 *
6273 * This routine writes (english readable) ASCII text, which represents
6274 * a summary of IOC information, to a buffer.
6275 */
6276void
6277mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6278{
6279 char expVer[32];
6280 int y;
6281
6282 mpt_get_fw_exp_ver(expVer, ioc);
6283
6284 /*
6285 * Shorter summary of attached ioc's...
6286 */
6287 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6288 ioc->name,
6289 ioc->prod_name,
6290 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6291 ioc->facts.FWVersion.Word,
6292 expVer,
6293 ioc->facts.NumberOfPorts,
6294 ioc->req_depth);
6295
6296 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6297 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6298 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6299 a[5], a[4], a[3], a[2], a[1], a[0]);
6300 }
6301
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303
6304 if (!ioc->active)
6305 y += sprintf(buffer+len+y, " (disabled)");
6306
6307 y += sprintf(buffer+len+y, "\n");
6308
6309 *size = y;
6310}
6311
6312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6313/*
6314 * Reset Handling
6315 */
6316/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6317/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006318 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 * @ioc: Pointer to MPT_ADAPTER structure
6320 * @sleepFlag: Indicates if sleep or schedule must be called.
6321 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006322 * Issues SCSI Task Management call based on input arg values.
6323 * If TaskMgmt fails, returns associated SCSI request.
6324 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6326 * or a non-interrupt thread. In the former, must not call schedule().
6327 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006328 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006329 * FW reload/initialization failed.
6330 *
6331 * Returns 0 for SUCCESS or -1 if FAILED.
6332 */
6333int
6334mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6335{
6336 int rc;
6337 unsigned long flags;
6338
Prakash, Sathya436ace72007-07-24 15:42:08 +05306339 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340#ifdef MFCNT
6341 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6342 printk("MF count 0x%x !\n", ioc->mfcnt);
6343#endif
6344
6345 /* Reset the adapter. Prevent more than 1 call to
6346 * mpt_do_ioc_recovery at any instant in time.
6347 */
6348 spin_lock_irqsave(&ioc->diagLock, flags);
6349 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6350 spin_unlock_irqrestore(&ioc->diagLock, flags);
6351 return 0;
6352 } else {
6353 ioc->diagPending = 1;
6354 }
6355 spin_unlock_irqrestore(&ioc->diagLock, flags);
6356
6357 /* FIXME: If do_ioc_recovery fails, repeat....
6358 */
6359
6360 /* The SCSI driver needs to adjust timeouts on all current
6361 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006362 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 * For all other protocol drivers, this is a no-op.
6364 */
6365 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306366 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 int r = 0;
6368
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306369 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6370 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306371 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306372 ioc->name, cb_idx));
6373 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306375 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306376 ioc->name, ioc->alt_ioc->name, cb_idx));
6377 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 }
6379 }
6380 }
6381 }
6382
6383 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006384 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385 }
6386 ioc->reload_fw = 0;
6387 if (ioc->alt_ioc)
6388 ioc->alt_ioc->reload_fw = 0;
6389
6390 spin_lock_irqsave(&ioc->diagLock, flags);
6391 ioc->diagPending = 0;
6392 if (ioc->alt_ioc)
6393 ioc->alt_ioc->diagPending = 0;
6394 spin_unlock_irqrestore(&ioc->diagLock, flags);
6395
Prakash, Sathya436ace72007-07-24 15:42:08 +05306396 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397
6398 return rc;
6399}
6400
6401/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006402static void
6403EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404{
Eric Moore509e5e52006-04-26 13:22:37 -06006405 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406
6407 switch(event) {
6408 case MPI_EVENT_NONE:
6409 ds = "None";
6410 break;
6411 case MPI_EVENT_LOG_DATA:
6412 ds = "Log Data";
6413 break;
6414 case MPI_EVENT_STATE_CHANGE:
6415 ds = "State Change";
6416 break;
6417 case MPI_EVENT_UNIT_ATTENTION:
6418 ds = "Unit Attention";
6419 break;
6420 case MPI_EVENT_IOC_BUS_RESET:
6421 ds = "IOC Bus Reset";
6422 break;
6423 case MPI_EVENT_EXT_BUS_RESET:
6424 ds = "External Bus Reset";
6425 break;
6426 case MPI_EVENT_RESCAN:
6427 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428 break;
6429 case MPI_EVENT_LINK_STATUS_CHANGE:
6430 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6431 ds = "Link Status(FAILURE) Change";
6432 else
6433 ds = "Link Status(ACTIVE) Change";
6434 break;
6435 case MPI_EVENT_LOOP_STATE_CHANGE:
6436 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6437 ds = "Loop State(LIP) Change";
6438 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006439 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440 else
Eric Moore509e5e52006-04-26 13:22:37 -06006441 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442 break;
6443 case MPI_EVENT_LOGOUT:
6444 ds = "Logout";
6445 break;
6446 case MPI_EVENT_EVENT_CHANGE:
6447 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006448 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006450 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006451 break;
6452 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006453 {
6454 u8 ReasonCode = (u8)(evData0 >> 16);
6455 switch (ReasonCode) {
6456 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6457 ds = "Integrated Raid: Volume Created";
6458 break;
6459 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6460 ds = "Integrated Raid: Volume Deleted";
6461 break;
6462 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6463 ds = "Integrated Raid: Volume Settings Changed";
6464 break;
6465 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6466 ds = "Integrated Raid: Volume Status Changed";
6467 break;
6468 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6469 ds = "Integrated Raid: Volume Physdisk Changed";
6470 break;
6471 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6472 ds = "Integrated Raid: Physdisk Created";
6473 break;
6474 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6475 ds = "Integrated Raid: Physdisk Deleted";
6476 break;
6477 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6478 ds = "Integrated Raid: Physdisk Settings Changed";
6479 break;
6480 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6481 ds = "Integrated Raid: Physdisk Status Changed";
6482 break;
6483 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6484 ds = "Integrated Raid: Domain Validation Needed";
6485 break;
6486 case MPI_EVENT_RAID_RC_SMART_DATA :
6487 ds = "Integrated Raid; Smart Data";
6488 break;
6489 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6490 ds = "Integrated Raid: Replace Action Started";
6491 break;
6492 default:
6493 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006494 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006495 }
6496 break;
6497 }
6498 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6499 ds = "SCSI Device Status Change";
6500 break;
6501 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6502 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006503 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006504 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006505 u8 ReasonCode = (u8)(evData0 >> 16);
6506 switch (ReasonCode) {
6507 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006508 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006509 "SAS Device Status Change: Added: "
6510 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006511 break;
6512 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006513 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006514 "SAS Device Status Change: Deleted: "
6515 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006516 break;
6517 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006518 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006519 "SAS Device Status Change: SMART Data: "
6520 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006521 break;
6522 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006523 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006524 "SAS Device Status Change: No Persistancy: "
6525 "id=%d channel=%d", id, channel);
6526 break;
6527 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6528 snprintf(evStr, EVENT_DESCR_STR_SZ,
6529 "SAS Device Status Change: Unsupported Device "
6530 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006531 break;
6532 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6533 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006534 "SAS Device Status Change: Internal Device "
6535 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006536 break;
6537 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6538 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006539 "SAS Device Status Change: Internal Task "
6540 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006541 break;
6542 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6543 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006544 "SAS Device Status Change: Internal Abort "
6545 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006546 break;
6547 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6548 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006549 "SAS Device Status Change: Internal Clear "
6550 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006551 break;
6552 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6553 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006554 "SAS Device Status Change: Internal Query "
6555 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006556 break;
6557 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006558 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006559 "SAS Device Status Change: Unknown: "
6560 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006561 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006562 }
6563 break;
6564 }
6565 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6566 ds = "Bus Timer Expired";
6567 break;
6568 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006569 {
6570 u16 curr_depth = (u16)(evData0 >> 16);
6571 u8 channel = (u8)(evData0 >> 8);
6572 u8 id = (u8)(evData0);
6573
6574 snprintf(evStr, EVENT_DESCR_STR_SZ,
6575 "Queue Full: channel=%d id=%d depth=%d",
6576 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006577 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006578 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006579 case MPI_EVENT_SAS_SES:
6580 ds = "SAS SES Event";
6581 break;
6582 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6583 ds = "Persistent Table Full";
6584 break;
6585 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006586 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006587 u8 LinkRates = (u8)(evData0 >> 8);
6588 u8 PhyNumber = (u8)(evData0);
6589 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6590 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6591 switch (LinkRates) {
6592 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006593 snprintf(evStr, EVENT_DESCR_STR_SZ,
6594 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006595 " Rate Unknown",PhyNumber);
6596 break;
6597 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006598 snprintf(evStr, EVENT_DESCR_STR_SZ,
6599 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006600 " Phy Disabled",PhyNumber);
6601 break;
6602 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006603 snprintf(evStr, EVENT_DESCR_STR_SZ,
6604 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006605 " Failed Speed Nego",PhyNumber);
6606 break;
6607 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006608 snprintf(evStr, EVENT_DESCR_STR_SZ,
6609 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006610 " Sata OOB Completed",PhyNumber);
6611 break;
6612 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006613 snprintf(evStr, EVENT_DESCR_STR_SZ,
6614 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006615 " Rate 1.5 Gbps",PhyNumber);
6616 break;
6617 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006618 snprintf(evStr, EVENT_DESCR_STR_SZ,
6619 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006620 " Rate 3.0 Gpbs",PhyNumber);
6621 break;
6622 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006623 snprintf(evStr, EVENT_DESCR_STR_SZ,
6624 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006625 break;
6626 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006627 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006628 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006629 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6630 ds = "SAS Discovery Error";
6631 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006632 case MPI_EVENT_IR_RESYNC_UPDATE:
6633 {
6634 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006635 snprintf(evStr, EVENT_DESCR_STR_SZ,
6636 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006637 break;
6638 }
6639 case MPI_EVENT_IR2:
6640 {
6641 u8 ReasonCode = (u8)(evData0 >> 16);
6642 switch (ReasonCode) {
6643 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6644 ds = "IR2: LD State Changed";
6645 break;
6646 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6647 ds = "IR2: PD State Changed";
6648 break;
6649 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6650 ds = "IR2: Bad Block Table Full";
6651 break;
6652 case MPI_EVENT_IR2_RC_PD_INSERTED:
6653 ds = "IR2: PD Inserted";
6654 break;
6655 case MPI_EVENT_IR2_RC_PD_REMOVED:
6656 ds = "IR2: PD Removed";
6657 break;
6658 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6659 ds = "IR2: Foreign CFG Detected";
6660 break;
6661 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6662 ds = "IR2: Rebuild Medium Error";
6663 break;
6664 default:
6665 ds = "IR2";
6666 break;
6667 }
6668 break;
6669 }
6670 case MPI_EVENT_SAS_DISCOVERY:
6671 {
6672 if (evData0)
6673 ds = "SAS Discovery: Start";
6674 else
6675 ds = "SAS Discovery: Stop";
6676 break;
6677 }
6678 case MPI_EVENT_LOG_ENTRY_ADDED:
6679 ds = "SAS Log Entry Added";
6680 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006681
Eric Moorec6c727a2007-01-29 09:44:54 -07006682 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6683 {
6684 u8 phy_num = (u8)(evData0);
6685 u8 port_num = (u8)(evData0 >> 8);
6686 u8 port_width = (u8)(evData0 >> 16);
6687 u8 primative = (u8)(evData0 >> 24);
6688 snprintf(evStr, EVENT_DESCR_STR_SZ,
6689 "SAS Broadcase Primative: phy=%d port=%d "
6690 "width=%d primative=0x%02x",
6691 phy_num, port_num, port_width, primative);
6692 break;
6693 }
6694
6695 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6696 {
6697 u8 reason = (u8)(evData0);
6698 u8 port_num = (u8)(evData0 >> 8);
6699 u16 handle = le16_to_cpu(evData0 >> 16);
6700
6701 snprintf(evStr, EVENT_DESCR_STR_SZ,
6702 "SAS Initiator Device Status Change: reason=0x%02x "
6703 "port=%d handle=0x%04x",
6704 reason, port_num, handle);
6705 break;
6706 }
6707
6708 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6709 {
6710 u8 max_init = (u8)(evData0);
6711 u8 current_init = (u8)(evData0 >> 8);
6712
6713 snprintf(evStr, EVENT_DESCR_STR_SZ,
6714 "SAS Initiator Device Table Overflow: max initiators=%02d "
6715 "current initators=%02d",
6716 max_init, current_init);
6717 break;
6718 }
6719 case MPI_EVENT_SAS_SMP_ERROR:
6720 {
6721 u8 status = (u8)(evData0);
6722 u8 port_num = (u8)(evData0 >> 8);
6723 u8 result = (u8)(evData0 >> 16);
6724
6725 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6726 snprintf(evStr, EVENT_DESCR_STR_SZ,
6727 "SAS SMP Error: port=%d result=0x%02x",
6728 port_num, result);
6729 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6730 snprintf(evStr, EVENT_DESCR_STR_SZ,
6731 "SAS SMP Error: port=%d : CRC Error",
6732 port_num);
6733 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6734 snprintf(evStr, EVENT_DESCR_STR_SZ,
6735 "SAS SMP Error: port=%d : Timeout",
6736 port_num);
6737 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6738 snprintf(evStr, EVENT_DESCR_STR_SZ,
6739 "SAS SMP Error: port=%d : No Destination",
6740 port_num);
6741 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6742 snprintf(evStr, EVENT_DESCR_STR_SZ,
6743 "SAS SMP Error: port=%d : Bad Destination",
6744 port_num);
6745 else
6746 snprintf(evStr, EVENT_DESCR_STR_SZ,
6747 "SAS SMP Error: port=%d : status=0x%02x",
6748 port_num, status);
6749 break;
6750 }
6751
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752 /*
6753 * MPT base "custom" events may be added here...
6754 */
6755 default:
6756 ds = "Unknown";
6757 break;
6758 }
Eric Moore509e5e52006-04-26 13:22:37 -06006759 if (ds)
6760 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761}
6762
6763/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006764/**
6765 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006766 * @ioc: Pointer to MPT_ADAPTER structure
6767 * @pEventReply: Pointer to EventNotification reply frame
6768 * @evHandlers: Pointer to integer, number of event handlers
6769 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006770 * Routes a received EventNotificationReply to all currently registered
6771 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772 * Returns sum of event handlers return values.
6773 */
6774static int
6775ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6776{
6777 u16 evDataLen;
6778 u32 evData0 = 0;
6779// u32 evCtx;
6780 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306781 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006782 int r = 0;
6783 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006784 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006785 u8 event;
6786
6787 /*
6788 * Do platform normalization of values
6789 */
6790 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6791// evCtx = le32_to_cpu(pEventReply->EventContext);
6792 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6793 if (evDataLen) {
6794 evData0 = le32_to_cpu(pEventReply->Data[0]);
6795 }
6796
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006797 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306798 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006799 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006800 event,
6801 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006802
Prakash, Sathya436ace72007-07-24 15:42:08 +05306803#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006804 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6805 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006806 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306807 devtverboseprintk(ioc, printk(" %08x",
6808 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006809 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810#endif
6811
6812 /*
6813 * Do general / base driver event processing
6814 */
6815 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6817 if (evDataLen) {
6818 u8 evState = evData0 & 0xFF;
6819
6820 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6821
6822 /* Update EventState field in cached IocFacts */
6823 if (ioc->facts.Function) {
6824 ioc->facts.EventState = evState;
6825 }
6826 }
6827 break;
Moore, Ericece50912006-01-16 18:53:19 -07006828 case MPI_EVENT_INTEGRATED_RAID:
6829 mptbase_raid_process_event_data(ioc,
6830 (MpiEventDataRaid_t *)pEventReply->Data);
6831 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006832 default:
6833 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006834 }
6835
6836 /*
6837 * Should this event be logged? Events are written sequentially.
6838 * When buffer is full, start again at the top.
6839 */
6840 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6841 int idx;
6842
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006843 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006844
6845 ioc->events[idx].event = event;
6846 ioc->events[idx].eventContext = ioc->eventContext;
6847
6848 for (ii = 0; ii < 2; ii++) {
6849 if (ii < evDataLen)
6850 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6851 else
6852 ioc->events[idx].data[ii] = 0;
6853 }
6854
6855 ioc->eventContext++;
6856 }
6857
6858
6859 /*
6860 * Call each currently registered protocol event handler.
6861 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006862 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306863 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306864 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306865 ioc->name, cb_idx));
6866 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006867 handlers++;
6868 }
6869 }
6870 /* FIXME? Examine results here? */
6871
6872 /*
6873 * If needed, send (a single) EventAck.
6874 */
6875 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306876 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006877 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006878 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306879 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006880 ioc->name, ii));
6881 }
6882 }
6883
6884 *evHandlers = handlers;
6885 return r;
6886}
6887
6888/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006889/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006890 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6891 * @ioc: Pointer to MPT_ADAPTER structure
6892 * @log_info: U32 LogInfo reply word from the IOC
6893 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006894 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006895 */
6896static void
6897mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6898{
Eric Moore7c431e52007-06-13 16:34:36 -06006899 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006900
Eric Moore7c431e52007-06-13 16:34:36 -06006901 switch (log_info & 0xFF000000) {
6902 case MPI_IOCLOGINFO_FC_INIT_BASE:
6903 desc = "FCP Initiator";
6904 break;
6905 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6906 desc = "FCP Target";
6907 break;
6908 case MPI_IOCLOGINFO_FC_LAN_BASE:
6909 desc = "LAN";
6910 break;
6911 case MPI_IOCLOGINFO_FC_MSG_BASE:
6912 desc = "MPI Message Layer";
6913 break;
6914 case MPI_IOCLOGINFO_FC_LINK_BASE:
6915 desc = "FC Link";
6916 break;
6917 case MPI_IOCLOGINFO_FC_CTX_BASE:
6918 desc = "Context Manager";
6919 break;
6920 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6921 desc = "Invalid Field Offset";
6922 break;
6923 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6924 desc = "State Change Info";
6925 break;
6926 }
6927
6928 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6929 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006930}
6931
6932/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006933/**
Moore, Eric335a9412006-01-17 17:06:23 -07006934 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935 * @ioc: Pointer to MPT_ADAPTER structure
6936 * @mr: Pointer to MPT reply frame
6937 * @log_info: U32 LogInfo word from the IOC
6938 *
6939 * Refer to lsi/sp_log.h.
6940 */
6941static void
Moore, Eric335a9412006-01-17 17:06:23 -07006942mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943{
6944 u32 info = log_info & 0x00FF0000;
6945 char *desc = "unknown";
6946
6947 switch (info) {
6948 case 0x00010000:
6949 desc = "bug! MID not found";
6950 if (ioc->reload_fw == 0)
6951 ioc->reload_fw++;
6952 break;
6953
6954 case 0x00020000:
6955 desc = "Parity Error";
6956 break;
6957
6958 case 0x00030000:
6959 desc = "ASYNC Outbound Overrun";
6960 break;
6961
6962 case 0x00040000:
6963 desc = "SYNC Offset Error";
6964 break;
6965
6966 case 0x00050000:
6967 desc = "BM Change";
6968 break;
6969
6970 case 0x00060000:
6971 desc = "Msg In Overflow";
6972 break;
6973
6974 case 0x00070000:
6975 desc = "DMA Error";
6976 break;
6977
6978 case 0x00080000:
6979 desc = "Outbound DMA Overrun";
6980 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006981
Linus Torvalds1da177e2005-04-16 15:20:36 -07006982 case 0x00090000:
6983 desc = "Task Management";
6984 break;
6985
6986 case 0x000A0000:
6987 desc = "Device Problem";
6988 break;
6989
6990 case 0x000B0000:
6991 desc = "Invalid Phase Change";
6992 break;
6993
6994 case 0x000C0000:
6995 desc = "Untagged Table Size";
6996 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006997
Linus Torvalds1da177e2005-04-16 15:20:36 -07006998 }
6999
7000 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7001}
7002
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007003/* strings for sas loginfo */
7004 static char *originator_str[] = {
7005 "IOP", /* 00h */
7006 "PL", /* 01h */
7007 "IR" /* 02h */
7008 };
7009 static char *iop_code_str[] = {
7010 NULL, /* 00h */
7011 "Invalid SAS Address", /* 01h */
7012 NULL, /* 02h */
7013 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007014 "Diag Message Error", /* 04h */
7015 "Task Terminated", /* 05h */
7016 "Enclosure Management", /* 06h */
7017 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007018 };
7019 static char *pl_code_str[] = {
7020 NULL, /* 00h */
7021 "Open Failure", /* 01h */
7022 "Invalid Scatter Gather List", /* 02h */
7023 "Wrong Relative Offset or Frame Length", /* 03h */
7024 "Frame Transfer Error", /* 04h */
7025 "Transmit Frame Connected Low", /* 05h */
7026 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7027 "SATA Read Log Receive Data Error", /* 07h */
7028 "SATA NCQ Fail All Commands After Error", /* 08h */
7029 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7030 "Receive Frame Invalid Message", /* 0Ah */
7031 "Receive Context Message Valid Error", /* 0Bh */
7032 "Receive Frame Current Frame Error", /* 0Ch */
7033 "SATA Link Down", /* 0Dh */
7034 "Discovery SATA Init W IOS", /* 0Eh */
7035 "Config Invalid Page", /* 0Fh */
7036 "Discovery SATA Init Timeout", /* 10h */
7037 "Reset", /* 11h */
7038 "Abort", /* 12h */
7039 "IO Not Yet Executed", /* 13h */
7040 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007041 "Persistent Reservation Out Not Affiliation "
7042 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007043 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007044 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007045 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007046 NULL, /* 19h */
7047 NULL, /* 1Ah */
7048 NULL, /* 1Bh */
7049 NULL, /* 1Ch */
7050 NULL, /* 1Dh */
7051 NULL, /* 1Eh */
7052 NULL, /* 1Fh */
7053 "Enclosure Management" /* 20h */
7054 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007055 static char *ir_code_str[] = {
7056 "Raid Action Error", /* 00h */
7057 NULL, /* 00h */
7058 NULL, /* 01h */
7059 NULL, /* 02h */
7060 NULL, /* 03h */
7061 NULL, /* 04h */
7062 NULL, /* 05h */
7063 NULL, /* 06h */
7064 NULL /* 07h */
7065 };
7066 static char *raid_sub_code_str[] = {
7067 NULL, /* 00h */
7068 "Volume Creation Failed: Data Passed too "
7069 "Large", /* 01h */
7070 "Volume Creation Failed: Duplicate Volumes "
7071 "Attempted", /* 02h */
7072 "Volume Creation Failed: Max Number "
7073 "Supported Volumes Exceeded", /* 03h */
7074 "Volume Creation Failed: DMA Error", /* 04h */
7075 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7076 "Volume Creation Failed: Error Reading "
7077 "MFG Page 4", /* 06h */
7078 "Volume Creation Failed: Creating Internal "
7079 "Structures", /* 07h */
7080 NULL, /* 08h */
7081 NULL, /* 09h */
7082 NULL, /* 0Ah */
7083 NULL, /* 0Bh */
7084 NULL, /* 0Ch */
7085 NULL, /* 0Dh */
7086 NULL, /* 0Eh */
7087 NULL, /* 0Fh */
7088 "Activation failed: Already Active Volume", /* 10h */
7089 "Activation failed: Unsupported Volume Type", /* 11h */
7090 "Activation failed: Too Many Active Volumes", /* 12h */
7091 "Activation failed: Volume ID in Use", /* 13h */
7092 "Activation failed: Reported Failure", /* 14h */
7093 "Activation failed: Importing a Volume", /* 15h */
7094 NULL, /* 16h */
7095 NULL, /* 17h */
7096 NULL, /* 18h */
7097 NULL, /* 19h */
7098 NULL, /* 1Ah */
7099 NULL, /* 1Bh */
7100 NULL, /* 1Ch */
7101 NULL, /* 1Dh */
7102 NULL, /* 1Eh */
7103 NULL, /* 1Fh */
7104 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7105 "Phys Disk failed: Data Passed too Large", /* 21h */
7106 "Phys Disk failed: DMA Error", /* 22h */
7107 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7108 "Phys Disk failed: Creating Phys Disk Config "
7109 "Page", /* 24h */
7110 NULL, /* 25h */
7111 NULL, /* 26h */
7112 NULL, /* 27h */
7113 NULL, /* 28h */
7114 NULL, /* 29h */
7115 NULL, /* 2Ah */
7116 NULL, /* 2Bh */
7117 NULL, /* 2Ch */
7118 NULL, /* 2Dh */
7119 NULL, /* 2Eh */
7120 NULL, /* 2Fh */
7121 "Compatibility Error: IR Disabled", /* 30h */
7122 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7123 "Compatibility Error: Device not Direct Access "
7124 "Device ", /* 32h */
7125 "Compatibility Error: Removable Device Found", /* 33h */
7126 "Compatibility Error: Device SCSI Version not "
7127 "2 or Higher", /* 34h */
7128 "Compatibility Error: SATA Device, 48 BIT LBA "
7129 "not Supported", /* 35h */
7130 "Compatibility Error: Device doesn't have "
7131 "512 Byte Block Sizes", /* 36h */
7132 "Compatibility Error: Volume Type Check Failed", /* 37h */
7133 "Compatibility Error: Volume Type is "
7134 "Unsupported by FW", /* 38h */
7135 "Compatibility Error: Disk Drive too Small for "
7136 "use in Volume", /* 39h */
7137 "Compatibility Error: Phys Disk for Create "
7138 "Volume not Found", /* 3Ah */
7139 "Compatibility Error: Too Many or too Few "
7140 "Disks for Volume Type", /* 3Bh */
7141 "Compatibility Error: Disk stripe Sizes "
7142 "Must be 64KB", /* 3Ch */
7143 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7144 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007145
7146/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007147/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007148 * mpt_sas_log_info - Log information returned from SAS IOC.
7149 * @ioc: Pointer to MPT_ADAPTER structure
7150 * @log_info: U32 LogInfo reply word from the IOC
7151 *
7152 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007153 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007154static void
7155mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7156{
7157union loginfo_type {
7158 u32 loginfo;
7159 struct {
7160 u32 subcode:16;
7161 u32 code:8;
7162 u32 originator:4;
7163 u32 bus_type:4;
7164 }dw;
7165};
7166 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007167 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007168 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007169 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007170
7171 sas_loginfo.loginfo = log_info;
7172 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
7173 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
7174 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007175
7176 originator_desc = originator_str[sas_loginfo.dw.originator];
7177
7178 switch (sas_loginfo.dw.originator) {
7179
7180 case 0: /* IOP */
7181 if (sas_loginfo.dw.code <
7182 sizeof(iop_code_str)/sizeof(char*))
7183 code_desc = iop_code_str[sas_loginfo.dw.code];
7184 break;
7185 case 1: /* PL */
7186 if (sas_loginfo.dw.code <
7187 sizeof(pl_code_str)/sizeof(char*))
7188 code_desc = pl_code_str[sas_loginfo.dw.code];
7189 break;
7190 case 2: /* IR */
7191 if (sas_loginfo.dw.code >=
7192 sizeof(ir_code_str)/sizeof(char*))
7193 break;
7194 code_desc = ir_code_str[sas_loginfo.dw.code];
7195 if (sas_loginfo.dw.subcode >=
7196 sizeof(raid_sub_code_str)/sizeof(char*))
7197 break;
7198 if (sas_loginfo.dw.code == 0)
7199 sub_code_desc =
7200 raid_sub_code_str[sas_loginfo.dw.subcode];
7201 break;
7202 default:
7203 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007204 }
7205
Eric Moorec6c727a2007-01-29 09:44:54 -07007206 if (sub_code_desc != NULL)
7207 printk(MYIOC_s_INFO_FMT
7208 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7209 " SubCode={%s}\n",
7210 ioc->name, log_info, originator_desc, code_desc,
7211 sub_code_desc);
7212 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007213 printk(MYIOC_s_INFO_FMT
7214 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7215 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007216 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007217 sas_loginfo.dw.subcode);
7218 else
7219 printk(MYIOC_s_INFO_FMT
7220 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7221 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007222 ioc->name, log_info, originator_desc,
7223 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007224}
7225
Linus Torvalds1da177e2005-04-16 15:20:36 -07007226/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007227/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007228 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7229 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007230 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007231 * @mf: Pointer to MPT request frame
7232 *
7233 * Refer to lsi/mpi.h.
7234 **/
7235static void
7236mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7237{
7238 Config_t *pReq = (Config_t *)mf;
7239 char extend_desc[EVENT_DESCR_STR_SZ];
7240 char *desc = NULL;
7241 u32 form;
7242 u8 page_type;
7243
7244 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7245 page_type = pReq->ExtPageType;
7246 else
7247 page_type = pReq->Header.PageType;
7248
7249 /*
7250 * ignore invalid page messages for GET_NEXT_HANDLE
7251 */
7252 form = le32_to_cpu(pReq->PageAddress);
7253 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7254 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7255 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7256 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7257 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7258 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7259 return;
7260 }
7261 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7262 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7263 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7264 return;
7265 }
7266
7267 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7268 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7269 page_type, pReq->Header.PageNumber, pReq->Action, form);
7270
7271 switch (ioc_status) {
7272
7273 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7274 desc = "Config Page Invalid Action";
7275 break;
7276
7277 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7278 desc = "Config Page Invalid Type";
7279 break;
7280
7281 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7282 desc = "Config Page Invalid Page";
7283 break;
7284
7285 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7286 desc = "Config Page Invalid Data";
7287 break;
7288
7289 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7290 desc = "Config Page No Defaults";
7291 break;
7292
7293 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7294 desc = "Config Page Can't Commit";
7295 break;
7296 }
7297
7298 if (!desc)
7299 return;
7300
Eric Moore29dd3602007-09-14 18:46:51 -06007301 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7302 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007303}
7304
7305/**
7306 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307 * @ioc: Pointer to MPT_ADAPTER structure
7308 * @ioc_status: U32 IOCStatus word from IOC
7309 * @mf: Pointer to MPT request frame
7310 *
7311 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007312 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007313static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007314mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007315{
7316 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007317 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007318
7319 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007320
7321/****************************************************************************/
7322/* Common IOCStatus values for all replies */
7323/****************************************************************************/
7324
Linus Torvalds1da177e2005-04-16 15:20:36 -07007325 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7326 desc = "Invalid Function";
7327 break;
7328
7329 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7330 desc = "Busy";
7331 break;
7332
7333 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7334 desc = "Invalid SGL";
7335 break;
7336
7337 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7338 desc = "Internal Error";
7339 break;
7340
7341 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7342 desc = "Reserved";
7343 break;
7344
7345 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7346 desc = "Insufficient Resources";
7347 break;
7348
7349 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7350 desc = "Invalid Field";
7351 break;
7352
7353 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7354 desc = "Invalid State";
7355 break;
7356
Eric Moorec6c727a2007-01-29 09:44:54 -07007357/****************************************************************************/
7358/* Config IOCStatus values */
7359/****************************************************************************/
7360
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7362 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7363 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7364 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7365 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7366 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007367 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007368 break;
7369
Eric Moorec6c727a2007-01-29 09:44:54 -07007370/****************************************************************************/
7371/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7372/* */
7373/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7374/* */
7375/****************************************************************************/
7376
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007378 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007379 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7380 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7381 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7382 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007384 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007385 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007386 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007387 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007389 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007390 break;
7391
Eric Moorec6c727a2007-01-29 09:44:54 -07007392/****************************************************************************/
7393/* SCSI Target values */
7394/****************************************************************************/
7395
7396 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7397 desc = "Target: Priority IO";
7398 break;
7399
7400 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7401 desc = "Target: Invalid Port";
7402 break;
7403
7404 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7405 desc = "Target Invalid IO Index:";
7406 break;
7407
7408 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7409 desc = "Target: Aborted";
7410 break;
7411
7412 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7413 desc = "Target: No Conn Retryable";
7414 break;
7415
7416 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7417 desc = "Target: No Connection";
7418 break;
7419
7420 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7421 desc = "Target: Transfer Count Mismatch";
7422 break;
7423
7424 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7425 desc = "Target: STS Data not Sent";
7426 break;
7427
7428 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7429 desc = "Target: Data Offset Error";
7430 break;
7431
7432 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7433 desc = "Target: Too Much Write Data";
7434 break;
7435
7436 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7437 desc = "Target: IU Too Short";
7438 break;
7439
7440 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7441 desc = "Target: ACK NAK Timeout";
7442 break;
7443
7444 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7445 desc = "Target: Nak Received";
7446 break;
7447
7448/****************************************************************************/
7449/* Fibre Channel Direct Access values */
7450/****************************************************************************/
7451
7452 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7453 desc = "FC: Aborted";
7454 break;
7455
7456 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7457 desc = "FC: RX ID Invalid";
7458 break;
7459
7460 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7461 desc = "FC: DID Invalid";
7462 break;
7463
7464 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7465 desc = "FC: Node Logged Out";
7466 break;
7467
7468 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7469 desc = "FC: Exchange Canceled";
7470 break;
7471
7472/****************************************************************************/
7473/* LAN values */
7474/****************************************************************************/
7475
7476 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7477 desc = "LAN: Device not Found";
7478 break;
7479
7480 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7481 desc = "LAN: Device Failure";
7482 break;
7483
7484 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7485 desc = "LAN: Transmit Error";
7486 break;
7487
7488 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7489 desc = "LAN: Transmit Aborted";
7490 break;
7491
7492 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7493 desc = "LAN: Receive Error";
7494 break;
7495
7496 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7497 desc = "LAN: Receive Aborted";
7498 break;
7499
7500 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7501 desc = "LAN: Partial Packet";
7502 break;
7503
7504 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7505 desc = "LAN: Canceled";
7506 break;
7507
7508/****************************************************************************/
7509/* Serial Attached SCSI values */
7510/****************************************************************************/
7511
7512 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7513 desc = "SAS: SMP Request Failed";
7514 break;
7515
7516 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7517 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007518 break;
7519
7520 default:
7521 desc = "Others";
7522 break;
7523 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007524
7525 if (!desc)
7526 return;
7527
Eric Moore29dd3602007-09-14 18:46:51 -06007528 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7529 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007530}
7531
7532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007533EXPORT_SYMBOL(mpt_attach);
7534EXPORT_SYMBOL(mpt_detach);
7535#ifdef CONFIG_PM
7536EXPORT_SYMBOL(mpt_resume);
7537EXPORT_SYMBOL(mpt_suspend);
7538#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007539EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007540EXPORT_SYMBOL(mpt_register);
7541EXPORT_SYMBOL(mpt_deregister);
7542EXPORT_SYMBOL(mpt_event_register);
7543EXPORT_SYMBOL(mpt_event_deregister);
7544EXPORT_SYMBOL(mpt_reset_register);
7545EXPORT_SYMBOL(mpt_reset_deregister);
7546EXPORT_SYMBOL(mpt_device_driver_register);
7547EXPORT_SYMBOL(mpt_device_driver_deregister);
7548EXPORT_SYMBOL(mpt_get_msg_frame);
7549EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307550EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007551EXPORT_SYMBOL(mpt_free_msg_frame);
7552EXPORT_SYMBOL(mpt_add_sge);
7553EXPORT_SYMBOL(mpt_send_handshake_request);
7554EXPORT_SYMBOL(mpt_verify_adapter);
7555EXPORT_SYMBOL(mpt_GetIocState);
7556EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007557EXPORT_SYMBOL(mpt_HardResetHandler);
7558EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007559EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007560EXPORT_SYMBOL(mpt_alloc_fw_memory);
7561EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007562EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007563EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007564
Linus Torvalds1da177e2005-04-16 15:20:36 -07007565/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007566/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007567 * fusion_init - Fusion MPT base driver initialization routine.
7568 *
7569 * Returns 0 for success, non-zero for failure.
7570 */
7571static int __init
7572fusion_init(void)
7573{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307574 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007575
7576 show_mptmod_ver(my_NAME, my_VERSION);
7577 printk(KERN_INFO COPYRIGHT "\n");
7578
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307579 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7580 MptCallbacks[cb_idx] = NULL;
7581 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7582 MptEvHandlers[cb_idx] = NULL;
7583 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007584 }
7585
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007586 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007587 * EventNotification handling.
7588 */
7589 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7590
7591 /* Register for hard reset handling callbacks.
7592 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307593 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007594
7595#ifdef CONFIG_PROC_FS
7596 (void) procmpt_create();
7597#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007598 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007599}
7600
7601/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007602/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603 * fusion_exit - Perform driver unload cleanup.
7604 *
7605 * This routine frees all resources associated with each MPT adapter
7606 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7607 */
7608static void __exit
7609fusion_exit(void)
7610{
7611
Linus Torvalds1da177e2005-04-16 15:20:36 -07007612 mpt_reset_deregister(mpt_base_index);
7613
7614#ifdef CONFIG_PROC_FS
7615 procmpt_destroy();
7616#endif
7617}
7618
Linus Torvalds1da177e2005-04-16 15:20:36 -07007619module_init(fusion_init);
7620module_exit(fusion_exit);