blob: 083acfd91d8bff0dad61188a8195c7b8aa1893e2 [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.
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
7 *
Eric Moore9f4203b2007-01-04 20:47:47 -07008 * Copyright (c) 1999-2007 LSI Logic Corporation
Eric Moore07c861d2007-01-29 09:48:50 -07009 * (mailto:mpt_linux_developer@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"
67
68/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
69#define my_NAME "Fusion MPT base driver"
70#define my_VERSION MPT_LINUX_VERSION_COMMON
71#define MYNAM "mptbase"
72
73MODULE_AUTHOR(MODULEAUTHOR);
74MODULE_DESCRIPTION(my_NAME);
75MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070076MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78/*
79 * cmd line parameters
80 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000081static int mpt_msi_enable;
82module_param(mpt_msi_enable, int, 0);
83MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
84
Eric Moore793955f2007-01-29 09:42:20 -070085static int mpt_channel_mapping;
86module_param(mpt_channel_mapping, int, 0);
87MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
88
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#ifdef MFCNT
90static int mfcounter = 0;
91#define PRINT_MF_COUNT 20000
92#endif
93
94/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
95/*
96 * Public data...
97 */
98int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080099int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Linus Torvaldsf7473072005-11-29 14:21:57 -0800101struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103#define WHOINIT_UNKNOWN 0xAA
104
105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
106/*
107 * Private data...
108 */
109 /* Adapter link list */
110LIST_HEAD(ioc_list);
111 /* Callback lookup table */
112static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
113 /* Protocol driver class lookup table */
114static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
115 /* Event handler lookup table */
116static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
117 /* Reset handler lookup table */
118static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
119static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
120
121static int mpt_base_index = -1;
122static int last_drv_idx = -1;
123
124static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
125
126/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
127/*
128 * Forward protos...
129 */
David Howells7d12e782006-10-05 14:55:46 +0100130static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
132static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
133 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
134 int sleepFlag);
135static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
136static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
137static void mpt_adapter_disable(MPT_ADAPTER *ioc);
138static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
139
140static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
141static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
143static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
144static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
145static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
146static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200147static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
149static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
150static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
151static int PrimeIocFifos(MPT_ADAPTER *ioc);
152static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
153static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
154static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
155static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200157int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
159static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
160static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
161static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
162static void mpt_timer_expired(unsigned long data);
163static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
164static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200165static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
166static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168#ifdef CONFIG_PROC_FS
169static int procmpt_summary_read(char *buf, char **start, off_t offset,
170 int request, int *eof, void *data);
171static int procmpt_version_read(char *buf, char **start, off_t offset,
172 int request, int *eof, void *data);
173static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
174 int request, int *eof, void *data);
175#endif
176static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
177
178//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
179static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700180#ifdef MPT_DEBUG_REPLY
181static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
182#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700184static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600185static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700186static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700187static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static int __init fusion_init (void);
191static void __exit fusion_exit (void);
192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193#define CHIPREG_READ32(addr) readl_relaxed(addr)
194#define CHIPREG_READ32_dmasync(addr) readl(addr)
195#define CHIPREG_WRITE32(addr,val) writel(val, addr)
196#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
197#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
198
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600199static void
200pci_disable_io_access(struct pci_dev *pdev)
201{
202 u16 command_reg;
203
204 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
205 command_reg &= ~1;
206 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
207}
208
209static void
210pci_enable_io_access(struct pci_dev *pdev)
211{
212 u16 command_reg;
213
214 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
215 command_reg |= 1;
216 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
217}
218
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600219/*
220 * Process turbo (context) reply...
221 */
222static void
223mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
224{
225 MPT_FRAME_HDR *mf = NULL;
226 MPT_FRAME_HDR *mr = NULL;
227 int req_idx = 0;
228 int cb_idx;
229
230 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
231 ioc->name, pa));
232
233 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
234 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
235 req_idx = pa & 0x0000FFFF;
236 cb_idx = (pa & 0x00FF0000) >> 16;
237 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
238 break;
239 case MPI_CONTEXT_REPLY_TYPE_LAN:
240 cb_idx = mpt_lan_index;
241 /*
242 * Blind set of mf to NULL here was fatal
243 * after lan_reply says "freeme"
244 * Fix sort of combined with an optimization here;
245 * added explicit check for case where lan_reply
246 * was just returning 1 and doing nothing else.
247 * For this case skip the callback, but set up
248 * proper mf value first here:-)
249 */
250 if ((pa & 0x58000000) == 0x58000000) {
251 req_idx = pa & 0x0000FFFF;
252 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
253 mpt_free_msg_frame(ioc, mf);
254 mb();
255 return;
256 break;
257 }
258 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
259 break;
260 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
261 cb_idx = mpt_stm_index;
262 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
263 break;
264 default:
265 cb_idx = 0;
266 BUG();
267 }
268
269 /* Check for (valid) IO callback! */
270 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
271 MptCallbacks[cb_idx] == NULL) {
272 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
273 __FUNCTION__, ioc->name, cb_idx);
274 goto out;
275 }
276
277 if (MptCallbacks[cb_idx](ioc, mf, mr))
278 mpt_free_msg_frame(ioc, mf);
279 out:
280 mb();
281}
282
283static void
284mpt_reply(MPT_ADAPTER *ioc, u32 pa)
285{
286 MPT_FRAME_HDR *mf;
287 MPT_FRAME_HDR *mr;
288 int req_idx;
289 int cb_idx;
290 int freeme;
291
292 u32 reply_dma_low;
293 u16 ioc_stat;
294
295 /* non-TURBO reply! Hmmm, something may be up...
296 * Newest turbo reply mechanism; get address
297 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
298 */
299
300 /* Map DMA address of reply header to cpu address.
301 * pa is 32 bits - but the dma address may be 32 or 64 bits
302 * get offset based only only the low addresses
303 */
304
305 reply_dma_low = (pa <<= 1);
306 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
307 (reply_dma_low - ioc->reply_frames_low_dma));
308
309 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
310 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
311 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
312
313 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
314 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
315 DBG_DUMP_REPLY_FRAME(mr)
316
317 /* Check/log IOC log info
318 */
319 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
320 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
321 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
322 if (ioc->bus_type == FC)
323 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700324 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700325 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600326 else if (ioc->bus_type == SAS)
327 mpt_sas_log_info(ioc, log_info);
328 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600329
Eric Moorec6c727a2007-01-29 09:44:54 -0700330#ifdef MPT_DEBUG_REPLY
331 if (ioc_stat & MPI_IOCSTATUS_MASK)
332 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
333#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600334
335 /* Check for (valid) IO callback! */
336 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
337 MptCallbacks[cb_idx] == NULL) {
338 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
339 __FUNCTION__, ioc->name, cb_idx);
340 freeme = 0;
341 goto out;
342 }
343
344 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
345
346 out:
347 /* Flush (non-TURBO) reply with a WRITE! */
348 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
349
350 if (freeme)
351 mpt_free_msg_frame(ioc, mf);
352 mb();
353}
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800356/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
358 * @irq: irq number (not used)
359 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 *
361 * This routine is registered via the request_irq() kernel API call,
362 * and handles all interrupts generated from a specific MPT adapter
363 * (also referred to as a IO Controller or IOC).
364 * This routine must clear the interrupt from the adapter and does
365 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200366 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 *
368 * This routine handles register-level access of the adapter but
369 * dispatches (calls) a protocol-specific callback routine to handle
370 * the protocol-specific details of the MPT request completion.
371 */
372static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100373mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600375 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600376 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
377
378 if (pa == 0xFFFFFFFF)
379 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 /*
382 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600384 do {
385 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600386 mpt_reply(ioc, pa);
387 else
388 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600389 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
390 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
392 return IRQ_HANDLED;
393}
394
395/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800396/**
397 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 * @ioc: Pointer to MPT_ADAPTER structure
399 * @mf: Pointer to original MPT request frame
400 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
401 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800402 * MPT base driver's callback routine; all base driver
403 * "internal" request/reply processing is routed here.
404 * Currently used for EventNotification and EventAck handling.
405 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200406 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 * should be freed, or 0 if it shouldn't.
408 */
409static int
410mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
411{
412 int freereq = 1;
413 u8 func;
414
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200415 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200417#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
419 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
420 DBG_DUMP_REQUEST_FRAME_HDR(mf)
421 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200422#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200425 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 ioc->name, func));
427
428 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
429 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
430 int evHandlers = 0;
431 int results;
432
433 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
434 if (results != evHandlers) {
435 /* CHECKME! Any special handling needed here? */
Moore, Eric3a892be2006-03-14 09:14:03 -0700436 devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 ioc->name, evHandlers, results));
438 }
439
440 /*
441 * Hmmm... It seems that EventNotificationReply is an exception
442 * to the rule of one reply per request.
443 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200444 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200446 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700447 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200448 ioc->name, pEvReply));
449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451#ifdef CONFIG_PROC_FS
452// LogEvent(ioc, pEvReply);
453#endif
454
455 } else if (func == MPI_FUNCTION_EVENT_ACK) {
456 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
457 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700458 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 CONFIGPARMS *pCfg;
460 unsigned long flags;
461
462 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
463 ioc->name, mf, reply));
464
465 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
466
467 if (pCfg) {
468 /* disable timer and remove from linked list */
469 del_timer(&pCfg->timer);
470
471 spin_lock_irqsave(&ioc->FreeQlock, flags);
472 list_del(&pCfg->linkage);
473 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
474
475 /*
476 * If IOC Status is SUCCESS, save the header
477 * and set the status code to GOOD.
478 */
479 pCfg->status = MPT_CONFIG_ERROR;
480 if (reply) {
481 ConfigReply_t *pReply = (ConfigReply_t *)reply;
482 u16 status;
483
484 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
485 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
486 status, le32_to_cpu(pReply->IOCLogInfo)));
487
488 pCfg->status = status;
489 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200490 if ((pReply->Header.PageType &
491 MPI_CONFIG_PAGETYPE_MASK) ==
492 MPI_CONFIG_PAGETYPE_EXTENDED) {
493 pCfg->cfghdr.ehdr->ExtPageLength =
494 le16_to_cpu(pReply->ExtPageLength);
495 pCfg->cfghdr.ehdr->ExtPageType =
496 pReply->ExtPageType;
497 }
498 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
499
500 /* If this is a regular header, save PageLength. */
501 /* LMP Do this better so not using a reserved field! */
502 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
503 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
504 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 }
506 }
507
508 /*
509 * Wake up the original calling thread
510 */
511 pCfg->wait_done = 1;
512 wake_up(&mpt_waitq);
513 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200514 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
515 /* we should be always getting a reply frame */
516 memcpy(ioc->persist_reply_frame, reply,
517 min(MPT_DEFAULT_FRAME_SIZE,
518 4*reply->u.reply.MsgLength));
519 del_timer(&ioc->persist_timer);
520 ioc->persist_wait_done = 1;
521 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 } else {
523 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
524 ioc->name, func);
525 }
526
527 /*
528 * Conditionally tell caller to free the original
529 * EventNotification/EventAck/unexpected request frame!
530 */
531 return freereq;
532}
533
534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
535/**
536 * mpt_register - Register protocol-specific main callback handler.
537 * @cbfunc: callback function pointer
538 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
539 *
540 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800541 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 * protocol-specific driver must do this before it will be able to
543 * use any IOC resources, such as obtaining request frames.
544 *
545 * NOTES: The SCSI protocol driver currently calls this routine thrice
546 * in order to register separate callbacks; one for "normal" SCSI IO;
547 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
548 *
549 * Returns a positive integer valued "handle" in the
550 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
551 * Any non-positive return value (including zero!) should be considered
552 * an error by the caller.
553 */
554int
555mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
556{
557 int i;
558
559 last_drv_idx = -1;
560
561 /*
562 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
563 * (slot/handle 0 is reserved!)
564 */
565 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
566 if (MptCallbacks[i] == NULL) {
567 MptCallbacks[i] = cbfunc;
568 MptDriverClass[i] = dclass;
569 MptEvHandlers[i] = NULL;
570 last_drv_idx = i;
571 break;
572 }
573 }
574
575 return last_drv_idx;
576}
577
578/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
579/**
580 * mpt_deregister - Deregister a protocol drivers resources.
581 * @cb_idx: previously registered callback handle
582 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800583 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 * module is unloaded.
585 */
586void
587mpt_deregister(int cb_idx)
588{
589 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
590 MptCallbacks[cb_idx] = NULL;
591 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
592 MptEvHandlers[cb_idx] = NULL;
593
594 last_drv_idx++;
595 }
596}
597
598/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
599/**
600 * mpt_event_register - Register protocol-specific event callback
601 * handler.
602 * @cb_idx: previously registered (via mpt_register) callback handle
603 * @ev_cbfunc: callback function
604 *
605 * This routine can be called by one or more protocol-specific drivers
606 * if/when they choose to be notified of MPT events.
607 *
608 * Returns 0 for success.
609 */
610int
611mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
612{
613 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
614 return -1;
615
616 MptEvHandlers[cb_idx] = ev_cbfunc;
617 return 0;
618}
619
620/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
621/**
622 * mpt_event_deregister - Deregister protocol-specific event callback
623 * handler.
624 * @cb_idx: previously registered callback handle
625 *
626 * Each protocol-specific driver should call this routine
627 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800628 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 */
630void
631mpt_event_deregister(int cb_idx)
632{
633 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
634 return;
635
636 MptEvHandlers[cb_idx] = NULL;
637}
638
639/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
640/**
641 * mpt_reset_register - Register protocol-specific IOC reset handler.
642 * @cb_idx: previously registered (via mpt_register) callback handle
643 * @reset_func: reset function
644 *
645 * This routine can be called by one or more protocol-specific drivers
646 * if/when they choose to be notified of IOC resets.
647 *
648 * Returns 0 for success.
649 */
650int
651mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
652{
653 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
654 return -1;
655
656 MptResetHandlers[cb_idx] = reset_func;
657 return 0;
658}
659
660/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
661/**
662 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
663 * @cb_idx: previously registered callback handle
664 *
665 * Each protocol-specific driver should call this routine
666 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800667 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 */
669void
670mpt_reset_deregister(int cb_idx)
671{
672 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
673 return;
674
675 MptResetHandlers[cb_idx] = NULL;
676}
677
678/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
679/**
680 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800681 * @dd_cbfunc: driver callbacks struct
682 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 */
684int
685mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
686{
687 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600688 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Eric Moored58b2722006-07-11 17:23:23 -0600690 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400691 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
694
695 /* call per pci device probe entry point */
696 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600697 id = ioc->pcidev->driver ?
698 ioc->pcidev->driver->id_table : NULL;
699 if (dd_cbfunc->probe)
700 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 }
702
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400703 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704}
705
706/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
707/**
708 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800709 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 */
711void
712mpt_device_driver_deregister(int cb_idx)
713{
714 struct mpt_pci_driver *dd_cbfunc;
715 MPT_ADAPTER *ioc;
716
717 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
718 return;
719
720 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
721
722 list_for_each_entry(ioc, &ioc_list, list) {
723 if (dd_cbfunc->remove)
724 dd_cbfunc->remove(ioc->pcidev);
725 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200726
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 MptDeviceDriverHandlers[cb_idx] = NULL;
728}
729
730
731/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
732/**
733 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
734 * allocated per MPT adapter.
735 * @handle: Handle of registered MPT protocol driver
736 * @ioc: Pointer to MPT adapter structure
737 *
738 * Returns pointer to a MPT request frame or %NULL if none are available
739 * or IOC is not active.
740 */
741MPT_FRAME_HDR*
742mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
743{
744 MPT_FRAME_HDR *mf;
745 unsigned long flags;
746 u16 req_idx; /* Request index */
747
748 /* validate handle and ioc identifier */
749
750#ifdef MFCNT
751 if (!ioc->active)
752 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
753#endif
754
755 /* If interrupts are not attached, do not return a request frame */
756 if (!ioc->active)
757 return NULL;
758
759 spin_lock_irqsave(&ioc->FreeQlock, flags);
760 if (!list_empty(&ioc->FreeQ)) {
761 int req_offset;
762
763 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
764 u.frame.linkage.list);
765 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200766 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
768 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
769 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500770 req_idx = req_offset / ioc->req_sz;
771 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
773 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
774#ifdef MFCNT
775 ioc->mfcnt++;
776#endif
777 }
778 else
779 mf = NULL;
780 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
781
782#ifdef MFCNT
783 if (mf == NULL)
784 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
785 mfcounter++;
786 if (mfcounter == PRINT_MF_COUNT)
787 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
788#endif
789
790 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
791 ioc->name, handle, ioc->id, mf));
792 return mf;
793}
794
795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
796/**
797 * mpt_put_msg_frame - Send a protocol specific MPT request frame
798 * to a IOC.
799 * @handle: Handle of registered MPT protocol driver
800 * @ioc: Pointer to MPT adapter structure
801 * @mf: Pointer to MPT request frame
802 *
803 * This routine posts a MPT request frame to the request post FIFO of a
804 * specific MPT adapter.
805 */
806void
807mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
808{
809 u32 mf_dma_addr;
810 int req_offset;
811 u16 req_idx; /* Request index */
812
813 /* ensure values are reset properly! */
814 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
815 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
816 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500817 req_idx = req_offset / ioc->req_sz;
818 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
820
821#ifdef MPT_DEBUG_MSG_FRAME
822 {
823 u32 *m = mf->u.frame.hwhdr.__hdr;
824 int ii, n;
825
826 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
827 ioc->name, m);
828 n = ioc->req_sz/4 - 1;
829 while (m[n] == 0)
830 n--;
831 for (ii=0; ii<=n; ii++) {
832 if (ii && ((ii%8)==0))
833 printk("\n" KERN_INFO " ");
834 printk(" %08x", le32_to_cpu(m[ii]));
835 }
836 printk("\n");
837 }
838#endif
839
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200840 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
842 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
843}
844
845/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
846/**
847 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
848 * @handle: Handle of registered MPT protocol driver
849 * @ioc: Pointer to MPT adapter structure
850 * @mf: Pointer to MPT request frame
851 *
852 * This routine places a MPT request frame back on the MPT adapter's
853 * FreeQ.
854 */
855void
856mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
857{
858 unsigned long flags;
859
860 /* Put Request back on FreeQ! */
861 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200862 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
864#ifdef MFCNT
865 ioc->mfcnt--;
866#endif
867 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
868}
869
870/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
871/**
872 * mpt_add_sge - Place a simple SGE at address pAddr.
873 * @pAddr: virtual address for SGE
874 * @flagslength: SGE flags and data transfer length
875 * @dma_addr: Physical address
876 *
877 * This routine places a MPT request frame back on the MPT adapter's
878 * FreeQ.
879 */
880void
881mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
882{
883 if (sizeof(dma_addr_t) == sizeof(u64)) {
884 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
885 u32 tmp = dma_addr & 0xFFFFFFFF;
886
887 pSge->FlagsLength = cpu_to_le32(flagslength);
888 pSge->Address.Low = cpu_to_le32(tmp);
889 tmp = (u32) ((u64)dma_addr >> 32);
890 pSge->Address.High = cpu_to_le32(tmp);
891
892 } else {
893 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
894 pSge->FlagsLength = cpu_to_le32(flagslength);
895 pSge->Address = cpu_to_le32(dma_addr);
896 }
897}
898
899/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
900/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800901 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 * @handle: Handle of registered MPT protocol driver
903 * @ioc: Pointer to MPT adapter structure
904 * @reqBytes: Size of the request in bytes
905 * @req: Pointer to MPT request frame
906 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
907 *
908 * This routine is used exclusively to send MptScsiTaskMgmt
909 * requests since they are required to be sent via doorbell handshake.
910 *
911 * NOTE: It is the callers responsibility to byte-swap fields in the
912 * request which are greater than 1 byte in size.
913 *
914 * Returns 0 for success, non-zero for failure.
915 */
916int
917mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
918{
Eric Moorecd2c6192007-01-29 09:47:47 -0700919 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 u8 *req_as_bytes;
921 int ii;
922
923 /* State is known to be good upon entering
924 * this function so issue the bus reset
925 * request.
926 */
927
928 /*
929 * Emulate what mpt_put_msg_frame() does /wrt to sanity
930 * setting cb_idx/req_idx. But ONLY if this request
931 * is in proper (pre-alloc'd) request buffer range...
932 */
933 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
934 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
935 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
936 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
937 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
938 }
939
940 /* Make sure there are no doorbells */
941 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200942
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 CHIPREG_WRITE32(&ioc->chip->Doorbell,
944 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
945 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
946
947 /* Wait for IOC doorbell int */
948 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
949 return ii;
950 }
951
952 /* Read doorbell and check for active bit */
953 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
954 return -5;
955
956 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200957 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
960
961 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
962 return -2;
963 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 /* Send request via doorbell handshake */
966 req_as_bytes = (u8 *) req;
967 for (ii = 0; ii < reqBytes/4; ii++) {
968 u32 word;
969
970 word = ((req_as_bytes[(ii*4) + 0] << 0) |
971 (req_as_bytes[(ii*4) + 1] << 8) |
972 (req_as_bytes[(ii*4) + 2] << 16) |
973 (req_as_bytes[(ii*4) + 3] << 24));
974 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
975 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
976 r = -3;
977 break;
978 }
979 }
980
981 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
982 r = 0;
983 else
984 r = -4;
985
986 /* Make sure there are no doorbells */
987 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 return r;
990}
991
992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
993/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800994 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200995 * @ioc: Pointer to MPT adapter structure
996 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800997 * @sleepFlag: Specifies whether the process can sleep
998 *
999 * Provides mechanism for the host driver to control the IOC's
1000 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001001 *
1002 * Access Control Value - bits[15:12]
1003 * 0h Reserved
1004 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1005 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1006 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1007 *
1008 * Returns 0 for success, non-zero for failure.
1009 */
1010
1011static int
1012mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1013{
1014 int r = 0;
1015
1016 /* return if in use */
1017 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1018 & MPI_DOORBELL_ACTIVE)
1019 return -1;
1020
1021 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1022
1023 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1024 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1025 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1026 (access_control_value<<12)));
1027
1028 /* Wait for IOC to clear Doorbell Status bit */
1029 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1030 return -2;
1031 }else
1032 return 0;
1033}
1034
1035/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1036/**
1037 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001038 * @ioc: Pointer to pointer to IOC adapter
1039 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001040 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001041 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001042 * Returns 0 for success, non-zero for failure.
1043 */
1044static int
1045mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1046{
1047 char *psge;
1048 int flags_length;
1049 u32 host_page_buffer_sz=0;
1050
1051 if(!ioc->HostPageBuffer) {
1052
1053 host_page_buffer_sz =
1054 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1055
1056 if(!host_page_buffer_sz)
1057 return 0; /* fw doesn't need any host buffers */
1058
1059 /* spin till we get enough memory */
1060 while(host_page_buffer_sz > 0) {
1061
1062 if((ioc->HostPageBuffer = pci_alloc_consistent(
1063 ioc->pcidev,
1064 host_page_buffer_sz,
1065 &ioc->HostPageBuffer_dma)) != NULL) {
1066
1067 dinitprintk((MYIOC_s_INFO_FMT
1068 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001069 ioc->name, ioc->HostPageBuffer,
1070 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001071 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001072 ioc->alloc_total += host_page_buffer_sz;
1073 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1074 break;
1075 }
1076
1077 host_page_buffer_sz -= (4*1024);
1078 }
1079 }
1080
1081 if(!ioc->HostPageBuffer) {
1082 printk(MYIOC_s_ERR_FMT
1083 "Failed to alloc memory for host_page_buffer!\n",
1084 ioc->name);
1085 return -999;
1086 }
1087
1088 psge = (char *)&ioc_init->HostPageBufferSGE;
1089 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1090 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1091 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1092 MPI_SGE_FLAGS_HOST_TO_IOC |
1093 MPI_SGE_FLAGS_END_OF_BUFFER;
1094 if (sizeof(dma_addr_t) == sizeof(u64)) {
1095 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1096 }
1097 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1098 flags_length |= ioc->HostPageBuffer_sz;
1099 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1100 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1101
1102return 0;
1103}
1104
1105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1106/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001107 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 * @iocid: IOC unique identifier (integer)
1109 * @iocpp: Pointer to pointer to IOC adapter
1110 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001111 * Given a unique IOC identifier, set pointer to the associated MPT
1112 * adapter structure.
1113 *
1114 * Returns iocid and sets iocpp if iocid is found.
1115 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 */
1117int
1118mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1119{
1120 MPT_ADAPTER *ioc;
1121
1122 list_for_each_entry(ioc,&ioc_list,list) {
1123 if (ioc->id == iocid) {
1124 *iocpp =ioc;
1125 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001128
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 *iocpp = NULL;
1130 return -1;
1131}
1132
1133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001134/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001135 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001137 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 *
1139 * This routine performs all the steps necessary to bring the IOC of
1140 * a MPT adapter to a OPERATIONAL state. This includes registering
1141 * memory regions, registering the interrupt, and allocating request
1142 * and reply memory pools.
1143 *
1144 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1145 * MPT adapter.
1146 *
1147 * Returns 0 for success, non-zero for failure.
1148 *
1149 * TODO: Add support for polled controllers
1150 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001151int
1152mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153{
1154 MPT_ADAPTER *ioc;
1155 u8 __iomem *mem;
1156 unsigned long mem_phys;
1157 unsigned long port;
1158 u32 msize;
1159 u32 psize;
1160 int ii;
1161 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 u8 revision;
1163 u8 pcixcmd;
1164 static int mpt_ids = 0;
1165#ifdef CONFIG_PROC_FS
1166 struct proc_dir_entry *dent, *ent;
1167#endif
1168
1169 if (pci_enable_device(pdev))
1170 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001171
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001173
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001174 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 dprintk((KERN_INFO MYNAM
1176 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001177 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1179 return r;
1180 }
1181
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001182 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 dprintk((KERN_INFO MYNAM
1184 ": Using 64 bit consistent mask\n"));
1185 else
1186 dprintk((KERN_INFO MYNAM
1187 ": Not using 64 bit consistent mask\n"));
1188
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001189 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 if (ioc == NULL) {
1191 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1192 return -ENOMEM;
1193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 ioc->alloc_total = sizeof(MPT_ADAPTER);
1195 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1196 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 ioc->pcidev = pdev;
1199 ioc->diagPending = 0;
1200 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001201 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 /* Initialize the event logging.
1204 */
1205 ioc->eventTypes = 0; /* None */
1206 ioc->eventContext = 0;
1207 ioc->eventLogSize = 0;
1208 ioc->events = NULL;
1209
1210#ifdef MFCNT
1211 ioc->mfcnt = 0;
1212#endif
1213
1214 ioc->cached_fw = NULL;
1215
1216 /* Initilize SCSI Config Data structure
1217 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001218 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
1220 /* Initialize the running configQ head.
1221 */
1222 INIT_LIST_HEAD(&ioc->configQ);
1223
Michael Reed05e8ec12006-01-13 14:31:54 -06001224 /* Initialize the fc rport list head.
1225 */
1226 INIT_LIST_HEAD(&ioc->fc_rports);
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 /* Find lookup slot. */
1229 INIT_LIST_HEAD(&ioc->list);
1230 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001231
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 mem_phys = msize = 0;
1233 port = psize = 0;
1234 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1235 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001236 if (psize)
1237 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 /* Get I/O space! */
1239 port = pci_resource_start(pdev, ii);
1240 psize = pci_resource_len(pdev,ii);
1241 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001242 if (msize)
1243 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 /* Get memmap */
1245 mem_phys = pci_resource_start(pdev, ii);
1246 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 }
1248 }
1249 ioc->mem_size = msize;
1250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 mem = NULL;
1252 /* Get logical ptr for PciMem0 space */
1253 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001254 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 if (mem == NULL) {
1256 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1257 kfree(ioc);
1258 return -EINVAL;
1259 }
1260 ioc->memmap = mem;
1261 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1262
1263 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1264 &ioc->facts, &ioc->pfacts[0]));
1265
1266 ioc->mem_phys = mem_phys;
1267 ioc->chip = (SYSIF_REGS __iomem *)mem;
1268
1269 /* Save Port IO values in case we need to do downloadboot */
1270 {
1271 u8 *pmem = (u8*)port;
1272 ioc->pio_mem_phys = port;
1273 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1274 }
1275
1276 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1277 ioc->prod_name = "LSIFC909";
1278 ioc->bus_type = FC;
1279 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001280 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 ioc->prod_name = "LSIFC929";
1282 ioc->bus_type = FC;
1283 }
1284 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1285 ioc->prod_name = "LSIFC919";
1286 ioc->bus_type = FC;
1287 }
1288 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1289 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1290 ioc->bus_type = FC;
1291 if (revision < XL_929) {
1292 ioc->prod_name = "LSIFC929X";
1293 /* 929X Chip Fix. Set Split transactions level
1294 * for PCIX. Set MOST bits to zero.
1295 */
1296 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1297 pcixcmd &= 0x8F;
1298 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1299 } else {
1300 ioc->prod_name = "LSIFC929XL";
1301 /* 929XL Chip Fix. Set MMRBC to 0x08.
1302 */
1303 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1304 pcixcmd |= 0x08;
1305 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1306 }
1307 }
1308 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1309 ioc->prod_name = "LSIFC919X";
1310 ioc->bus_type = FC;
1311 /* 919X Chip Fix. Set Split transactions level
1312 * for PCIX. Set MOST bits to zero.
1313 */
1314 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1315 pcixcmd &= 0x8F;
1316 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1317 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001318 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1319 ioc->prod_name = "LSIFC939X";
1320 ioc->bus_type = FC;
1321 ioc->errata_flag_1064 = 1;
1322 }
1323 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1324 ioc->prod_name = "LSIFC949X";
1325 ioc->bus_type = FC;
1326 ioc->errata_flag_1064 = 1;
1327 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001328 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1329 ioc->prod_name = "LSIFC949E";
1330 ioc->bus_type = FC;
1331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1333 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001334 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 /* 1030 Chip Fix. Disable Split transactions
1336 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1337 */
1338 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1339 if (revision < C0_1030) {
1340 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1341 pcixcmd &= 0x8F;
1342 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1343 }
1344 }
1345 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1346 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001347 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001349 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1350 ioc->prod_name = "LSISAS1064";
1351 ioc->bus_type = SAS;
1352 ioc->errata_flag_1064 = 1;
1353 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001354 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1355 ioc->prod_name = "LSISAS1068";
1356 ioc->bus_type = SAS;
1357 ioc->errata_flag_1064 = 1;
1358 }
1359 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1360 ioc->prod_name = "LSISAS1064E";
1361 ioc->bus_type = SAS;
1362 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001363 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1364 ioc->prod_name = "LSISAS1068E";
1365 ioc->bus_type = SAS;
1366 }
Eric Moore87cf8982006-06-27 16:09:26 -06001367 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
1368 ioc->prod_name = "LSISAS1078";
1369 ioc->bus_type = SAS;
1370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001372 if (ioc->errata_flag_1064)
1373 pci_disable_io_access(pdev);
1374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 sprintf(ioc->name, "ioc%d", ioc->id);
1376
1377 spin_lock_init(&ioc->FreeQlock);
1378
1379 /* Disable all! */
1380 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1381 ioc->active = 0;
1382 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1383
1384 /* Set lookup ptr. */
1385 list_add_tail(&ioc->list, &ioc_list);
1386
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001387 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 */
1389 mpt_detect_bound_ports(ioc, pdev);
1390
James Bottomleyc92f2222006-03-01 09:02:49 -06001391 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1392 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 printk(KERN_WARNING MYNAM
1394 ": WARNING - %s did not initialize properly! (%d)\n",
1395 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001398 if (ioc->alt_ioc)
1399 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 iounmap(mem);
1401 kfree(ioc);
1402 pci_set_drvdata(pdev, NULL);
1403 return r;
1404 }
1405
1406 /* call per device driver probe entry point */
1407 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1408 if(MptDeviceDriverHandlers[ii] &&
1409 MptDeviceDriverHandlers[ii]->probe) {
1410 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1411 }
1412 }
1413
1414#ifdef CONFIG_PROC_FS
1415 /*
1416 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1417 */
1418 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1419 if (dent) {
1420 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1421 if (ent) {
1422 ent->read_proc = procmpt_iocinfo_read;
1423 ent->data = ioc;
1424 }
1425 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1426 if (ent) {
1427 ent->read_proc = procmpt_summary_read;
1428 ent->data = ioc;
1429 }
1430 }
1431#endif
1432
1433 return 0;
1434}
1435
1436/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001437/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001438 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 */
1441
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001442void
1443mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444{
1445 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1446 char pname[32];
1447 int ii;
1448
1449 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1450 remove_proc_entry(pname, NULL);
1451 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1452 remove_proc_entry(pname, NULL);
1453 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1454 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001455
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 /* call per device driver remove entry point */
1457 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1458 if(MptDeviceDriverHandlers[ii] &&
1459 MptDeviceDriverHandlers[ii]->remove) {
1460 MptDeviceDriverHandlers[ii]->remove(pdev);
1461 }
1462 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001463
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 /* Disable interrupts! */
1465 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1466
1467 ioc->active = 0;
1468 synchronize_irq(pdev->irq);
1469
1470 /* Clear any lingering interrupt */
1471 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1472
1473 CHIPREG_READ32(&ioc->chip->IntStatus);
1474
1475 mpt_adapter_dispose(ioc);
1476
1477 pci_set_drvdata(pdev, NULL);
1478}
1479
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480/**************************************************************************
1481 * Power Management
1482 */
1483#ifdef CONFIG_PM
1484/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001485/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001486 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001487 * @pdev: Pointer to pci_dev structure
1488 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001490int
1491mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492{
1493 u32 device_state;
1494 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
Pavel Machek2a569572005-07-07 17:56:40 -07001496 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
1498 printk(MYIOC_s_INFO_FMT
1499 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1500 ioc->name, pdev, pci_name(pdev), device_state);
1501
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 pci_save_state(pdev);
1503
1504 /* put ioc into READY_STATE */
1505 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1506 printk(MYIOC_s_ERR_FMT
1507 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1508 }
1509
1510 /* disable interrupts */
1511 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1512 ioc->active = 0;
1513
1514 /* Clear any lingering interrupt */
1515 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1516
1517 pci_disable_device(pdev);
1518 pci_set_power_state(pdev, device_state);
1519
1520 return 0;
1521}
1522
1523/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001524/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001525 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001526 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001528int
1529mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530{
1531 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1532 u32 device_state = pdev->current_state;
1533 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 printk(MYIOC_s_INFO_FMT
1536 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1537 ioc->name, pdev, pci_name(pdev), device_state);
1538
1539 pci_set_power_state(pdev, 0);
1540 pci_restore_state(pdev);
1541 pci_enable_device(pdev);
1542
1543 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001544 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 ioc->active = 1;
1546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 printk(MYIOC_s_INFO_FMT
1548 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1549 ioc->name,
1550 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1551 CHIPREG_READ32(&ioc->chip->Doorbell));
1552
1553 /* bring ioc to operational state */
1554 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1555 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1556 printk(MYIOC_s_INFO_FMT
1557 "pci-resume: Cannot recover, error:[%x]\n",
1558 ioc->name, recovery_state);
1559 } else {
1560 printk(MYIOC_s_INFO_FMT
1561 "pci-resume: success\n", ioc->name);
1562 }
1563
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 return 0;
1565}
1566#endif
1567
James Bottomley4ff42a62006-05-17 18:06:52 -05001568static int
1569mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1570{
1571 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1572 ioc->bus_type != SPI) ||
1573 (MptDriverClass[index] == MPTFC_DRIVER &&
1574 ioc->bus_type != FC) ||
1575 (MptDriverClass[index] == MPTSAS_DRIVER &&
1576 ioc->bus_type != SAS))
1577 /* make sure we only call the relevant reset handler
1578 * for the bus */
1579 return 0;
1580 return (MptResetHandlers[index])(ioc, reset_phase);
1581}
1582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001584/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1586 * @ioc: Pointer to MPT adapter structure
1587 * @reason: Event word / reason
1588 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1589 *
1590 * This routine performs all the steps necessary to bring the IOC
1591 * to a OPERATIONAL state.
1592 *
1593 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1594 * MPT adapter.
1595 *
1596 * Returns:
1597 * 0 for success
1598 * -1 if failed to get board READY
1599 * -2 if READY but IOCFacts Failed
1600 * -3 if READY but PrimeIOCFifos Failed
1601 * -4 if READY but IOCInit Failed
1602 */
1603static int
1604mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1605{
1606 int hard_reset_done = 0;
1607 int alt_ioc_ready = 0;
1608 int hard;
1609 int rc=0;
1610 int ii;
1611 int handlers;
1612 int ret = 0;
1613 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001614 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
1616 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1617 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1618
1619 /* Disable reply interrupts (also blocks FreeQ) */
1620 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1621 ioc->active = 0;
1622
1623 if (ioc->alt_ioc) {
1624 if (ioc->alt_ioc->active)
1625 reset_alt_ioc_active = 1;
1626
1627 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1628 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1629 ioc->alt_ioc->active = 0;
1630 }
1631
1632 hard = 1;
1633 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1634 hard = 0;
1635
1636 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1637 if (hard_reset_done == -4) {
1638 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1639 ioc->name);
1640
1641 if (reset_alt_ioc_active && ioc->alt_ioc) {
1642 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1643 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1644 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001645 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 ioc->alt_ioc->active = 1;
1647 }
1648
1649 } else {
1650 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1651 ioc->name);
1652 }
1653 return -1;
1654 }
1655
1656 /* hard_reset_done = 0 if a soft reset was performed
1657 * and 1 if a hard reset was performed.
1658 */
1659 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1660 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1661 alt_ioc_ready = 1;
1662 else
1663 printk(KERN_WARNING MYNAM
1664 ": alt-%s: Not ready WARNING!\n",
1665 ioc->alt_ioc->name);
1666 }
1667
1668 for (ii=0; ii<5; ii++) {
1669 /* Get IOC facts! Allow 5 retries */
1670 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1671 break;
1672 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001673
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 if (ii == 5) {
1676 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1677 ret = -2;
1678 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1679 MptDisplayIocCapabilities(ioc);
1680 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 if (alt_ioc_ready) {
1683 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1684 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1685 /* Retry - alt IOC was initialized once
1686 */
1687 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1688 }
1689 if (rc) {
1690 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1691 alt_ioc_ready = 0;
1692 reset_alt_ioc_active = 0;
1693 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1694 MptDisplayIocCapabilities(ioc->alt_ioc);
1695 }
1696 }
1697
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001698 /*
1699 * Device is reset now. It must have de-asserted the interrupt line
1700 * (if it was asserted) and it should be safe to register for the
1701 * interrupt now.
1702 */
1703 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1704 ioc->pci_irq = -1;
1705 if (ioc->pcidev->irq) {
1706 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1707 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1708 ioc->name);
1709 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001710 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001711 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001712 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1713 "interrupt %d!\n", ioc->name,
1714 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001715 if (mpt_msi_enable)
1716 pci_disable_msi(ioc->pcidev);
1717 return -EBUSY;
1718 }
1719 irq_allocated = 1;
1720 ioc->pci_irq = ioc->pcidev->irq;
1721 pci_set_master(ioc->pcidev); /* ?? */
1722 pci_set_drvdata(ioc->pcidev, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001723 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1724 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001725 }
1726 }
1727
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 /* Prime reply & request queues!
1729 * (mucho alloc's) Must be done prior to
1730 * init as upper addresses are needed for init.
1731 * If fails, continue with alt-ioc processing
1732 */
1733 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1734 ret = -3;
1735
1736 /* May need to check/upload firmware & data here!
1737 * If fails, continue with alt-ioc processing
1738 */
1739 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1740 ret = -4;
1741// NEW!
1742 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1743 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1744 ioc->alt_ioc->name, rc);
1745 alt_ioc_ready = 0;
1746 reset_alt_ioc_active = 0;
1747 }
1748
1749 if (alt_ioc_ready) {
1750 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1751 alt_ioc_ready = 0;
1752 reset_alt_ioc_active = 0;
1753 printk(KERN_WARNING MYNAM
1754 ": alt-%s: (%d) init failure WARNING!\n",
1755 ioc->alt_ioc->name, rc);
1756 }
1757 }
1758
1759 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1760 if (ioc->upload_fw) {
1761 ddlprintk((MYIOC_s_INFO_FMT
1762 "firmware upload required!\n", ioc->name));
1763
1764 /* Controller is not operational, cannot do upload
1765 */
1766 if (ret == 0) {
1767 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001768 if (rc == 0) {
1769 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1770 /*
1771 * Maintain only one pointer to FW memory
1772 * so there will not be two attempt to
1773 * downloadboot onboard dual function
1774 * chips (mpt_adapter_disable,
1775 * mpt_diag_reset)
1776 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001777 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1778 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06001779 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001780 }
1781 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001783 ret = -5;
1784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 }
1786 }
1787 }
1788
1789 if (ret == 0) {
1790 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001791 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 ioc->active = 1;
1793 }
1794
1795 if (reset_alt_ioc_active && ioc->alt_ioc) {
1796 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001797 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001799 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 ioc->alt_ioc->active = 1;
1801 }
1802
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001803 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 * and EventAck handling.
1805 */
1806 if ((ret == 0) && (!ioc->facts.EventState))
1807 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1808
1809 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1810 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1811
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001812 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1814 * recursive scenario; GetLanConfigPages times out, timer expired
1815 * routine calls HardResetHandler, which calls into here again,
1816 * and we try GetLanConfigPages again...
1817 */
1818 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07001819
1820 /*
1821 * Initalize link list for inactive raid volumes.
1822 */
1823 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
1824 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
1825
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001826 if (ioc->bus_type == SAS) {
1827
1828 /* clear persistency table */
1829 if(ioc->facts.IOCExceptions &
1830 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1831 ret = mptbase_sas_persist_operation(ioc,
1832 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1833 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001834 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001835 }
1836
1837 /* Find IM volumes
1838 */
1839 mpt_findImVolumes(ioc);
1840
1841 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1843 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1844 /*
1845 * Pre-fetch the ports LAN MAC address!
1846 * (LANPage1_t stuff)
1847 */
1848 (void) GetLanConfigPages(ioc);
1849#ifdef MPT_DEBUG
1850 {
1851 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1852 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1853 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1854 }
1855#endif
1856 }
1857 } else {
1858 /* Get NVRAM and adapter maximums from SPP 0 and 2
1859 */
1860 mpt_GetScsiPortSettings(ioc, 0);
1861
1862 /* Get version and length of SDP 1
1863 */
1864 mpt_readScsiDevicePageHeaders(ioc, 0);
1865
1866 /* Find IM volumes
1867 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001868 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 mpt_findImVolumes(ioc);
1870
1871 /* Check, and possibly reset, the coalescing value
1872 */
1873 mpt_read_ioc_pg_1(ioc);
1874
1875 mpt_read_ioc_pg_4(ioc);
1876 }
1877
1878 GetIoUnitPage2(ioc);
1879 }
1880
1881 /*
1882 * Call each currently registered protocol IOC reset handler
1883 * with post-reset indication.
1884 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1885 * MptResetHandlers[] registered yet.
1886 */
1887 if (hard_reset_done) {
1888 rc = handlers = 0;
1889 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1890 if ((ret == 0) && MptResetHandlers[ii]) {
1891 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1892 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001893 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 handlers++;
1895 }
1896
1897 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001898 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001900 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 handlers++;
1902 }
1903 }
1904 /* FIXME? Examine results here? */
1905 }
1906
Eric Moore0ccdb002006-07-11 17:33:13 -06001907 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001908 if ((ret != 0) && irq_allocated) {
1909 free_irq(ioc->pci_irq, ioc);
1910 if (mpt_msi_enable)
1911 pci_disable_msi(ioc->pcidev);
1912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 return ret;
1914}
1915
1916/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001917/**
1918 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 * @ioc: Pointer to MPT adapter structure
1920 * @pdev: Pointer to (struct pci_dev) structure
1921 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001922 * Search for PCI bus/dev_function which matches
1923 * PCI bus/dev_function (+/-1) for newly discovered 929,
1924 * 929X, 1030 or 1035.
1925 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1927 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1928 */
1929static void
1930mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1931{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001932 struct pci_dev *peer=NULL;
1933 unsigned int slot = PCI_SLOT(pdev->devfn);
1934 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 MPT_ADAPTER *ioc_srch;
1936
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001937 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1938 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001939 ioc->name, pci_name(pdev), pdev->bus->number,
1940 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001941
1942 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1943 if (!peer) {
1944 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1945 if (!peer)
1946 return;
1947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
1949 list_for_each_entry(ioc_srch, &ioc_list, list) {
1950 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001951 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 /* Paranoia checks */
1953 if (ioc->alt_ioc != NULL) {
1954 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001955 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 break;
1957 } else if (ioc_srch->alt_ioc != NULL) {
1958 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001959 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 break;
1961 }
1962 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001963 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 ioc_srch->alt_ioc = ioc;
1965 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 }
1967 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001968 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969}
1970
1971/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001972/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001974 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 */
1976static void
1977mpt_adapter_disable(MPT_ADAPTER *ioc)
1978{
1979 int sz;
1980 int ret;
1981
1982 if (ioc->cached_fw != NULL) {
1983 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001984 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 printk(KERN_WARNING MYNAM
1986 ": firmware downloadboot failure (%d)!\n", ret);
1987 }
1988 }
1989
1990 /* Disable adapter interrupts! */
1991 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1992 ioc->active = 0;
1993 /* Clear any lingering interrupt */
1994 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1995
1996 if (ioc->alloc != NULL) {
1997 sz = ioc->alloc_sz;
1998 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1999 ioc->name, ioc->alloc, ioc->alloc_sz));
2000 pci_free_consistent(ioc->pcidev, sz,
2001 ioc->alloc, ioc->alloc_dma);
2002 ioc->reply_frames = NULL;
2003 ioc->req_frames = NULL;
2004 ioc->alloc = NULL;
2005 ioc->alloc_total -= sz;
2006 }
2007
2008 if (ioc->sense_buf_pool != NULL) {
2009 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2010 pci_free_consistent(ioc->pcidev, sz,
2011 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2012 ioc->sense_buf_pool = NULL;
2013 ioc->alloc_total -= sz;
2014 }
2015
2016 if (ioc->events != NULL){
2017 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2018 kfree(ioc->events);
2019 ioc->events = NULL;
2020 ioc->alloc_total -= sz;
2021 }
2022
2023 if (ioc->cached_fw != NULL) {
2024 sz = ioc->facts.FWImageSize;
2025 pci_free_consistent(ioc->pcidev, sz,
2026 ioc->cached_fw, ioc->cached_fw_dma);
2027 ioc->cached_fw = NULL;
2028 ioc->alloc_total -= sz;
2029 }
2030
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002031 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002032 mpt_inactive_raid_list_free(ioc);
2033 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002034 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002035 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002036 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037
2038 if (ioc->spi_data.pIocPg4 != NULL) {
2039 sz = ioc->spi_data.IocPg4Sz;
2040 pci_free_consistent(ioc->pcidev, sz,
2041 ioc->spi_data.pIocPg4,
2042 ioc->spi_data.IocPg4_dma);
2043 ioc->spi_data.pIocPg4 = NULL;
2044 ioc->alloc_total -= sz;
2045 }
2046
2047 if (ioc->ReqToChain != NULL) {
2048 kfree(ioc->ReqToChain);
2049 kfree(ioc->RequestNB);
2050 ioc->ReqToChain = NULL;
2051 }
2052
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002053 kfree(ioc->ChainToChain);
2054 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002055
2056 if (ioc->HostPageBuffer != NULL) {
2057 if((ret = mpt_host_page_access_control(ioc,
2058 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2059 printk(KERN_ERR MYNAM
2060 ": %s: host page buffers free failed (%d)!\n",
2061 __FUNCTION__, ret);
2062 }
2063 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2064 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2065 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2066 ioc->HostPageBuffer,
2067 ioc->HostPageBuffer_dma);
2068 ioc->HostPageBuffer = NULL;
2069 ioc->HostPageBuffer_sz = 0;
2070 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072}
2073
2074/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002075/**
2076 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 * @ioc: Pointer to MPT adapter structure
2078 *
2079 * This routine unregisters h/w resources and frees all alloc'd memory
2080 * associated with a MPT adapter structure.
2081 */
2082static void
2083mpt_adapter_dispose(MPT_ADAPTER *ioc)
2084{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002085 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002087 if (ioc == NULL)
2088 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002090 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002092 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002094 if (ioc->pci_irq != -1) {
2095 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002096 if (mpt_msi_enable)
2097 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002098 ioc->pci_irq = -1;
2099 }
2100
2101 if (ioc->memmap != NULL) {
2102 iounmap(ioc->memmap);
2103 ioc->memmap = NULL;
2104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
2106#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002107 if (ioc->mtrr_reg > 0) {
2108 mtrr_del(ioc->mtrr_reg, 0, 0);
2109 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111#endif
2112
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002113 /* Zap the adapter lookup ptr! */
2114 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002116 sz_last = ioc->alloc_total;
2117 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2118 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002119
2120 if (ioc->alt_ioc)
2121 ioc->alt_ioc->alt_ioc = NULL;
2122
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002123 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124}
2125
2126/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002127/**
2128 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 * @ioc: Pointer to MPT adapter structure
2130 */
2131static void
2132MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2133{
2134 int i = 0;
2135
2136 printk(KERN_INFO "%s: ", ioc->name);
2137 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2138 printk("%s: ", ioc->prod_name+3);
2139 printk("Capabilities={");
2140
2141 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2142 printk("Initiator");
2143 i++;
2144 }
2145
2146 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2147 printk("%sTarget", i ? "," : "");
2148 i++;
2149 }
2150
2151 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2152 printk("%sLAN", i ? "," : "");
2153 i++;
2154 }
2155
2156#if 0
2157 /*
2158 * This would probably evoke more questions than it's worth
2159 */
2160 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2161 printk("%sLogBusAddr", i ? "," : "");
2162 i++;
2163 }
2164#endif
2165
2166 printk("}\n");
2167}
2168
2169/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002170/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2172 * @ioc: Pointer to MPT_ADAPTER structure
2173 * @force: Force hard KickStart of IOC
2174 * @sleepFlag: Specifies whether the process can sleep
2175 *
2176 * Returns:
2177 * 1 - DIAG reset and READY
2178 * 0 - READY initially OR soft reset and READY
2179 * -1 - Any failure on KickStart
2180 * -2 - Msg Unit Reset Failed
2181 * -3 - IO Unit Reset Failed
2182 * -4 - IOC owned by a PEER
2183 */
2184static int
2185MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2186{
2187 u32 ioc_state;
2188 int statefault = 0;
2189 int cntdn;
2190 int hard_reset_done = 0;
2191 int r;
2192 int ii;
2193 int whoinit;
2194
2195 /* Get current [raw] IOC state */
2196 ioc_state = mpt_GetIocState(ioc, 0);
2197 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2198
2199 /*
2200 * Check to see if IOC got left/stuck in doorbell handshake
2201 * grip of death. If so, hard reset the IOC.
2202 */
2203 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2204 statefault = 1;
2205 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2206 ioc->name);
2207 }
2208
2209 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002210 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 return 0;
2212
2213 /*
2214 * Check to see if IOC is in FAULT state.
2215 */
2216 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2217 statefault = 2;
2218 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2219 ioc->name);
2220 printk(KERN_WARNING " FAULT code = %04xh\n",
2221 ioc_state & MPI_DOORBELL_DATA_MASK);
2222 }
2223
2224 /*
2225 * Hmmm... Did it get left operational?
2226 */
2227 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002228 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 ioc->name));
2230
2231 /* Check WhoInit.
2232 * If PCI Peer, exit.
2233 * Else, if no fault conditions are present, issue a MessageUnitReset
2234 * Else, fall through to KickStart case
2235 */
2236 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002237 dinitprintk((KERN_INFO MYNAM
2238 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 whoinit, statefault, force));
2240 if (whoinit == MPI_WHOINIT_PCI_PEER)
2241 return -4;
2242 else {
2243 if ((statefault == 0 ) && (force == 0)) {
2244 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2245 return 0;
2246 }
2247 statefault = 3;
2248 }
2249 }
2250
2251 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2252 if (hard_reset_done < 0)
2253 return -1;
2254
2255 /*
2256 * Loop here waiting for IOC to come READY.
2257 */
2258 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002259 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260
2261 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2262 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2263 /*
2264 * BIOS or previous driver load left IOC in OP state.
2265 * Reset messaging FIFOs.
2266 */
2267 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2268 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2269 return -2;
2270 }
2271 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2272 /*
2273 * Something is wrong. Try to get IOC back
2274 * to a known state.
2275 */
2276 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2277 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2278 return -3;
2279 }
2280 }
2281
2282 ii++; cntdn--;
2283 if (!cntdn) {
2284 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2285 ioc->name, (int)((ii+5)/HZ));
2286 return -ETIME;
2287 }
2288
2289 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002290 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 } else {
2292 mdelay (1); /* 1 msec delay */
2293 }
2294
2295 }
2296
2297 if (statefault < 3) {
2298 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2299 ioc->name,
2300 statefault==1 ? "stuck handshake" : "IOC FAULT");
2301 }
2302
2303 return hard_reset_done;
2304}
2305
2306/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002307/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 * mpt_GetIocState - Get the current state of a MPT adapter.
2309 * @ioc: Pointer to MPT_ADAPTER structure
2310 * @cooked: Request raw or cooked IOC state
2311 *
2312 * Returns all IOC Doorbell register bits if cooked==0, else just the
2313 * Doorbell bits in MPI_IOC_STATE_MASK.
2314 */
2315u32
2316mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2317{
2318 u32 s, sc;
2319
2320 /* Get! */
2321 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2322// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2323 sc = s & MPI_IOC_STATE_MASK;
2324
2325 /* Save! */
2326 ioc->last_state = sc;
2327
2328 return cooked ? sc : s;
2329}
2330
2331/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002332/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 * GetIocFacts - Send IOCFacts request to MPT adapter.
2334 * @ioc: Pointer to MPT_ADAPTER structure
2335 * @sleepFlag: Specifies whether the process can sleep
2336 * @reason: If recovery, only update facts.
2337 *
2338 * Returns 0 for success, non-zero for failure.
2339 */
2340static int
2341GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2342{
2343 IOCFacts_t get_facts;
2344 IOCFactsReply_t *facts;
2345 int r;
2346 int req_sz;
2347 int reply_sz;
2348 int sz;
2349 u32 status, vv;
2350 u8 shiftFactor=1;
2351
2352 /* IOC *must* NOT be in RESET state! */
2353 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2354 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2355 ioc->name,
2356 ioc->last_state );
2357 return -44;
2358 }
2359
2360 facts = &ioc->facts;
2361
2362 /* Destination (reply area)... */
2363 reply_sz = sizeof(*facts);
2364 memset(facts, 0, reply_sz);
2365
2366 /* Request area (get_facts on the stack right now!) */
2367 req_sz = sizeof(get_facts);
2368 memset(&get_facts, 0, req_sz);
2369
2370 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2371 /* Assert: All other get_facts fields are zero! */
2372
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002373 dinitprintk((MYIOC_s_INFO_FMT
2374 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 ioc->name, req_sz, reply_sz));
2376
2377 /* No non-zero fields in the get_facts request are greater than
2378 * 1 byte in size, so we can just fire it off as is.
2379 */
2380 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2381 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2382 if (r != 0)
2383 return r;
2384
2385 /*
2386 * Now byte swap (GRRR) the necessary fields before any further
2387 * inspection of reply contents.
2388 *
2389 * But need to do some sanity checks on MsgLength (byte) field
2390 * to make sure we don't zero IOC's req_sz!
2391 */
2392 /* Did we get a valid reply? */
2393 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2394 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2395 /*
2396 * If not been here, done that, save off first WhoInit value
2397 */
2398 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2399 ioc->FirstWhoInit = facts->WhoInit;
2400 }
2401
2402 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2403 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2404 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2405 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2406 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002407 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 /* CHECKME! IOCStatus, IOCLogInfo */
2409
2410 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2411 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2412
2413 /*
2414 * FC f/w version changed between 1.1 and 1.2
2415 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2416 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2417 */
2418 if (facts->MsgVersion < 0x0102) {
2419 /*
2420 * Handle old FC f/w style, convert to new...
2421 */
2422 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2423 facts->FWVersion.Word =
2424 ((oldv<<12) & 0xFF000000) |
2425 ((oldv<<8) & 0x000FFF00);
2426 } else
2427 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2428
2429 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002430 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2431 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2432 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 facts->CurrentHostMfaHighAddr =
2434 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2435 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2436 facts->CurrentSenseBufferHighAddr =
2437 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2438 facts->CurReplyFrameSize =
2439 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002440 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
2442 /*
2443 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2444 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2445 * to 14 in MPI-1.01.0x.
2446 */
2447 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2448 facts->MsgVersion > 0x0100) {
2449 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2450 }
2451
2452 sz = facts->FWImageSize;
2453 if ( sz & 0x01 )
2454 sz += 1;
2455 if ( sz & 0x02 )
2456 sz += 2;
2457 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002458
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 if (!facts->RequestFrameSize) {
2460 /* Something is wrong! */
2461 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2462 ioc->name);
2463 return -55;
2464 }
2465
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002466 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 vv = ((63 / (sz * 4)) + 1) & 0x03;
2468 ioc->NB_for_64_byte_frame = vv;
2469 while ( sz )
2470 {
2471 shiftFactor++;
2472 sz = sz >> 1;
2473 }
2474 ioc->NBShiftFactor = shiftFactor;
2475 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2476 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002477
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2479 /*
2480 * Set values for this IOC's request & reply frame sizes,
2481 * and request & reply queue depths...
2482 */
2483 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2484 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2485 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2486 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2487
2488 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2489 ioc->name, ioc->reply_sz, ioc->reply_depth));
2490 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2491 ioc->name, ioc->req_sz, ioc->req_depth));
2492
2493 /* Get port facts! */
2494 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2495 return r;
2496 }
2497 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002498 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2500 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2501 RequestFrameSize)/sizeof(u32)));
2502 return -66;
2503 }
2504
2505 return 0;
2506}
2507
2508/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002509/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 * GetPortFacts - Send PortFacts request to MPT adapter.
2511 * @ioc: Pointer to MPT_ADAPTER structure
2512 * @portnum: Port number
2513 * @sleepFlag: Specifies whether the process can sleep
2514 *
2515 * Returns 0 for success, non-zero for failure.
2516 */
2517static int
2518GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2519{
2520 PortFacts_t get_pfacts;
2521 PortFactsReply_t *pfacts;
2522 int ii;
2523 int req_sz;
2524 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002525 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
2527 /* IOC *must* NOT be in RESET state! */
2528 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2529 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2530 ioc->name,
2531 ioc->last_state );
2532 return -4;
2533 }
2534
2535 pfacts = &ioc->pfacts[portnum];
2536
2537 /* Destination (reply area)... */
2538 reply_sz = sizeof(*pfacts);
2539 memset(pfacts, 0, reply_sz);
2540
2541 /* Request area (get_pfacts on the stack right now!) */
2542 req_sz = sizeof(get_pfacts);
2543 memset(&get_pfacts, 0, req_sz);
2544
2545 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2546 get_pfacts.PortNumber = portnum;
2547 /* Assert: All other get_pfacts fields are zero! */
2548
2549 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2550 ioc->name, portnum));
2551
2552 /* No non-zero fields in the get_pfacts request are greater than
2553 * 1 byte in size, so we can just fire it off as is.
2554 */
2555 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2556 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2557 if (ii != 0)
2558 return ii;
2559
2560 /* Did we get a valid reply? */
2561
2562 /* Now byte swap the necessary fields in the response. */
2563 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2564 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2565 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2566 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2567 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2568 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2569 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2570 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2571 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2572
Eric Moore793955f2007-01-29 09:42:20 -07002573 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2574 pfacts->MaxDevices;
2575 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2576 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2577
2578 /*
2579 * Place all the devices on channels
2580 *
2581 * (for debuging)
2582 */
2583 if (mpt_channel_mapping) {
2584 ioc->devices_per_bus = 1;
2585 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2586 }
2587
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 return 0;
2589}
2590
2591/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002592/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 * SendIocInit - Send IOCInit request to MPT adapter.
2594 * @ioc: Pointer to MPT_ADAPTER structure
2595 * @sleepFlag: Specifies whether the process can sleep
2596 *
2597 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2598 *
2599 * Returns 0 for success, non-zero for failure.
2600 */
2601static int
2602SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2603{
2604 IOCInit_t ioc_init;
2605 MPIDefaultReply_t init_reply;
2606 u32 state;
2607 int r;
2608 int count;
2609 int cntdn;
2610
2611 memset(&ioc_init, 0, sizeof(ioc_init));
2612 memset(&init_reply, 0, sizeof(init_reply));
2613
2614 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2615 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2616
2617 /* If we are in a recovery mode and we uploaded the FW image,
2618 * then this pointer is not NULL. Skip the upload a second time.
2619 * Set this flag if cached_fw set for either IOC.
2620 */
2621 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2622 ioc->upload_fw = 1;
2623 else
2624 ioc->upload_fw = 0;
2625 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2626 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2627
Eric Moore793955f2007-01-29 09:42:20 -07002628 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2629 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002630 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2631 ioc->name, ioc->facts.MsgVersion));
2632 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2633 // set MsgVersion and HeaderVersion host driver was built with
2634 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2635 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002637 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2638 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2639 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2640 return -99;
2641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2643
2644 if (sizeof(dma_addr_t) == sizeof(u64)) {
2645 /* Save the upper 32-bits of the request
2646 * (reply) and sense buffers.
2647 */
2648 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2649 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2650 } else {
2651 /* Force 32-bit addressing */
2652 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2653 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2654 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2657 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002658 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2659 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
2661 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2662 ioc->name, &ioc_init));
2663
2664 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2665 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002666 if (r != 0) {
2667 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
2671 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002672 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 */
2674
2675 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2676 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002677
2678 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2679 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682
2683 /* YIKES! SUPER IMPORTANT!!!
2684 * Poll IocState until _OPERATIONAL while IOC is doing
2685 * LoopInit and TargetDiscovery!
2686 */
2687 count = 0;
2688 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2689 state = mpt_GetIocState(ioc, 1);
2690 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2691 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002692 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 } else {
2694 mdelay(1);
2695 }
2696
2697 if (!cntdn) {
2698 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2699 ioc->name, (int)((count+5)/HZ));
2700 return -9;
2701 }
2702
2703 state = mpt_GetIocState(ioc, 1);
2704 count++;
2705 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002706 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 ioc->name, count));
2708
Eric Mooreba856d32006-07-11 17:34:01 -06002709 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 return r;
2711}
2712
2713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002714/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 * SendPortEnable - Send PortEnable request to MPT adapter port.
2716 * @ioc: Pointer to MPT_ADAPTER structure
2717 * @portnum: Port number to enable
2718 * @sleepFlag: Specifies whether the process can sleep
2719 *
2720 * Send PortEnable to bring IOC to OPERATIONAL state.
2721 *
2722 * Returns 0 for success, non-zero for failure.
2723 */
2724static int
2725SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2726{
2727 PortEnable_t port_enable;
2728 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002729 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 int req_sz;
2731 int reply_sz;
2732
2733 /* Destination... */
2734 reply_sz = sizeof(MPIDefaultReply_t);
2735 memset(&reply_buf, 0, reply_sz);
2736
2737 req_sz = sizeof(PortEnable_t);
2738 memset(&port_enable, 0, req_sz);
2739
2740 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2741 port_enable.PortNumber = portnum;
2742/* port_enable.ChainOffset = 0; */
2743/* port_enable.MsgFlags = 0; */
2744/* port_enable.MsgContext = 0; */
2745
2746 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2747 ioc->name, portnum, &port_enable));
2748
2749 /* RAID FW may take a long time to enable
2750 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002751 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07002752 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2753 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2754 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002755 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002756 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2757 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2758 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002760 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761}
2762
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002763/**
2764 * mpt_alloc_fw_memory - allocate firmware memory
2765 * @ioc: Pointer to MPT_ADAPTER structure
2766 * @size: total FW bytes
2767 *
2768 * If memory has already been allocated, the same (cached) value
2769 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 */
2771void
2772mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2773{
2774 if (ioc->cached_fw)
2775 return; /* use already allocated memory */
2776 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2777 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2778 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06002779 ioc->alloc_total += size;
2780 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 } else {
2782 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2783 ioc->alloc_total += size;
2784 }
2785}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002786/**
2787 * mpt_free_fw_memory - free firmware memory
2788 * @ioc: Pointer to MPT_ADAPTER structure
2789 *
2790 * If alt_img is NULL, delete from ioc structure.
2791 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 */
2793void
2794mpt_free_fw_memory(MPT_ADAPTER *ioc)
2795{
2796 int sz;
2797
2798 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002799 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2801 pci_free_consistent(ioc->pcidev, sz,
2802 ioc->cached_fw, ioc->cached_fw_dma);
2803 ioc->cached_fw = NULL;
2804
2805 return;
2806}
2807
2808
2809/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002810/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2812 * @ioc: Pointer to MPT_ADAPTER structure
2813 * @sleepFlag: Specifies whether the process can sleep
2814 *
2815 * Returns 0 for success, >0 for handshake failure
2816 * <0 for fw upload failure.
2817 *
2818 * Remark: If bound IOC and a successful FWUpload was performed
2819 * on the bound IOC, the second image is discarded
2820 * and memory is free'd. Both channels must upload to prevent
2821 * IOC from running in degraded mode.
2822 */
2823static int
2824mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2825{
2826 u8 request[ioc->req_sz];
2827 u8 reply[sizeof(FWUploadReply_t)];
2828 FWUpload_t *prequest;
2829 FWUploadReply_t *preply;
2830 FWUploadTCSGE_t *ptcsge;
2831 int sgeoffset;
2832 u32 flagsLength;
2833 int ii, sz, reply_sz;
2834 int cmdStatus;
2835
2836 /* If the image size is 0, we are done.
2837 */
2838 if ((sz = ioc->facts.FWImageSize) == 0)
2839 return 0;
2840
2841 mpt_alloc_fw_memory(ioc, sz);
2842
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002843 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002845
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 if (ioc->cached_fw == NULL) {
2847 /* Major Failure.
2848 */
2849 return -ENOMEM;
2850 }
2851
2852 prequest = (FWUpload_t *)&request;
2853 preply = (FWUploadReply_t *)&reply;
2854
2855 /* Destination... */
2856 memset(prequest, 0, ioc->req_sz);
2857
2858 reply_sz = sizeof(reply);
2859 memset(preply, 0, reply_sz);
2860
2861 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2862 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2863
2864 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2865 ptcsge->DetailsLength = 12;
2866 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2867 ptcsge->ImageSize = cpu_to_le32(sz);
2868
2869 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2870
2871 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2872 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2873
2874 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002875 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 prequest, sgeoffset));
2877 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2878
2879 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2880 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2881
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002882 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
2884 cmdStatus = -EFAULT;
2885 if (ii == 0) {
2886 /* Handshake transfer was complete and successful.
2887 * Check the Reply Frame.
2888 */
2889 int status, transfer_sz;
2890 status = le16_to_cpu(preply->IOCStatus);
2891 if (status == MPI_IOCSTATUS_SUCCESS) {
2892 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2893 if (transfer_sz == sz)
2894 cmdStatus = 0;
2895 }
2896 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002897 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 ioc->name, cmdStatus));
2899
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002900
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 if (cmdStatus) {
2902
2903 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2904 ioc->name));
2905 mpt_free_fw_memory(ioc);
2906 }
2907
2908 return cmdStatus;
2909}
2910
2911/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002912/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 * mpt_downloadboot - DownloadBoot code
2914 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002915 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 * @sleepFlag: Specifies whether the process can sleep
2917 *
2918 * FwDownloadBoot requires Programmed IO access.
2919 *
2920 * Returns 0 for success
2921 * -1 FW Image size is 0
2922 * -2 No valid cached_fw Pointer
2923 * <0 for fw upload failure.
2924 */
2925static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002926mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 MpiExtImageHeader_t *pExtImage;
2929 u32 fwSize;
2930 u32 diag0val;
2931 int count;
2932 u32 *ptrFw;
2933 u32 diagRwData;
2934 u32 nextImage;
2935 u32 load_addr;
2936 u32 ioc_state=0;
2937
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002938 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2939 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002940
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2942 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2943 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2944 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2945 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2946 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2947
2948 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2949
2950 /* wait 1 msec */
2951 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002952 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 } else {
2954 mdelay (1);
2955 }
2956
2957 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2958 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2959
2960 for (count = 0; count < 30; count ++) {
2961 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2962 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2963 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2964 ioc->name, count));
2965 break;
2966 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002967 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002969 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002971 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 }
2973 }
2974
2975 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002976 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2977 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 ioc->name, diag0val));
2979 return -3;
2980 }
2981
2982 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2983 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2984 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2985 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2986 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2987 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2988
2989 /* Set the DiagRwEn and Disable ARM bits */
2990 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2991
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 fwSize = (pFwHeader->ImageSize + 3)/4;
2993 ptrFw = (u32 *) pFwHeader;
2994
2995 /* Write the LoadStartAddress to the DiagRw Address Register
2996 * using Programmed IO
2997 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002998 if (ioc->errata_flag_1064)
2999 pci_enable_io_access(ioc->pcidev);
3000
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
3002 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
3003 ioc->name, pFwHeader->LoadStartAddress));
3004
3005 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
3006 ioc->name, fwSize*4, ptrFw));
3007 while (fwSize--) {
3008 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3009 }
3010
3011 nextImage = pFwHeader->NextImageHeaderOffset;
3012 while (nextImage) {
3013 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3014
3015 load_addr = pExtImage->LoadStartAddress;
3016
3017 fwSize = (pExtImage->ImageSize + 3) >> 2;
3018 ptrFw = (u32 *)pExtImage;
3019
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003020 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
3021 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3023
3024 while (fwSize--) {
3025 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3026 }
3027 nextImage = pExtImage->NextImageHeaderOffset;
3028 }
3029
3030 /* Write the IopResetVectorRegAddr */
3031 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3032 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3033
3034 /* Write the IopResetVectorValue */
3035 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3036 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3037
3038 /* Clear the internal flash bad bit - autoincrementing register,
3039 * so must do two writes.
3040 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003041 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003042 /*
3043 * 1030 and 1035 H/W errata, workaround to access
3044 * the ClearFlashBadSignatureBit
3045 */
3046 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3047 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3048 diagRwData |= 0x40000000;
3049 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3050 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3051
3052 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3053 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3054 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3055 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3056
3057 /* wait 1 msec */
3058 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003059 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003060 } else {
3061 mdelay (1);
3062 }
3063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003065 if (ioc->errata_flag_1064)
3066 pci_disable_io_access(ioc->pcidev);
3067
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003069 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3070 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003072 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3074 ioc->name, diag0val));
3075 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3076
3077 /* Write 0xFF to reset the sequencer */
3078 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3079
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003080 if (ioc->bus_type == SAS) {
3081 ioc_state = mpt_GetIocState(ioc, 0);
3082 if ( (GetIocFacts(ioc, sleepFlag,
3083 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3084 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3085 ioc->name, ioc_state));
3086 return -EFAULT;
3087 }
3088 }
3089
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 for (count=0; count<HZ*20; count++) {
3091 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3092 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3093 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003094 if (ioc->bus_type == SAS) {
3095 return 0;
3096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3098 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3099 ioc->name));
3100 return -EFAULT;
3101 }
3102 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3103 ioc->name));
3104 return 0;
3105 }
3106 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003107 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 } else {
3109 mdelay (10);
3110 }
3111 }
3112 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3113 ioc->name, ioc_state));
3114 return -EFAULT;
3115}
3116
3117/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003118/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 * KickStart - Perform hard reset of MPT adapter.
3120 * @ioc: Pointer to MPT_ADAPTER structure
3121 * @force: Force hard reset
3122 * @sleepFlag: Specifies whether the process can sleep
3123 *
3124 * This routine places MPT adapter in diagnostic mode via the
3125 * WriteSequence register, and then performs a hard reset of adapter
3126 * via the Diagnostic register.
3127 *
3128 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3129 * or NO_SLEEP (interrupt thread, use mdelay)
3130 * force - 1 if doorbell active, board fault state
3131 * board operational, IOC_RECOVERY or
3132 * IOC_BRINGUP and there is an alt_ioc.
3133 * 0 else
3134 *
3135 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003136 * 1 - hard reset, READY
3137 * 0 - no reset due to History bit, READY
3138 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 * OR reset but failed to come READY
3140 * -2 - no reset, could not enter DIAG mode
3141 * -3 - reset but bad FW bit
3142 */
3143static int
3144KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3145{
3146 int hard_reset_done = 0;
3147 u32 ioc_state=0;
3148 int cnt,cntdn;
3149
3150 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003151 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 /* Always issue a Msg Unit Reset first. This will clear some
3153 * SCSI bus hang conditions.
3154 */
3155 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3156
3157 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003158 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 } else {
3160 mdelay (1000);
3161 }
3162 }
3163
3164 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3165 if (hard_reset_done < 0)
3166 return hard_reset_done;
3167
3168 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3169 ioc->name));
3170
3171 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3172 for (cnt=0; cnt<cntdn; cnt++) {
3173 ioc_state = mpt_GetIocState(ioc, 1);
3174 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3175 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3176 ioc->name, cnt));
3177 return hard_reset_done;
3178 }
3179 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003180 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 } else {
3182 mdelay (10);
3183 }
3184 }
3185
3186 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3187 ioc->name, ioc_state);
3188 return -1;
3189}
3190
3191/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003192/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 * mpt_diag_reset - Perform hard reset of the adapter.
3194 * @ioc: Pointer to MPT_ADAPTER structure
3195 * @ignore: Set if to honor and clear to ignore
3196 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003197 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 * else set to NO_SLEEP (use mdelay instead)
3199 *
3200 * This routine places the adapter in diagnostic mode via the
3201 * WriteSequence register and then performs a hard reset of adapter
3202 * via the Diagnostic register. Adapter should be in ready state
3203 * upon successful completion.
3204 *
3205 * Returns: 1 hard reset successful
3206 * 0 no reset performed because reset history bit set
3207 * -2 enabling diagnostic mode failed
3208 * -3 diagnostic reset failed
3209 */
3210static int
3211mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3212{
Eric Moore0ccdb002006-07-11 17:33:13 -06003213 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 u32 diag0val;
3215 u32 doorbell;
3216 int hard_reset_done = 0;
3217 int count = 0;
3218#ifdef MPT_DEBUG
3219 u32 diag1val = 0;
3220#endif
3221
Eric Moorecd2c6192007-01-29 09:47:47 -07003222 /* Clear any existing interrupts */
3223 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3224
Eric Moore87cf8982006-06-27 16:09:26 -06003225 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
3226 drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
3227 "address=%p\n", ioc->name, __FUNCTION__,
3228 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3229 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3230 if (sleepFlag == CAN_SLEEP)
3231 msleep(1);
3232 else
3233 mdelay(1);
3234
3235 for (count = 0; count < 60; count ++) {
3236 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3237 doorbell &= MPI_IOC_STATE_MASK;
3238
3239 drsprintk((MYIOC_s_INFO_FMT
3240 "looking for READY STATE: doorbell=%x"
3241 " count=%d\n",
3242 ioc->name, doorbell, count));
3243 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003244 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003245 }
3246
3247 /* wait 1 sec */
3248 if (sleepFlag == CAN_SLEEP)
3249 msleep(1000);
3250 else
3251 mdelay(1000);
3252 }
3253 return -1;
3254 }
3255
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 /* Use "Diagnostic reset" method! (only thing available!) */
3257 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3258
3259#ifdef MPT_DEBUG
3260 if (ioc->alt_ioc)
3261 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3262 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3263 ioc->name, diag0val, diag1val));
3264#endif
3265
3266 /* Do the reset if we are told to ignore the reset history
3267 * or if the reset history is 0
3268 */
3269 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3270 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3271 /* Write magic sequence to WriteSequence register
3272 * Loop until in diagnostic mode
3273 */
3274 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3275 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3276 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3277 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3278 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3279 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3280
3281 /* wait 100 msec */
3282 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003283 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 } else {
3285 mdelay (100);
3286 }
3287
3288 count++;
3289 if (count > 20) {
3290 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3291 ioc->name, diag0val);
3292 return -2;
3293
3294 }
3295
3296 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3297
3298 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3299 ioc->name, diag0val));
3300 }
3301
3302#ifdef MPT_DEBUG
3303 if (ioc->alt_ioc)
3304 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3305 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3306 ioc->name, diag0val, diag1val));
3307#endif
3308 /*
3309 * Disable the ARM (Bug fix)
3310 *
3311 */
3312 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003313 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
3315 /*
3316 * Now hit the reset bit in the Diagnostic register
3317 * (THE BIG HAMMER!) (Clears DRWE bit).
3318 */
3319 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3320 hard_reset_done = 1;
3321 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3322 ioc->name));
3323
3324 /*
3325 * Call each currently registered protocol IOC reset handler
3326 * with pre-reset indication.
3327 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3328 * MptResetHandlers[] registered yet.
3329 */
3330 {
3331 int ii;
3332 int r = 0;
3333
3334 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3335 if (MptResetHandlers[ii]) {
3336 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3337 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003338 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 if (ioc->alt_ioc) {
3340 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3341 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003342 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 }
3344 }
3345 }
3346 /* FIXME? Examine results here? */
3347 }
3348
Eric Moore0ccdb002006-07-11 17:33:13 -06003349 if (ioc->cached_fw)
3350 iocp = ioc;
3351 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3352 iocp = ioc->alt_ioc;
3353 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 /* If the DownloadBoot operation fails, the
3355 * IOC will be left unusable. This is a fatal error
3356 * case. _diag_reset will return < 0
3357 */
3358 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003359 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3361 break;
3362 }
3363
Eric Moore0ccdb002006-07-11 17:33:13 -06003364 dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n",
3365 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 /* wait 1 sec */
3367 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003368 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 } else {
3370 mdelay (1000);
3371 }
3372 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003373 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003374 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 printk(KERN_WARNING MYNAM
3376 ": firmware downloadboot failure (%d)!\n", count);
3377 }
3378
3379 } else {
3380 /* Wait for FW to reload and for board
3381 * to go to the READY state.
3382 * Maximum wait is 60 seconds.
3383 * If fail, no error will check again
3384 * with calling program.
3385 */
3386 for (count = 0; count < 60; count ++) {
3387 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3388 doorbell &= MPI_IOC_STATE_MASK;
3389
3390 if (doorbell == MPI_IOC_STATE_READY) {
3391 break;
3392 }
3393
3394 /* wait 1 sec */
3395 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003396 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 } else {
3398 mdelay (1000);
3399 }
3400 }
3401 }
3402 }
3403
3404 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3405#ifdef MPT_DEBUG
3406 if (ioc->alt_ioc)
3407 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3408 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3409 ioc->name, diag0val, diag1val));
3410#endif
3411
3412 /* Clear RESET_HISTORY bit! Place board in the
3413 * diagnostic mode to update the diag register.
3414 */
3415 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3416 count = 0;
3417 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3418 /* Write magic sequence to WriteSequence register
3419 * Loop until in diagnostic mode
3420 */
3421 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3422 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3423 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3424 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3425 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3426 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3427
3428 /* wait 100 msec */
3429 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003430 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 } else {
3432 mdelay (100);
3433 }
3434
3435 count++;
3436 if (count > 20) {
3437 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3438 ioc->name, diag0val);
3439 break;
3440 }
3441 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3442 }
3443 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3444 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3445 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3446 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3447 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3448 ioc->name);
3449 }
3450
3451 /* Disable Diagnostic Mode
3452 */
3453 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3454
3455 /* Check FW reload status flags.
3456 */
3457 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3458 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3459 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3460 ioc->name, diag0val);
3461 return -3;
3462 }
3463
3464#ifdef MPT_DEBUG
3465 if (ioc->alt_ioc)
3466 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3467 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3468 ioc->name, diag0val, diag1val));
3469#endif
3470
3471 /*
3472 * Reset flag that says we've enabled event notification
3473 */
3474 ioc->facts.EventState = 0;
3475
3476 if (ioc->alt_ioc)
3477 ioc->alt_ioc->facts.EventState = 0;
3478
3479 return hard_reset_done;
3480}
3481
3482/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003483/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 * SendIocReset - Send IOCReset request to MPT adapter.
3485 * @ioc: Pointer to MPT_ADAPTER structure
3486 * @reset_type: reset type, expected values are
3487 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003488 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 *
3490 * Send IOCReset request to the MPT adapter.
3491 *
3492 * Returns 0 for success, non-zero for failure.
3493 */
3494static int
3495SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3496{
3497 int r;
3498 u32 state;
3499 int cntdn, count;
3500
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003501 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 ioc->name, reset_type));
3503 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3504 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3505 return r;
3506
3507 /* FW ACK'd request, wait for READY state
3508 */
3509 count = 0;
3510 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3511
3512 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3513 cntdn--;
3514 count++;
3515 if (!cntdn) {
3516 if (sleepFlag != CAN_SLEEP)
3517 count *= 10;
3518
3519 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3520 ioc->name, (int)((count+5)/HZ));
3521 return -ETIME;
3522 }
3523
3524 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003525 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 } else {
3527 mdelay (1); /* 1 msec delay */
3528 }
3529 }
3530
3531 /* TODO!
3532 * Cleanup all event stuff for this IOC; re-issue EventNotification
3533 * request if needed.
3534 */
3535 if (ioc->facts.Function)
3536 ioc->facts.EventState = 0;
3537
3538 return 0;
3539}
3540
3541/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003542/**
3543 * initChainBuffers - Allocate memory for and initialize chain buffers
3544 * @ioc: Pointer to MPT_ADAPTER structure
3545 *
3546 * Allocates memory for and initializes chain buffers,
3547 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548 */
3549static int
3550initChainBuffers(MPT_ADAPTER *ioc)
3551{
3552 u8 *mem;
3553 int sz, ii, num_chain;
3554 int scale, num_sge, numSGE;
3555
3556 /* ReqToChain size must equal the req_depth
3557 * index = req_idx
3558 */
3559 if (ioc->ReqToChain == NULL) {
3560 sz = ioc->req_depth * sizeof(int);
3561 mem = kmalloc(sz, GFP_ATOMIC);
3562 if (mem == NULL)
3563 return -1;
3564
3565 ioc->ReqToChain = (int *) mem;
3566 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3567 ioc->name, mem, sz));
3568 mem = kmalloc(sz, GFP_ATOMIC);
3569 if (mem == NULL)
3570 return -1;
3571
3572 ioc->RequestNB = (int *) mem;
3573 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3574 ioc->name, mem, sz));
3575 }
3576 for (ii = 0; ii < ioc->req_depth; ii++) {
3577 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3578 }
3579
3580 /* ChainToChain size must equal the total number
3581 * of chain buffers to be allocated.
3582 * index = chain_idx
3583 *
3584 * Calculate the number of chain buffers needed(plus 1) per I/O
3585 * then multiply the the maximum number of simultaneous cmds
3586 *
3587 * num_sge = num sge in request frame + last chain buffer
3588 * scale = num sge per chain buffer if no chain element
3589 */
3590 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3591 if (sizeof(dma_addr_t) == sizeof(u64))
3592 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3593 else
3594 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3595
3596 if (sizeof(dma_addr_t) == sizeof(u64)) {
3597 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3598 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3599 } else {
3600 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3601 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3602 }
3603 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3604 ioc->name, num_sge, numSGE));
3605
3606 if ( numSGE > MPT_SCSI_SG_DEPTH )
3607 numSGE = MPT_SCSI_SG_DEPTH;
3608
3609 num_chain = 1;
3610 while (numSGE - num_sge > 0) {
3611 num_chain++;
3612 num_sge += (scale - 1);
3613 }
3614 num_chain++;
3615
3616 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3617 ioc->name, numSGE, num_sge, num_chain));
3618
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003619 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 num_chain *= MPT_SCSI_CAN_QUEUE;
3621 else
3622 num_chain *= MPT_FC_CAN_QUEUE;
3623
3624 ioc->num_chain = num_chain;
3625
3626 sz = num_chain * sizeof(int);
3627 if (ioc->ChainToChain == NULL) {
3628 mem = kmalloc(sz, GFP_ATOMIC);
3629 if (mem == NULL)
3630 return -1;
3631
3632 ioc->ChainToChain = (int *) mem;
3633 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3634 ioc->name, mem, sz));
3635 } else {
3636 mem = (u8 *) ioc->ChainToChain;
3637 }
3638 memset(mem, 0xFF, sz);
3639 return num_chain;
3640}
3641
3642/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003643/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3645 * @ioc: Pointer to MPT_ADAPTER structure
3646 *
3647 * This routine allocates memory for the MPT reply and request frame
3648 * pools (if necessary), and primes the IOC reply FIFO with
3649 * reply frames.
3650 *
3651 * Returns 0 for success, non-zero for failure.
3652 */
3653static int
3654PrimeIocFifos(MPT_ADAPTER *ioc)
3655{
3656 MPT_FRAME_HDR *mf;
3657 unsigned long flags;
3658 dma_addr_t alloc_dma;
3659 u8 *mem;
3660 int i, reply_sz, sz, total_size, num_chain;
3661
3662 /* Prime reply FIFO... */
3663
3664 if (ioc->reply_frames == NULL) {
3665 if ( (num_chain = initChainBuffers(ioc)) < 0)
3666 return -1;
3667
3668 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3669 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3670 ioc->name, ioc->reply_sz, ioc->reply_depth));
3671 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3672 ioc->name, reply_sz, reply_sz));
3673
3674 sz = (ioc->req_sz * ioc->req_depth);
3675 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3676 ioc->name, ioc->req_sz, ioc->req_depth));
3677 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3678 ioc->name, sz, sz));
3679 total_size += sz;
3680
3681 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3682 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3683 ioc->name, ioc->req_sz, num_chain));
3684 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3685 ioc->name, sz, sz, num_chain));
3686
3687 total_size += sz;
3688 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3689 if (mem == NULL) {
3690 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3691 ioc->name);
3692 goto out_fail;
3693 }
3694
3695 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3696 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3697
3698 memset(mem, 0, total_size);
3699 ioc->alloc_total += total_size;
3700 ioc->alloc = mem;
3701 ioc->alloc_dma = alloc_dma;
3702 ioc->alloc_sz = total_size;
3703 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3704 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3705
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003706 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3707 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3708
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 alloc_dma += reply_sz;
3710 mem += reply_sz;
3711
3712 /* Request FIFO - WE manage this! */
3713
3714 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3715 ioc->req_frames_dma = alloc_dma;
3716
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003717 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 ioc->name, mem, (void *)(ulong)alloc_dma));
3719
3720 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3721
3722#if defined(CONFIG_MTRR) && 0
3723 /*
3724 * Enable Write Combining MTRR for IOC's memory region.
3725 * (at least as much as we can; "size and base must be
3726 * multiples of 4 kiB"
3727 */
3728 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3729 sz,
3730 MTRR_TYPE_WRCOMB, 1);
3731 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3732 ioc->name, ioc->req_frames_dma, sz));
3733#endif
3734
3735 for (i = 0; i < ioc->req_depth; i++) {
3736 alloc_dma += ioc->req_sz;
3737 mem += ioc->req_sz;
3738 }
3739
3740 ioc->ChainBuffer = mem;
3741 ioc->ChainBufferDMA = alloc_dma;
3742
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003743 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3745
3746 /* Initialize the free chain Q.
3747 */
3748
3749 INIT_LIST_HEAD(&ioc->FreeChainQ);
3750
3751 /* Post the chain buffers to the FreeChainQ.
3752 */
3753 mem = (u8 *)ioc->ChainBuffer;
3754 for (i=0; i < num_chain; i++) {
3755 mf = (MPT_FRAME_HDR *) mem;
3756 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3757 mem += ioc->req_sz;
3758 }
3759
3760 /* Initialize Request frames linked list
3761 */
3762 alloc_dma = ioc->req_frames_dma;
3763 mem = (u8 *) ioc->req_frames;
3764
3765 spin_lock_irqsave(&ioc->FreeQlock, flags);
3766 INIT_LIST_HEAD(&ioc->FreeQ);
3767 for (i = 0; i < ioc->req_depth; i++) {
3768 mf = (MPT_FRAME_HDR *) mem;
3769
3770 /* Queue REQUESTs *internally*! */
3771 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3772
3773 mem += ioc->req_sz;
3774 }
3775 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3776
3777 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3778 ioc->sense_buf_pool =
3779 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3780 if (ioc->sense_buf_pool == NULL) {
3781 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3782 ioc->name);
3783 goto out_fail;
3784 }
3785
3786 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3787 ioc->alloc_total += sz;
3788 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3789 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3790
3791 }
3792
3793 /* Post Reply frames to FIFO
3794 */
3795 alloc_dma = ioc->alloc_dma;
3796 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3797 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3798
3799 for (i = 0; i < ioc->reply_depth; i++) {
3800 /* Write each address to the IOC! */
3801 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3802 alloc_dma += ioc->reply_sz;
3803 }
3804
3805 return 0;
3806
3807out_fail:
3808 if (ioc->alloc != NULL) {
3809 sz = ioc->alloc_sz;
3810 pci_free_consistent(ioc->pcidev,
3811 sz,
3812 ioc->alloc, ioc->alloc_dma);
3813 ioc->reply_frames = NULL;
3814 ioc->req_frames = NULL;
3815 ioc->alloc_total -= sz;
3816 }
3817 if (ioc->sense_buf_pool != NULL) {
3818 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3819 pci_free_consistent(ioc->pcidev,
3820 sz,
3821 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3822 ioc->sense_buf_pool = NULL;
3823 }
3824 return -1;
3825}
3826
3827/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3828/**
3829 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3830 * from IOC via doorbell handshake method.
3831 * @ioc: Pointer to MPT_ADAPTER structure
3832 * @reqBytes: Size of the request in bytes
3833 * @req: Pointer to MPT request frame
3834 * @replyBytes: Expected size of the reply in bytes
3835 * @u16reply: Pointer to area where reply should be written
3836 * @maxwait: Max wait time for a reply (in seconds)
3837 * @sleepFlag: Specifies whether the process can sleep
3838 *
3839 * NOTES: It is the callers responsibility to byte-swap fields in the
3840 * request which are greater than 1 byte in size. It is also the
3841 * callers responsibility to byte-swap response fields which are
3842 * greater than 1 byte in size.
3843 *
3844 * Returns 0 for success, non-zero for failure.
3845 */
3846static int
3847mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003848 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849{
3850 MPIDefaultReply_t *mptReply;
3851 int failcnt = 0;
3852 int t;
3853
3854 /*
3855 * Get ready to cache a handshake reply
3856 */
3857 ioc->hs_reply_idx = 0;
3858 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3859 mptReply->MsgLength = 0;
3860
3861 /*
3862 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3863 * then tell IOC that we want to handshake a request of N words.
3864 * (WRITE u32val to Doorbell reg).
3865 */
3866 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3867 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3868 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3869 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3870
3871 /*
3872 * Wait for IOC's doorbell handshake int
3873 */
3874 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3875 failcnt++;
3876
3877 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3878 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3879
3880 /* Read doorbell and check for active bit */
3881 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3882 return -1;
3883
3884 /*
3885 * Clear doorbell int (WRITE 0 to IntStatus reg),
3886 * then wait for IOC to ACKnowledge that it's ready for
3887 * our handshake request.
3888 */
3889 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3890 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3891 failcnt++;
3892
3893 if (!failcnt) {
3894 int ii;
3895 u8 *req_as_bytes = (u8 *) req;
3896
3897 /*
3898 * Stuff request words via doorbell handshake,
3899 * with ACK from IOC for each.
3900 */
3901 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3902 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3903 (req_as_bytes[(ii*4) + 1] << 8) |
3904 (req_as_bytes[(ii*4) + 2] << 16) |
3905 (req_as_bytes[(ii*4) + 3] << 24));
3906
3907 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3908 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3909 failcnt++;
3910 }
3911
3912 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3913 DBG_DUMP_REQUEST_FRAME_HDR(req)
3914
3915 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3916 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3917
3918 /*
3919 * Wait for completion of doorbell handshake reply from the IOC
3920 */
3921 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3922 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003923
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3925 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3926
3927 /*
3928 * Copy out the cached reply...
3929 */
3930 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3931 u16reply[ii] = ioc->hs_reply[ii];
3932 } else {
3933 return -99;
3934 }
3935
3936 return -failcnt;
3937}
3938
3939/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003940/**
3941 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 * @ioc: Pointer to MPT_ADAPTER structure
3943 * @howlong: How long to wait (in seconds)
3944 * @sleepFlag: Specifies whether the process can sleep
3945 *
3946 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003947 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
3948 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 *
3950 * Returns a negative value on failure, else wait loop count.
3951 */
3952static int
3953WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3954{
3955 int cntdn;
3956 int count = 0;
3957 u32 intstat=0;
3958
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003959 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960
3961 if (sleepFlag == CAN_SLEEP) {
3962 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003963 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3965 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3966 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 count++;
3968 }
3969 } else {
3970 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003971 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3973 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3974 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 count++;
3976 }
3977 }
3978
3979 if (cntdn) {
3980 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3981 ioc->name, count));
3982 return count;
3983 }
3984
3985 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3986 ioc->name, count, intstat);
3987 return -1;
3988}
3989
3990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003991/**
3992 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 * @ioc: Pointer to MPT_ADAPTER structure
3994 * @howlong: How long to wait (in seconds)
3995 * @sleepFlag: Specifies whether the process can sleep
3996 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003997 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
3998 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 *
4000 * Returns a negative value on failure, else wait loop count.
4001 */
4002static int
4003WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4004{
4005 int cntdn;
4006 int count = 0;
4007 u32 intstat=0;
4008
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004009 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 if (sleepFlag == CAN_SLEEP) {
4011 while (--cntdn) {
4012 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4013 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4014 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004015 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 count++;
4017 }
4018 } else {
4019 while (--cntdn) {
4020 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4021 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4022 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004023 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 count++;
4025 }
4026 }
4027
4028 if (cntdn) {
4029 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
4030 ioc->name, count, howlong));
4031 return count;
4032 }
4033
4034 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4035 ioc->name, count, intstat);
4036 return -1;
4037}
4038
4039/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004040/**
4041 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 * @ioc: Pointer to MPT_ADAPTER structure
4043 * @howlong: How long to wait (in seconds)
4044 * @sleepFlag: Specifies whether the process can sleep
4045 *
4046 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4047 * Reply is cached to IOC private area large enough to hold a maximum
4048 * of 128 bytes of reply data.
4049 *
4050 * Returns a negative value on failure, else size of reply in WORDS.
4051 */
4052static int
4053WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4054{
4055 int u16cnt = 0;
4056 int failcnt = 0;
4057 int t;
4058 u16 *hs_reply = ioc->hs_reply;
4059 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4060 u16 hword;
4061
4062 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4063
4064 /*
4065 * Get first two u16's so we can look at IOC's intended reply MsgLength
4066 */
4067 u16cnt=0;
4068 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4069 failcnt++;
4070 } else {
4071 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4072 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4073 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4074 failcnt++;
4075 else {
4076 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4077 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4078 }
4079 }
4080
4081 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004082 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4084
4085 /*
4086 * If no error (and IOC said MsgLength is > 0), piece together
4087 * reply 16 bits at a time.
4088 */
4089 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4090 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4091 failcnt++;
4092 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4093 /* don't overflow our IOC hs_reply[] buffer! */
4094 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4095 hs_reply[u16cnt] = hword;
4096 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4097 }
4098
4099 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4100 failcnt++;
4101 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4102
4103 if (failcnt) {
4104 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4105 ioc->name);
4106 return -failcnt;
4107 }
4108#if 0
4109 else if (u16cnt != (2 * mptReply->MsgLength)) {
4110 return -101;
4111 }
4112 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4113 return -102;
4114 }
4115#endif
4116
4117 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4118 DBG_DUMP_REPLY_FRAME(mptReply)
4119
4120 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4121 ioc->name, t, u16cnt/2));
4122 return u16cnt/2;
4123}
4124
4125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004126/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 * GetLanConfigPages - Fetch LANConfig pages.
4128 * @ioc: Pointer to MPT_ADAPTER structure
4129 *
4130 * Return: 0 for success
4131 * -ENOMEM if no memory available
4132 * -EPERM if not allowed due to ISR context
4133 * -EAGAIN if no msg frames currently available
4134 * -EFAULT for non-successful reply or no reply (timeout)
4135 */
4136static int
4137GetLanConfigPages(MPT_ADAPTER *ioc)
4138{
4139 ConfigPageHeader_t hdr;
4140 CONFIGPARMS cfg;
4141 LANPage0_t *ppage0_alloc;
4142 dma_addr_t page0_dma;
4143 LANPage1_t *ppage1_alloc;
4144 dma_addr_t page1_dma;
4145 int rc = 0;
4146 int data_sz;
4147 int copy_sz;
4148
4149 /* Get LAN Page 0 header */
4150 hdr.PageVersion = 0;
4151 hdr.PageLength = 0;
4152 hdr.PageNumber = 0;
4153 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004154 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 cfg.physAddr = -1;
4156 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4157 cfg.dir = 0;
4158 cfg.pageAddr = 0;
4159 cfg.timeout = 0;
4160
4161 if ((rc = mpt_config(ioc, &cfg)) != 0)
4162 return rc;
4163
4164 if (hdr.PageLength > 0) {
4165 data_sz = hdr.PageLength * 4;
4166 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4167 rc = -ENOMEM;
4168 if (ppage0_alloc) {
4169 memset((u8 *)ppage0_alloc, 0, data_sz);
4170 cfg.physAddr = page0_dma;
4171 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4172
4173 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4174 /* save the data */
4175 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4176 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4177
4178 }
4179
4180 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4181
4182 /* FIXME!
4183 * Normalize endianness of structure data,
4184 * by byte-swapping all > 1 byte fields!
4185 */
4186
4187 }
4188
4189 if (rc)
4190 return rc;
4191 }
4192
4193 /* Get LAN Page 1 header */
4194 hdr.PageVersion = 0;
4195 hdr.PageLength = 0;
4196 hdr.PageNumber = 1;
4197 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004198 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 cfg.physAddr = -1;
4200 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4201 cfg.dir = 0;
4202 cfg.pageAddr = 0;
4203
4204 if ((rc = mpt_config(ioc, &cfg)) != 0)
4205 return rc;
4206
4207 if (hdr.PageLength == 0)
4208 return 0;
4209
4210 data_sz = hdr.PageLength * 4;
4211 rc = -ENOMEM;
4212 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4213 if (ppage1_alloc) {
4214 memset((u8 *)ppage1_alloc, 0, data_sz);
4215 cfg.physAddr = page1_dma;
4216 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4217
4218 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4219 /* save the data */
4220 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4221 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4222 }
4223
4224 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4225
4226 /* FIXME!
4227 * Normalize endianness of structure data,
4228 * by byte-swapping all > 1 byte fields!
4229 */
4230
4231 }
4232
4233 return rc;
4234}
4235
4236/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004237/**
4238 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004239 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004240 * @persist_opcode: see below
4241 *
4242 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4243 * devices not currently present.
4244 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4245 *
4246 * NOTE: Don't use not this function during interrupt time.
4247 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004248 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004249 */
4250
4251/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4252int
4253mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4254{
4255 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4256 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4257 MPT_FRAME_HDR *mf = NULL;
4258 MPIHeader_t *mpi_hdr;
4259
4260
4261 /* insure garbage is not sent to fw */
4262 switch(persist_opcode) {
4263
4264 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4265 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4266 break;
4267
4268 default:
4269 return -1;
4270 break;
4271 }
4272
4273 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4274
4275 /* Get a MF for this command.
4276 */
4277 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4278 printk("%s: no msg frames!\n",__FUNCTION__);
4279 return -1;
4280 }
4281
4282 mpi_hdr = (MPIHeader_t *) mf;
4283 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4284 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4285 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4286 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4287 sasIoUnitCntrReq->Operation = persist_opcode;
4288
4289 init_timer(&ioc->persist_timer);
4290 ioc->persist_timer.data = (unsigned long) ioc;
4291 ioc->persist_timer.function = mpt_timer_expired;
4292 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4293 ioc->persist_wait_done=0;
4294 add_timer(&ioc->persist_timer);
4295 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4296 wait_event(mpt_waitq, ioc->persist_wait_done);
4297
4298 sasIoUnitCntrReply =
4299 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4300 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4301 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4302 __FUNCTION__,
4303 sasIoUnitCntrReply->IOCStatus,
4304 sasIoUnitCntrReply->IOCLogInfo);
4305 return -1;
4306 }
4307
4308 printk("%s: success\n",__FUNCTION__);
4309 return 0;
4310}
4311
4312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004313
4314static void
4315mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4316 MpiEventDataRaid_t * pRaidEventData)
4317{
4318 int volume;
4319 int reason;
4320 int disk;
4321 int status;
4322 int flags;
4323 int state;
4324
4325 volume = pRaidEventData->VolumeID;
4326 reason = pRaidEventData->ReasonCode;
4327 disk = pRaidEventData->PhysDiskNum;
4328 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4329 flags = (status >> 0) & 0xff;
4330 state = (status >> 8) & 0xff;
4331
4332 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4333 return;
4334 }
4335
4336 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4337 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4338 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004339 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4340 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004341 } else {
4342 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4343 ioc->name, volume);
4344 }
4345
4346 switch(reason) {
4347 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4348 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4349 ioc->name);
4350 break;
4351
4352 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4353
4354 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4355 ioc->name);
4356 break;
4357
4358 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4359 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4360 ioc->name);
4361 break;
4362
4363 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4364 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4365 ioc->name,
4366 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4367 ? "optimal"
4368 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4369 ? "degraded"
4370 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4371 ? "failed"
4372 : "state unknown",
4373 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4374 ? ", enabled" : "",
4375 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4376 ? ", quiesced" : "",
4377 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4378 ? ", resync in progress" : "" );
4379 break;
4380
4381 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4382 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4383 ioc->name, disk);
4384 break;
4385
4386 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4387 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4388 ioc->name);
4389 break;
4390
4391 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4392 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4393 ioc->name);
4394 break;
4395
4396 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4397 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4398 ioc->name);
4399 break;
4400
4401 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4402 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4403 ioc->name,
4404 state == MPI_PHYSDISK0_STATUS_ONLINE
4405 ? "online"
4406 : state == MPI_PHYSDISK0_STATUS_MISSING
4407 ? "missing"
4408 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4409 ? "not compatible"
4410 : state == MPI_PHYSDISK0_STATUS_FAILED
4411 ? "failed"
4412 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4413 ? "initializing"
4414 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4415 ? "offline requested"
4416 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4417 ? "failed requested"
4418 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4419 ? "offline"
4420 : "state unknown",
4421 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4422 ? ", out of sync" : "",
4423 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4424 ? ", quiesced" : "" );
4425 break;
4426
4427 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4428 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4429 ioc->name, disk);
4430 break;
4431
4432 case MPI_EVENT_RAID_RC_SMART_DATA:
4433 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4434 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4435 break;
4436
4437 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4438 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4439 ioc->name, disk);
4440 break;
4441 }
4442}
4443
4444/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004445/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4447 * @ioc: Pointer to MPT_ADAPTER structure
4448 *
4449 * Returns: 0 for success
4450 * -ENOMEM if no memory available
4451 * -EPERM if not allowed due to ISR context
4452 * -EAGAIN if no msg frames currently available
4453 * -EFAULT for non-successful reply or no reply (timeout)
4454 */
4455static int
4456GetIoUnitPage2(MPT_ADAPTER *ioc)
4457{
4458 ConfigPageHeader_t hdr;
4459 CONFIGPARMS cfg;
4460 IOUnitPage2_t *ppage_alloc;
4461 dma_addr_t page_dma;
4462 int data_sz;
4463 int rc;
4464
4465 /* Get the page header */
4466 hdr.PageVersion = 0;
4467 hdr.PageLength = 0;
4468 hdr.PageNumber = 2;
4469 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004470 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 cfg.physAddr = -1;
4472 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4473 cfg.dir = 0;
4474 cfg.pageAddr = 0;
4475 cfg.timeout = 0;
4476
4477 if ((rc = mpt_config(ioc, &cfg)) != 0)
4478 return rc;
4479
4480 if (hdr.PageLength == 0)
4481 return 0;
4482
4483 /* Read the config page */
4484 data_sz = hdr.PageLength * 4;
4485 rc = -ENOMEM;
4486 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4487 if (ppage_alloc) {
4488 memset((u8 *)ppage_alloc, 0, data_sz);
4489 cfg.physAddr = page_dma;
4490 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4491
4492 /* If Good, save data */
4493 if ((rc = mpt_config(ioc, &cfg)) == 0)
4494 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4495
4496 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4497 }
4498
4499 return rc;
4500}
4501
4502/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004503/**
4504 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 * @ioc: Pointer to a Adapter Strucutre
4506 * @portnum: IOC port number
4507 *
4508 * Return: -EFAULT if read of config page header fails
4509 * or if no nvram
4510 * If read of SCSI Port Page 0 fails,
4511 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4512 * Adapter settings: async, narrow
4513 * Return 1
4514 * If read of SCSI Port Page 2 fails,
4515 * Adapter settings valid
4516 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4517 * Return 1
4518 * Else
4519 * Both valid
4520 * Return 0
4521 * CHECK - what type of locking mechanisms should be used????
4522 */
4523static int
4524mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4525{
4526 u8 *pbuf;
4527 dma_addr_t buf_dma;
4528 CONFIGPARMS cfg;
4529 ConfigPageHeader_t header;
4530 int ii;
4531 int data, rc = 0;
4532
4533 /* Allocate memory
4534 */
4535 if (!ioc->spi_data.nvram) {
4536 int sz;
4537 u8 *mem;
4538 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4539 mem = kmalloc(sz, GFP_ATOMIC);
4540 if (mem == NULL)
4541 return -EFAULT;
4542
4543 ioc->spi_data.nvram = (int *) mem;
4544
4545 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4546 ioc->name, ioc->spi_data.nvram, sz));
4547 }
4548
4549 /* Invalidate NVRAM information
4550 */
4551 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4552 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4553 }
4554
4555 /* Read SPP0 header, allocate memory, then read page.
4556 */
4557 header.PageVersion = 0;
4558 header.PageLength = 0;
4559 header.PageNumber = 0;
4560 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004561 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 cfg.physAddr = -1;
4563 cfg.pageAddr = portnum;
4564 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4565 cfg.dir = 0;
4566 cfg.timeout = 0; /* use default */
4567 if (mpt_config(ioc, &cfg) != 0)
4568 return -EFAULT;
4569
4570 if (header.PageLength > 0) {
4571 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4572 if (pbuf) {
4573 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4574 cfg.physAddr = buf_dma;
4575 if (mpt_config(ioc, &cfg) != 0) {
4576 ioc->spi_data.maxBusWidth = MPT_NARROW;
4577 ioc->spi_data.maxSyncOffset = 0;
4578 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4579 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4580 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004581 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4582 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 } else {
4584 /* Save the Port Page 0 data
4585 */
4586 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4587 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4588 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4589
4590 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4591 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004592 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 ioc->name, pPP0->Capabilities));
4594 }
4595 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4596 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4597 if (data) {
4598 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4599 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4600 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004601 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4602 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 } else {
4604 ioc->spi_data.maxSyncOffset = 0;
4605 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4606 }
4607
4608 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4609
4610 /* Update the minSyncFactor based on bus type.
4611 */
4612 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4613 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4614
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004615 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004617 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4618 ioc->name, ioc->spi_data.minSyncFactor));
4619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 }
4621 }
4622 if (pbuf) {
4623 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4624 }
4625 }
4626 }
4627
4628 /* SCSI Port Page 2 - Read the header then the page.
4629 */
4630 header.PageVersion = 0;
4631 header.PageLength = 0;
4632 header.PageNumber = 2;
4633 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004634 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 cfg.physAddr = -1;
4636 cfg.pageAddr = portnum;
4637 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4638 cfg.dir = 0;
4639 if (mpt_config(ioc, &cfg) != 0)
4640 return -EFAULT;
4641
4642 if (header.PageLength > 0) {
4643 /* Allocate memory and read SCSI Port Page 2
4644 */
4645 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4646 if (pbuf) {
4647 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4648 cfg.physAddr = buf_dma;
4649 if (mpt_config(ioc, &cfg) != 0) {
4650 /* Nvram data is left with INVALID mark
4651 */
4652 rc = 1;
4653 } else {
4654 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4655 MpiDeviceInfo_t *pdevice = NULL;
4656
Moore, Ericd8e925d2006-01-16 18:53:06 -07004657 /*
4658 * Save "Set to Avoid SCSI Bus Resets" flag
4659 */
4660 ioc->spi_data.bus_reset =
4661 (le32_to_cpu(pPP2->PortFlags) &
4662 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4663 0 : 1 ;
4664
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 /* Save the Port Page 2 data
4666 * (reformat into a 32bit quantity)
4667 */
4668 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4669 ioc->spi_data.PortFlags = data;
4670 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4671 pdevice = &pPP2->DeviceSettings[ii];
4672 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4673 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4674 ioc->spi_data.nvram[ii] = data;
4675 }
4676 }
4677
4678 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4679 }
4680 }
4681
4682 /* Update Adapter limits with those from NVRAM
4683 * Comment: Don't need to do this. Target performance
4684 * parameters will never exceed the adapters limits.
4685 */
4686
4687 return rc;
4688}
4689
4690/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004691/**
4692 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 * @ioc: Pointer to a Adapter Strucutre
4694 * @portnum: IOC port number
4695 *
4696 * Return: -EFAULT if read of config page header fails
4697 * or 0 if success.
4698 */
4699static int
4700mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4701{
4702 CONFIGPARMS cfg;
4703 ConfigPageHeader_t header;
4704
4705 /* Read the SCSI Device Page 1 header
4706 */
4707 header.PageVersion = 0;
4708 header.PageLength = 0;
4709 header.PageNumber = 1;
4710 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004711 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 cfg.physAddr = -1;
4713 cfg.pageAddr = portnum;
4714 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4715 cfg.dir = 0;
4716 cfg.timeout = 0;
4717 if (mpt_config(ioc, &cfg) != 0)
4718 return -EFAULT;
4719
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004720 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4721 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722
4723 header.PageVersion = 0;
4724 header.PageLength = 0;
4725 header.PageNumber = 0;
4726 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4727 if (mpt_config(ioc, &cfg) != 0)
4728 return -EFAULT;
4729
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004730 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4731 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732
4733 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4734 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4735
4736 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4737 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4738 return 0;
4739}
4740
Eric Mooreb506ade2007-01-29 09:45:37 -07004741/**
4742 * mpt_inactive_raid_list_free
4743 *
4744 * This clears this link list.
4745 *
4746 * @ioc - pointer to per adapter structure
4747 *
4748 **/
4749static void
4750mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
4751{
4752 struct inactive_raid_component_info *component_info, *pNext;
4753
4754 if (list_empty(&ioc->raid_data.inactive_list))
4755 return;
4756
4757 down(&ioc->raid_data.inactive_list_mutex);
4758 list_for_each_entry_safe(component_info, pNext,
4759 &ioc->raid_data.inactive_list, list) {
4760 list_del(&component_info->list);
4761 kfree(component_info);
4762 }
4763 up(&ioc->raid_data.inactive_list_mutex);
4764}
4765
4766/**
4767 * mpt_inactive_raid_volumes
4768 *
4769 * This sets up link list of phy_disk_nums for devices belonging in an inactive volume
4770 *
4771 * @ioc - pointer to per adapter structure
4772 * @channel - volume channel
4773 * @id - volume target id
4774 *
4775 *
4776 **/
4777static void
4778mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
4779{
4780 CONFIGPARMS cfg;
4781 ConfigPageHeader_t hdr;
4782 dma_addr_t dma_handle;
4783 pRaidVolumePage0_t buffer = NULL;
4784 int i;
4785 RaidPhysDiskPage0_t phys_disk;
4786 struct inactive_raid_component_info *component_info;
4787 int handle_inactive_volumes;
4788
4789 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4790 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4791 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4792 cfg.pageAddr = (channel << 8) + id;
4793 cfg.cfghdr.hdr = &hdr;
4794 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4795
4796 if (mpt_config(ioc, &cfg) != 0)
4797 goto out;
4798
4799 if (!hdr.PageLength)
4800 goto out;
4801
4802 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4803 &dma_handle);
4804
4805 if (!buffer)
4806 goto out;
4807
4808 cfg.physAddr = dma_handle;
4809 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4810
4811 if (mpt_config(ioc, &cfg) != 0)
4812 goto out;
4813
4814 if (!buffer->NumPhysDisks)
4815 goto out;
4816
4817 handle_inactive_volumes =
4818 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
4819 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
4820 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
4821 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
4822
4823 if (!handle_inactive_volumes)
4824 goto out;
4825
4826 down(&ioc->raid_data.inactive_list_mutex);
4827 for (i = 0; i < buffer->NumPhysDisks; i++) {
4828 if(mpt_raid_phys_disk_pg0(ioc,
4829 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4830 continue;
4831
4832 if ((component_info = kmalloc(sizeof (*component_info),
4833 GFP_KERNEL)) == NULL)
4834 continue;
4835
4836 component_info->volumeID = id;
4837 component_info->volumeBus = channel;
4838 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
4839 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
4840 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
4841 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
4842
4843 list_add_tail(&component_info->list,
4844 &ioc->raid_data.inactive_list);
4845 }
4846 up(&ioc->raid_data.inactive_list_mutex);
4847
4848 out:
4849 if (buffer)
4850 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4851 dma_handle);
4852}
4853
4854/**
4855 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
4856 * @ioc: Pointer to a Adapter Structure
4857 * @phys_disk_num: io unit unique phys disk num generated by the ioc
4858 * @phys_disk: requested payload data returned
4859 *
4860 * Return:
4861 * 0 on success
4862 * -EFAULT if read of config page header fails or data pointer not NULL
4863 * -ENOMEM if pci_alloc failed
4864 **/
4865int
4866mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
4867{
4868 CONFIGPARMS cfg;
4869 ConfigPageHeader_t hdr;
4870 dma_addr_t dma_handle;
4871 pRaidPhysDiskPage0_t buffer = NULL;
4872 int rc;
4873
4874 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4875 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4876
4877 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
4878 cfg.cfghdr.hdr = &hdr;
4879 cfg.physAddr = -1;
4880 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4881
4882 if (mpt_config(ioc, &cfg) != 0) {
4883 rc = -EFAULT;
4884 goto out;
4885 }
4886
4887 if (!hdr.PageLength) {
4888 rc = -EFAULT;
4889 goto out;
4890 }
4891
4892 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4893 &dma_handle);
4894
4895 if (!buffer) {
4896 rc = -ENOMEM;
4897 goto out;
4898 }
4899
4900 cfg.physAddr = dma_handle;
4901 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4902 cfg.pageAddr = phys_disk_num;
4903
4904 if (mpt_config(ioc, &cfg) != 0) {
4905 rc = -EFAULT;
4906 goto out;
4907 }
4908
4909 rc = 0;
4910 memcpy(phys_disk, buffer, sizeof(*buffer));
4911 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
4912
4913 out:
4914
4915 if (buffer)
4916 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4917 dma_handle);
4918
4919 return rc;
4920}
4921
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922/**
4923 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4924 * @ioc: Pointer to a Adapter Strucutre
4925 * @portnum: IOC port number
4926 *
4927 * Return:
4928 * 0 on success
4929 * -EFAULT if read of config page header fails or data pointer not NULL
4930 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07004931 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932int
4933mpt_findImVolumes(MPT_ADAPTER *ioc)
4934{
4935 IOCPage2_t *pIoc2;
4936 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 dma_addr_t ioc2_dma;
4938 CONFIGPARMS cfg;
4939 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 int rc = 0;
4941 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07004942 int i;
4943
4944 if (!ioc->ir_firmware)
4945 return 0;
4946
4947 /* Free the old page
4948 */
4949 kfree(ioc->raid_data.pIocPg2);
4950 ioc->raid_data.pIocPg2 = NULL;
4951 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952
4953 /* Read IOCP2 header then the page.
4954 */
4955 header.PageVersion = 0;
4956 header.PageLength = 0;
4957 header.PageNumber = 2;
4958 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004959 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960 cfg.physAddr = -1;
4961 cfg.pageAddr = 0;
4962 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4963 cfg.dir = 0;
4964 cfg.timeout = 0;
4965 if (mpt_config(ioc, &cfg) != 0)
4966 return -EFAULT;
4967
4968 if (header.PageLength == 0)
4969 return -EFAULT;
4970
4971 iocpage2sz = header.PageLength * 4;
4972 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4973 if (!pIoc2)
4974 return -ENOMEM;
4975
4976 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4977 cfg.physAddr = ioc2_dma;
4978 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07004979 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980
Eric Mooreb506ade2007-01-29 09:45:37 -07004981 mem = kmalloc(iocpage2sz, GFP_KERNEL);
4982 if (!mem)
4983 goto out;
4984
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07004986 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987
Eric Mooreb506ade2007-01-29 09:45:37 -07004988 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989
Eric Mooreb506ade2007-01-29 09:45:37 -07004990 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
4991 mpt_inactive_raid_volumes(ioc,
4992 pIoc2->RaidVolume[i].VolumeBus,
4993 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994
Eric Mooreb506ade2007-01-29 09:45:37 -07004995 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4997
4998 return rc;
4999}
5000
Moore, Ericc972c702006-03-14 09:14:06 -07005001static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5003{
5004 IOCPage3_t *pIoc3;
5005 u8 *mem;
5006 CONFIGPARMS cfg;
5007 ConfigPageHeader_t header;
5008 dma_addr_t ioc3_dma;
5009 int iocpage3sz = 0;
5010
5011 /* Free the old page
5012 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005013 kfree(ioc->raid_data.pIocPg3);
5014 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015
5016 /* There is at least one physical disk.
5017 * Read and save IOC Page 3
5018 */
5019 header.PageVersion = 0;
5020 header.PageLength = 0;
5021 header.PageNumber = 3;
5022 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005023 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 cfg.physAddr = -1;
5025 cfg.pageAddr = 0;
5026 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5027 cfg.dir = 0;
5028 cfg.timeout = 0;
5029 if (mpt_config(ioc, &cfg) != 0)
5030 return 0;
5031
5032 if (header.PageLength == 0)
5033 return 0;
5034
5035 /* Read Header good, alloc memory
5036 */
5037 iocpage3sz = header.PageLength * 4;
5038 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5039 if (!pIoc3)
5040 return 0;
5041
5042 /* Read the Page and save the data
5043 * into malloc'd memory.
5044 */
5045 cfg.physAddr = ioc3_dma;
5046 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5047 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005048 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 if (mem) {
5050 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005051 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 }
5053 }
5054
5055 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5056
5057 return 0;
5058}
5059
5060static void
5061mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5062{
5063 IOCPage4_t *pIoc4;
5064 CONFIGPARMS cfg;
5065 ConfigPageHeader_t header;
5066 dma_addr_t ioc4_dma;
5067 int iocpage4sz;
5068
5069 /* Read and save IOC Page 4
5070 */
5071 header.PageVersion = 0;
5072 header.PageLength = 0;
5073 header.PageNumber = 4;
5074 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005075 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 cfg.physAddr = -1;
5077 cfg.pageAddr = 0;
5078 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5079 cfg.dir = 0;
5080 cfg.timeout = 0;
5081 if (mpt_config(ioc, &cfg) != 0)
5082 return;
5083
5084 if (header.PageLength == 0)
5085 return;
5086
5087 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5088 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5089 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5090 if (!pIoc4)
5091 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005092 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 } else {
5094 ioc4_dma = ioc->spi_data.IocPg4_dma;
5095 iocpage4sz = ioc->spi_data.IocPg4Sz;
5096 }
5097
5098 /* Read the Page into dma memory.
5099 */
5100 cfg.physAddr = ioc4_dma;
5101 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5102 if (mpt_config(ioc, &cfg) == 0) {
5103 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5104 ioc->spi_data.IocPg4_dma = ioc4_dma;
5105 ioc->spi_data.IocPg4Sz = iocpage4sz;
5106 } else {
5107 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5108 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005109 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 }
5111}
5112
5113static void
5114mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5115{
5116 IOCPage1_t *pIoc1;
5117 CONFIGPARMS cfg;
5118 ConfigPageHeader_t header;
5119 dma_addr_t ioc1_dma;
5120 int iocpage1sz = 0;
5121 u32 tmp;
5122
5123 /* Check the Coalescing Timeout in IOC Page 1
5124 */
5125 header.PageVersion = 0;
5126 header.PageLength = 0;
5127 header.PageNumber = 1;
5128 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005129 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 cfg.physAddr = -1;
5131 cfg.pageAddr = 0;
5132 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5133 cfg.dir = 0;
5134 cfg.timeout = 0;
5135 if (mpt_config(ioc, &cfg) != 0)
5136 return;
5137
5138 if (header.PageLength == 0)
5139 return;
5140
5141 /* Read Header good, alloc memory
5142 */
5143 iocpage1sz = header.PageLength * 4;
5144 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5145 if (!pIoc1)
5146 return;
5147
5148 /* Read the Page and check coalescing timeout
5149 */
5150 cfg.physAddr = ioc1_dma;
5151 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5152 if (mpt_config(ioc, &cfg) == 0) {
5153
5154 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5155 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5156 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5157
5158 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5159 ioc->name, tmp));
5160
5161 if (tmp > MPT_COALESCING_TIMEOUT) {
5162 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5163
5164 /* Write NVRAM and current
5165 */
5166 cfg.dir = 1;
5167 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5168 if (mpt_config(ioc, &cfg) == 0) {
5169 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5170 ioc->name, MPT_COALESCING_TIMEOUT));
5171
5172 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5173 if (mpt_config(ioc, &cfg) == 0) {
5174 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5175 ioc->name, MPT_COALESCING_TIMEOUT));
5176 } else {
5177 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5178 ioc->name));
5179 }
5180
5181 } else {
5182 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5183 ioc->name));
5184 }
5185 }
5186
5187 } else {
5188 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5189 }
5190 }
5191
5192 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5193
5194 return;
5195}
5196
5197/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005198/**
5199 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 * @ioc: Pointer to MPT_ADAPTER structure
5201 * @EvSwitch: Event switch flags
5202 */
5203static int
5204SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5205{
5206 EventNotification_t *evnp;
5207
5208 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5209 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005210 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 ioc->name));
5212 return 0;
5213 }
5214 memset(evnp, 0, sizeof(*evnp));
5215
Moore, Eric3a892be2006-03-14 09:14:03 -07005216 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217
5218 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5219 evnp->ChainOffset = 0;
5220 evnp->MsgFlags = 0;
5221 evnp->Switch = EvSwitch;
5222
5223 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5224
5225 return 0;
5226}
5227
5228/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5229/**
5230 * SendEventAck - Send EventAck request to MPT adapter.
5231 * @ioc: Pointer to MPT_ADAPTER structure
5232 * @evnp: Pointer to original EventNotification request
5233 */
5234static int
5235SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5236{
5237 EventAck_t *pAck;
5238
5239 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Eric Moore4f766dc2006-07-11 17:24:07 -06005240 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
5241 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 return -1;
5243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244
Eric Moore4f766dc2006-07-11 17:24:07 -06005245 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246
5247 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5248 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005249 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005251 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 pAck->Event = evnp->Event;
5253 pAck->EventContext = evnp->EventContext;
5254
5255 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5256
5257 return 0;
5258}
5259
5260/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5261/**
5262 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005263 * @ioc: Pointer to an adapter structure
5264 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 * action, page address, direction, physical address
5266 * and pointer to a configuration page header
5267 * Page header is updated.
5268 *
5269 * Returns 0 for success
5270 * -EPERM if not allowed due to ISR context
5271 * -EAGAIN if no msg frames currently available
5272 * -EFAULT for non-successful reply or no reply (timeout)
5273 */
5274int
5275mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5276{
5277 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005278 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 MPT_FRAME_HDR *mf;
5280 unsigned long flags;
5281 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005282 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 int in_isr;
5284
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005285 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 * to be in ISR context, because that is fatal!
5287 */
5288 in_isr = in_interrupt();
5289 if (in_isr) {
5290 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5291 ioc->name));
5292 return -EPERM;
5293 }
5294
5295 /* Get and Populate a free Frame
5296 */
5297 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5298 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5299 ioc->name));
5300 return -EAGAIN;
5301 }
5302 pReq = (Config_t *)mf;
5303 pReq->Action = pCfg->action;
5304 pReq->Reserved = 0;
5305 pReq->ChainOffset = 0;
5306 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005307
5308 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 pReq->ExtPageLength = 0;
5310 pReq->ExtPageType = 0;
5311 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005312
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 for (ii=0; ii < 8; ii++)
5314 pReq->Reserved2[ii] = 0;
5315
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005316 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5317 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5318 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5319 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5320
5321 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5322 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5323 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5324 pReq->ExtPageType = pExtHdr->ExtPageType;
5325 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5326
5327 /* Page Length must be treated as a reserved field for the extended header. */
5328 pReq->Header.PageLength = 0;
5329 }
5330
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5332
5333 /* Add a SGE to the config request.
5334 */
5335 if (pCfg->dir)
5336 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5337 else
5338 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5339
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005340 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5341 flagsLength |= pExtHdr->ExtPageLength * 4;
5342
5343 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5344 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5345 }
5346 else {
5347 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5348
5349 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5350 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352
5353 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5354
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 /* Append pCfg pointer to end of mf
5356 */
5357 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5358
5359 /* Initalize the timer
5360 */
5361 init_timer(&pCfg->timer);
5362 pCfg->timer.data = (unsigned long) ioc;
5363 pCfg->timer.function = mpt_timer_expired;
5364 pCfg->wait_done = 0;
5365
5366 /* Set the timer; ensure 10 second minimum */
5367 if (pCfg->timeout < 10)
5368 pCfg->timer.expires = jiffies + HZ*10;
5369 else
5370 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5371
5372 /* Add to end of Q, set timer and then issue this command */
5373 spin_lock_irqsave(&ioc->FreeQlock, flags);
5374 list_add_tail(&pCfg->linkage, &ioc->configQ);
5375 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5376
5377 add_timer(&pCfg->timer);
5378 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5379 wait_event(mpt_waitq, pCfg->wait_done);
5380
5381 /* mf has been freed - do not access */
5382
5383 rc = pCfg->status;
5384
5385 return rc;
5386}
5387
5388/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005389/**
5390 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 * Used only internal config functionality.
5392 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5393 */
5394static void
5395mpt_timer_expired(unsigned long data)
5396{
5397 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5398
5399 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5400
5401 /* Perform a FW reload */
5402 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5403 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5404
5405 /* No more processing.
5406 * Hard reset clean-up will wake up
5407 * process and free all resources.
5408 */
5409 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5410
5411 return;
5412}
5413
5414/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005415/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 * mpt_ioc_reset - Base cleanup for hard reset
5417 * @ioc: Pointer to the adapter structure
5418 * @reset_phase: Indicates pre- or post-reset functionality
5419 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005420 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 */
5422static int
5423mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5424{
5425 CONFIGPARMS *pCfg;
5426 unsigned long flags;
5427
5428 dprintk((KERN_WARNING MYNAM
5429 ": IOC %s_reset routed to MPT base driver!\n",
5430 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5431 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5432
5433 if (reset_phase == MPT_IOC_SETUP_RESET) {
5434 ;
5435 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5436 /* If the internal config Q is not empty -
5437 * delete timer. MF resources will be freed when
5438 * the FIFO's are primed.
5439 */
5440 spin_lock_irqsave(&ioc->FreeQlock, flags);
5441 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5442 del_timer(&pCfg->timer);
5443 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5444
5445 } else {
5446 CONFIGPARMS *pNext;
5447
5448 /* Search the configQ for internal commands.
5449 * Flush the Q, and wake up all suspended threads.
5450 */
5451 spin_lock_irqsave(&ioc->FreeQlock, flags);
5452 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5453 list_del(&pCfg->linkage);
5454
5455 pCfg->status = MPT_CONFIG_ERROR;
5456 pCfg->wait_done = 1;
5457 wake_up(&mpt_waitq);
5458 }
5459 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5460 }
5461
5462 return 1; /* currently means nothing really */
5463}
5464
5465
5466#ifdef CONFIG_PROC_FS /* { */
5467/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5468/*
5469 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5470 */
5471/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005472/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5474 *
5475 * Returns 0 for success, non-zero for failure.
5476 */
5477static int
5478procmpt_create(void)
5479{
5480 struct proc_dir_entry *ent;
5481
5482 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5483 if (mpt_proc_root_dir == NULL)
5484 return -ENOTDIR;
5485
5486 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5487 if (ent)
5488 ent->read_proc = procmpt_summary_read;
5489
5490 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5491 if (ent)
5492 ent->read_proc = procmpt_version_read;
5493
5494 return 0;
5495}
5496
5497/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005498/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5500 *
5501 * Returns 0 for success, non-zero for failure.
5502 */
5503static void
5504procmpt_destroy(void)
5505{
5506 remove_proc_entry("version", mpt_proc_root_dir);
5507 remove_proc_entry("summary", mpt_proc_root_dir);
5508 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5509}
5510
5511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005512/**
5513 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 * @buf: Pointer to area to write information
5515 * @start: Pointer to start pointer
5516 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005517 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 * @eof: Pointer to EOF integer
5519 * @data: Pointer
5520 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005521 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 * Returns number of characters written to process performing the read.
5523 */
5524static int
5525procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5526{
5527 MPT_ADAPTER *ioc;
5528 char *out = buf;
5529 int len;
5530
5531 if (data) {
5532 int more = 0;
5533
5534 ioc = data;
5535 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5536
5537 out += more;
5538 } else {
5539 list_for_each_entry(ioc, &ioc_list, list) {
5540 int more = 0;
5541
5542 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5543
5544 out += more;
5545 if ((out-buf) >= request)
5546 break;
5547 }
5548 }
5549
5550 len = out - buf;
5551
5552 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5553}
5554
5555/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005556/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 * procmpt_version_read - Handle read request from /proc/mpt/version.
5558 * @buf: Pointer to area to write information
5559 * @start: Pointer to start pointer
5560 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005561 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 * @eof: Pointer to EOF integer
5563 * @data: Pointer
5564 *
5565 * Returns number of characters written to process performing the read.
5566 */
5567static int
5568procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5569{
5570 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005571 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 char *drvname;
5573 int len;
5574
5575 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5576 len += sprintf(buf+len, " Fusion MPT base driver\n");
5577
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005578 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5580 drvname = NULL;
5581 if (MptCallbacks[ii]) {
5582 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005583 case MPTSPI_DRIVER:
5584 if (!scsi++) drvname = "SPI host";
5585 break;
5586 case MPTFC_DRIVER:
5587 if (!fc++) drvname = "FC host";
5588 break;
5589 case MPTSAS_DRIVER:
5590 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 break;
5592 case MPTLAN_DRIVER:
5593 if (!lan++) drvname = "LAN";
5594 break;
5595 case MPTSTM_DRIVER:
5596 if (!targ++) drvname = "SCSI target";
5597 break;
5598 case MPTCTL_DRIVER:
5599 if (!ctl++) drvname = "ioctl";
5600 break;
5601 }
5602
5603 if (drvname)
5604 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5605 }
5606 }
5607
5608 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5609}
5610
5611/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005612/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5614 * @buf: Pointer to area to write information
5615 * @start: Pointer to start pointer
5616 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005617 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 * @eof: Pointer to EOF integer
5619 * @data: Pointer
5620 *
5621 * Returns number of characters written to process performing the read.
5622 */
5623static int
5624procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5625{
5626 MPT_ADAPTER *ioc = data;
5627 int len;
5628 char expVer[32];
5629 int sz;
5630 int p;
5631
5632 mpt_get_fw_exp_ver(expVer, ioc);
5633
5634 len = sprintf(buf, "%s:", ioc->name);
5635 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5636 len += sprintf(buf+len, " (f/w download boot flag set)");
5637// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5638// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5639
5640 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5641 ioc->facts.ProductID,
5642 ioc->prod_name);
5643 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5644 if (ioc->facts.FWImageSize)
5645 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5646 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5647 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5648 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5649
5650 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5651 ioc->facts.CurrentHostMfaHighAddr);
5652 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5653 ioc->facts.CurrentSenseBufferHighAddr);
5654
5655 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5656 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5657
5658 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5659 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5660 /*
5661 * Rounding UP to nearest 4-kB boundary here...
5662 */
5663 sz = (ioc->req_sz * ioc->req_depth) + 128;
5664 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5665 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5666 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5667 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5668 4*ioc->facts.RequestFrameSize,
5669 ioc->facts.GlobalCredits);
5670
5671 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5672 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5673 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5674 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5675 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5676 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5677 ioc->facts.CurReplyFrameSize,
5678 ioc->facts.ReplyQueueDepth);
5679
5680 len += sprintf(buf+len, " MaxDevices = %d\n",
5681 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5682 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5683
5684 /* per-port info */
5685 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5686 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5687 p+1,
5688 ioc->facts.NumberOfPorts);
5689 if (ioc->bus_type == FC) {
5690 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5691 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5692 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5693 a[5], a[4], a[3], a[2], a[1], a[0]);
5694 }
5695 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5696 ioc->fc_port_page0[p].WWNN.High,
5697 ioc->fc_port_page0[p].WWNN.Low,
5698 ioc->fc_port_page0[p].WWPN.High,
5699 ioc->fc_port_page0[p].WWPN.Low);
5700 }
5701 }
5702
5703 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5704}
5705
5706#endif /* CONFIG_PROC_FS } */
5707
5708/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5709static void
5710mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5711{
5712 buf[0] ='\0';
5713 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5714 sprintf(buf, " (Exp %02d%02d)",
5715 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5716 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5717
5718 /* insider hack! */
5719 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5720 strcat(buf, " [MDBG]");
5721 }
5722}
5723
5724/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5725/**
5726 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5727 * @ioc: Pointer to MPT_ADAPTER structure
5728 * @buffer: Pointer to buffer where IOC summary info should be written
5729 * @size: Pointer to number of bytes we wrote (set by this routine)
5730 * @len: Offset at which to start writing in buffer
5731 * @showlan: Display LAN stuff?
5732 *
5733 * This routine writes (english readable) ASCII text, which represents
5734 * a summary of IOC information, to a buffer.
5735 */
5736void
5737mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5738{
5739 char expVer[32];
5740 int y;
5741
5742 mpt_get_fw_exp_ver(expVer, ioc);
5743
5744 /*
5745 * Shorter summary of attached ioc's...
5746 */
5747 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5748 ioc->name,
5749 ioc->prod_name,
5750 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5751 ioc->facts.FWVersion.Word,
5752 expVer,
5753 ioc->facts.NumberOfPorts,
5754 ioc->req_depth);
5755
5756 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5757 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5758 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5759 a[5], a[4], a[3], a[2], a[1], a[0]);
5760 }
5761
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763
5764 if (!ioc->active)
5765 y += sprintf(buffer+len+y, " (disabled)");
5766
5767 y += sprintf(buffer+len+y, "\n");
5768
5769 *size = y;
5770}
5771
5772/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5773/*
5774 * Reset Handling
5775 */
5776/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5777/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005778 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779 * @ioc: Pointer to MPT_ADAPTER structure
5780 * @sleepFlag: Indicates if sleep or schedule must be called.
5781 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005782 * Issues SCSI Task Management call based on input arg values.
5783 * If TaskMgmt fails, returns associated SCSI request.
5784 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5786 * or a non-interrupt thread. In the former, must not call schedule().
5787 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005788 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 * FW reload/initialization failed.
5790 *
5791 * Returns 0 for SUCCESS or -1 if FAILED.
5792 */
5793int
5794mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5795{
5796 int rc;
5797 unsigned long flags;
5798
5799 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5800#ifdef MFCNT
5801 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5802 printk("MF count 0x%x !\n", ioc->mfcnt);
5803#endif
5804
5805 /* Reset the adapter. Prevent more than 1 call to
5806 * mpt_do_ioc_recovery at any instant in time.
5807 */
5808 spin_lock_irqsave(&ioc->diagLock, flags);
5809 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5810 spin_unlock_irqrestore(&ioc->diagLock, flags);
5811 return 0;
5812 } else {
5813 ioc->diagPending = 1;
5814 }
5815 spin_unlock_irqrestore(&ioc->diagLock, flags);
5816
5817 /* FIXME: If do_ioc_recovery fails, repeat....
5818 */
5819
5820 /* The SCSI driver needs to adjust timeouts on all current
5821 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02005822 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823 * For all other protocol drivers, this is a no-op.
5824 */
5825 {
5826 int ii;
5827 int r = 0;
5828
5829 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5830 if (MptResetHandlers[ii]) {
5831 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5832 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005833 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834 if (ioc->alt_ioc) {
5835 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5836 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005837 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 }
5839 }
5840 }
5841 }
5842
5843 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5844 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5845 rc, ioc->name);
5846 }
5847 ioc->reload_fw = 0;
5848 if (ioc->alt_ioc)
5849 ioc->alt_ioc->reload_fw = 0;
5850
5851 spin_lock_irqsave(&ioc->diagLock, flags);
5852 ioc->diagPending = 0;
5853 if (ioc->alt_ioc)
5854 ioc->alt_ioc->diagPending = 0;
5855 spin_unlock_irqrestore(&ioc->diagLock, flags);
5856
5857 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5858
5859 return rc;
5860}
5861
5862/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005863static void
5864EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865{
Eric Moore509e5e52006-04-26 13:22:37 -06005866 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867
5868 switch(event) {
5869 case MPI_EVENT_NONE:
5870 ds = "None";
5871 break;
5872 case MPI_EVENT_LOG_DATA:
5873 ds = "Log Data";
5874 break;
5875 case MPI_EVENT_STATE_CHANGE:
5876 ds = "State Change";
5877 break;
5878 case MPI_EVENT_UNIT_ATTENTION:
5879 ds = "Unit Attention";
5880 break;
5881 case MPI_EVENT_IOC_BUS_RESET:
5882 ds = "IOC Bus Reset";
5883 break;
5884 case MPI_EVENT_EXT_BUS_RESET:
5885 ds = "External Bus Reset";
5886 break;
5887 case MPI_EVENT_RESCAN:
5888 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889 break;
5890 case MPI_EVENT_LINK_STATUS_CHANGE:
5891 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5892 ds = "Link Status(FAILURE) Change";
5893 else
5894 ds = "Link Status(ACTIVE) Change";
5895 break;
5896 case MPI_EVENT_LOOP_STATE_CHANGE:
5897 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5898 ds = "Loop State(LIP) Change";
5899 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005900 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 else
Eric Moore509e5e52006-04-26 13:22:37 -06005902 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903 break;
5904 case MPI_EVENT_LOGOUT:
5905 ds = "Logout";
5906 break;
5907 case MPI_EVENT_EVENT_CHANGE:
5908 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06005909 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 else
Eric Moore4f766dc2006-07-11 17:24:07 -06005911 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 break;
5913 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005914 {
5915 u8 ReasonCode = (u8)(evData0 >> 16);
5916 switch (ReasonCode) {
5917 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5918 ds = "Integrated Raid: Volume Created";
5919 break;
5920 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5921 ds = "Integrated Raid: Volume Deleted";
5922 break;
5923 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5924 ds = "Integrated Raid: Volume Settings Changed";
5925 break;
5926 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5927 ds = "Integrated Raid: Volume Status Changed";
5928 break;
5929 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5930 ds = "Integrated Raid: Volume Physdisk Changed";
5931 break;
5932 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5933 ds = "Integrated Raid: Physdisk Created";
5934 break;
5935 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5936 ds = "Integrated Raid: Physdisk Deleted";
5937 break;
5938 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5939 ds = "Integrated Raid: Physdisk Settings Changed";
5940 break;
5941 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5942 ds = "Integrated Raid: Physdisk Status Changed";
5943 break;
5944 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5945 ds = "Integrated Raid: Domain Validation Needed";
5946 break;
5947 case MPI_EVENT_RAID_RC_SMART_DATA :
5948 ds = "Integrated Raid; Smart Data";
5949 break;
5950 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5951 ds = "Integrated Raid: Replace Action Started";
5952 break;
5953 default:
5954 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005956 }
5957 break;
5958 }
5959 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5960 ds = "SCSI Device Status Change";
5961 break;
5962 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5963 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005964 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07005965 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005966 u8 ReasonCode = (u8)(evData0 >> 16);
5967 switch (ReasonCode) {
5968 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005969 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005970 "SAS Device Status Change: Added: "
5971 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005972 break;
5973 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005974 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005975 "SAS Device Status Change: Deleted: "
5976 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005977 break;
5978 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005979 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005980 "SAS Device Status Change: SMART Data: "
5981 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005982 break;
5983 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005984 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005985 "SAS Device Status Change: No Persistancy: "
5986 "id=%d channel=%d", id, channel);
5987 break;
5988 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
5989 snprintf(evStr, EVENT_DESCR_STR_SZ,
5990 "SAS Device Status Change: Unsupported Device "
5991 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06005992 break;
5993 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
5994 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005995 "SAS Device Status Change: Internal Device "
5996 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06005997 break;
5998 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
5999 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006000 "SAS Device Status Change: Internal Task "
6001 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006002 break;
6003 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6004 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006005 "SAS Device Status Change: Internal Abort "
6006 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006007 break;
6008 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6009 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006010 "SAS Device Status Change: Internal Clear "
6011 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006012 break;
6013 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6014 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006015 "SAS Device Status Change: Internal Query "
6016 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006017 break;
6018 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006019 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006020 "SAS Device Status Change: Unknown: "
6021 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006022 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006023 }
6024 break;
6025 }
6026 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6027 ds = "Bus Timer Expired";
6028 break;
6029 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006030 {
6031 u16 curr_depth = (u16)(evData0 >> 16);
6032 u8 channel = (u8)(evData0 >> 8);
6033 u8 id = (u8)(evData0);
6034
6035 snprintf(evStr, EVENT_DESCR_STR_SZ,
6036 "Queue Full: channel=%d id=%d depth=%d",
6037 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006038 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006039 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006040 case MPI_EVENT_SAS_SES:
6041 ds = "SAS SES Event";
6042 break;
6043 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6044 ds = "Persistent Table Full";
6045 break;
6046 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006047 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006048 u8 LinkRates = (u8)(evData0 >> 8);
6049 u8 PhyNumber = (u8)(evData0);
6050 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6051 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6052 switch (LinkRates) {
6053 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006054 snprintf(evStr, EVENT_DESCR_STR_SZ,
6055 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006056 " Rate Unknown",PhyNumber);
6057 break;
6058 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006059 snprintf(evStr, EVENT_DESCR_STR_SZ,
6060 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006061 " Phy Disabled",PhyNumber);
6062 break;
6063 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006064 snprintf(evStr, EVENT_DESCR_STR_SZ,
6065 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006066 " Failed Speed Nego",PhyNumber);
6067 break;
6068 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006069 snprintf(evStr, EVENT_DESCR_STR_SZ,
6070 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006071 " Sata OOB Completed",PhyNumber);
6072 break;
6073 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006074 snprintf(evStr, EVENT_DESCR_STR_SZ,
6075 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006076 " Rate 1.5 Gbps",PhyNumber);
6077 break;
6078 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006079 snprintf(evStr, EVENT_DESCR_STR_SZ,
6080 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006081 " Rate 3.0 Gpbs",PhyNumber);
6082 break;
6083 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006084 snprintf(evStr, EVENT_DESCR_STR_SZ,
6085 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006086 break;
6087 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006088 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006089 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006090 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6091 ds = "SAS Discovery Error";
6092 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006093 case MPI_EVENT_IR_RESYNC_UPDATE:
6094 {
6095 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006096 snprintf(evStr, EVENT_DESCR_STR_SZ,
6097 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006098 break;
6099 }
6100 case MPI_EVENT_IR2:
6101 {
6102 u8 ReasonCode = (u8)(evData0 >> 16);
6103 switch (ReasonCode) {
6104 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6105 ds = "IR2: LD State Changed";
6106 break;
6107 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6108 ds = "IR2: PD State Changed";
6109 break;
6110 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6111 ds = "IR2: Bad Block Table Full";
6112 break;
6113 case MPI_EVENT_IR2_RC_PD_INSERTED:
6114 ds = "IR2: PD Inserted";
6115 break;
6116 case MPI_EVENT_IR2_RC_PD_REMOVED:
6117 ds = "IR2: PD Removed";
6118 break;
6119 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6120 ds = "IR2: Foreign CFG Detected";
6121 break;
6122 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6123 ds = "IR2: Rebuild Medium Error";
6124 break;
6125 default:
6126 ds = "IR2";
6127 break;
6128 }
6129 break;
6130 }
6131 case MPI_EVENT_SAS_DISCOVERY:
6132 {
6133 if (evData0)
6134 ds = "SAS Discovery: Start";
6135 else
6136 ds = "SAS Discovery: Stop";
6137 break;
6138 }
6139 case MPI_EVENT_LOG_ENTRY_ADDED:
6140 ds = "SAS Log Entry Added";
6141 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006142
Eric Moorec6c727a2007-01-29 09:44:54 -07006143 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6144 {
6145 u8 phy_num = (u8)(evData0);
6146 u8 port_num = (u8)(evData0 >> 8);
6147 u8 port_width = (u8)(evData0 >> 16);
6148 u8 primative = (u8)(evData0 >> 24);
6149 snprintf(evStr, EVENT_DESCR_STR_SZ,
6150 "SAS Broadcase Primative: phy=%d port=%d "
6151 "width=%d primative=0x%02x",
6152 phy_num, port_num, port_width, primative);
6153 break;
6154 }
6155
6156 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6157 {
6158 u8 reason = (u8)(evData0);
6159 u8 port_num = (u8)(evData0 >> 8);
6160 u16 handle = le16_to_cpu(evData0 >> 16);
6161
6162 snprintf(evStr, EVENT_DESCR_STR_SZ,
6163 "SAS Initiator Device Status Change: reason=0x%02x "
6164 "port=%d handle=0x%04x",
6165 reason, port_num, handle);
6166 break;
6167 }
6168
6169 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6170 {
6171 u8 max_init = (u8)(evData0);
6172 u8 current_init = (u8)(evData0 >> 8);
6173
6174 snprintf(evStr, EVENT_DESCR_STR_SZ,
6175 "SAS Initiator Device Table Overflow: max initiators=%02d "
6176 "current initators=%02d",
6177 max_init, current_init);
6178 break;
6179 }
6180 case MPI_EVENT_SAS_SMP_ERROR:
6181 {
6182 u8 status = (u8)(evData0);
6183 u8 port_num = (u8)(evData0 >> 8);
6184 u8 result = (u8)(evData0 >> 16);
6185
6186 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6187 snprintf(evStr, EVENT_DESCR_STR_SZ,
6188 "SAS SMP Error: port=%d result=0x%02x",
6189 port_num, result);
6190 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6191 snprintf(evStr, EVENT_DESCR_STR_SZ,
6192 "SAS SMP Error: port=%d : CRC Error",
6193 port_num);
6194 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6195 snprintf(evStr, EVENT_DESCR_STR_SZ,
6196 "SAS SMP Error: port=%d : Timeout",
6197 port_num);
6198 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6199 snprintf(evStr, EVENT_DESCR_STR_SZ,
6200 "SAS SMP Error: port=%d : No Destination",
6201 port_num);
6202 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6203 snprintf(evStr, EVENT_DESCR_STR_SZ,
6204 "SAS SMP Error: port=%d : Bad Destination",
6205 port_num);
6206 else
6207 snprintf(evStr, EVENT_DESCR_STR_SZ,
6208 "SAS SMP Error: port=%d : status=0x%02x",
6209 port_num, status);
6210 break;
6211 }
6212
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213 /*
6214 * MPT base "custom" events may be added here...
6215 */
6216 default:
6217 ds = "Unknown";
6218 break;
6219 }
Eric Moore509e5e52006-04-26 13:22:37 -06006220 if (ds)
6221 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222}
6223
6224/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006225/**
6226 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227 * @ioc: Pointer to MPT_ADAPTER structure
6228 * @pEventReply: Pointer to EventNotification reply frame
6229 * @evHandlers: Pointer to integer, number of event handlers
6230 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006231 * Routes a received EventNotificationReply to all currently registered
6232 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233 * Returns sum of event handlers return values.
6234 */
6235static int
6236ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6237{
6238 u16 evDataLen;
6239 u32 evData0 = 0;
6240// u32 evCtx;
6241 int ii;
6242 int r = 0;
6243 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006244 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 u8 event;
6246
6247 /*
6248 * Do platform normalization of values
6249 */
6250 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6251// evCtx = le32_to_cpu(pEventReply->EventContext);
6252 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6253 if (evDataLen) {
6254 evData0 = le32_to_cpu(pEventReply->Data[0]);
6255 }
6256
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006257 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07006258 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006260 event,
6261 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262
Moore, Eric3a892be2006-03-14 09:14:03 -07006263#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6265 for (ii = 0; ii < evDataLen; ii++)
6266 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6267 printk("\n");
6268#endif
6269
6270 /*
6271 * Do general / base driver event processing
6272 */
6273 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6275 if (evDataLen) {
6276 u8 evState = evData0 & 0xFF;
6277
6278 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6279
6280 /* Update EventState field in cached IocFacts */
6281 if (ioc->facts.Function) {
6282 ioc->facts.EventState = evState;
6283 }
6284 }
6285 break;
Moore, Ericece50912006-01-16 18:53:19 -07006286 case MPI_EVENT_INTEGRATED_RAID:
6287 mptbase_raid_process_event_data(ioc,
6288 (MpiEventDataRaid_t *)pEventReply->Data);
6289 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006290 default:
6291 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292 }
6293
6294 /*
6295 * Should this event be logged? Events are written sequentially.
6296 * When buffer is full, start again at the top.
6297 */
6298 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6299 int idx;
6300
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006301 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302
6303 ioc->events[idx].event = event;
6304 ioc->events[idx].eventContext = ioc->eventContext;
6305
6306 for (ii = 0; ii < 2; ii++) {
6307 if (ii < evDataLen)
6308 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6309 else
6310 ioc->events[idx].data[ii] = 0;
6311 }
6312
6313 ioc->eventContext++;
6314 }
6315
6316
6317 /*
6318 * Call each currently registered protocol event handler.
6319 */
6320 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6321 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006322 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323 ioc->name, ii));
6324 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6325 handlers++;
6326 }
6327 }
6328 /* FIXME? Examine results here? */
6329
6330 /*
6331 * If needed, send (a single) EventAck.
6332 */
6333 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006334 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006335 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006336 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006337 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 ioc->name, ii));
6339 }
6340 }
6341
6342 *evHandlers = handlers;
6343 return r;
6344}
6345
6346/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006347/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6349 * @ioc: Pointer to MPT_ADAPTER structure
6350 * @log_info: U32 LogInfo reply word from the IOC
6351 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006352 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353 */
6354static void
6355mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6356{
6357 static char *subcl_str[8] = {
6358 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6359 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6360 };
6361 u8 subcl = (log_info >> 24) & 0x7;
6362
6363 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6364 ioc->name, log_info, subcl_str[subcl]);
6365}
6366
6367/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006368/**
Moore, Eric335a9412006-01-17 17:06:23 -07006369 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370 * @ioc: Pointer to MPT_ADAPTER structure
6371 * @mr: Pointer to MPT reply frame
6372 * @log_info: U32 LogInfo word from the IOC
6373 *
6374 * Refer to lsi/sp_log.h.
6375 */
6376static void
Moore, Eric335a9412006-01-17 17:06:23 -07006377mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378{
6379 u32 info = log_info & 0x00FF0000;
6380 char *desc = "unknown";
6381
6382 switch (info) {
6383 case 0x00010000:
6384 desc = "bug! MID not found";
6385 if (ioc->reload_fw == 0)
6386 ioc->reload_fw++;
6387 break;
6388
6389 case 0x00020000:
6390 desc = "Parity Error";
6391 break;
6392
6393 case 0x00030000:
6394 desc = "ASYNC Outbound Overrun";
6395 break;
6396
6397 case 0x00040000:
6398 desc = "SYNC Offset Error";
6399 break;
6400
6401 case 0x00050000:
6402 desc = "BM Change";
6403 break;
6404
6405 case 0x00060000:
6406 desc = "Msg In Overflow";
6407 break;
6408
6409 case 0x00070000:
6410 desc = "DMA Error";
6411 break;
6412
6413 case 0x00080000:
6414 desc = "Outbound DMA Overrun";
6415 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006416
Linus Torvalds1da177e2005-04-16 15:20:36 -07006417 case 0x00090000:
6418 desc = "Task Management";
6419 break;
6420
6421 case 0x000A0000:
6422 desc = "Device Problem";
6423 break;
6424
6425 case 0x000B0000:
6426 desc = "Invalid Phase Change";
6427 break;
6428
6429 case 0x000C0000:
6430 desc = "Untagged Table Size";
6431 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006432
Linus Torvalds1da177e2005-04-16 15:20:36 -07006433 }
6434
6435 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6436}
6437
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006438/* strings for sas loginfo */
6439 static char *originator_str[] = {
6440 "IOP", /* 00h */
6441 "PL", /* 01h */
6442 "IR" /* 02h */
6443 };
6444 static char *iop_code_str[] = {
6445 NULL, /* 00h */
6446 "Invalid SAS Address", /* 01h */
6447 NULL, /* 02h */
6448 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006449 "Diag Message Error", /* 04h */
6450 "Task Terminated", /* 05h */
6451 "Enclosure Management", /* 06h */
6452 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006453 };
6454 static char *pl_code_str[] = {
6455 NULL, /* 00h */
6456 "Open Failure", /* 01h */
6457 "Invalid Scatter Gather List", /* 02h */
6458 "Wrong Relative Offset or Frame Length", /* 03h */
6459 "Frame Transfer Error", /* 04h */
6460 "Transmit Frame Connected Low", /* 05h */
6461 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6462 "SATA Read Log Receive Data Error", /* 07h */
6463 "SATA NCQ Fail All Commands After Error", /* 08h */
6464 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6465 "Receive Frame Invalid Message", /* 0Ah */
6466 "Receive Context Message Valid Error", /* 0Bh */
6467 "Receive Frame Current Frame Error", /* 0Ch */
6468 "SATA Link Down", /* 0Dh */
6469 "Discovery SATA Init W IOS", /* 0Eh */
6470 "Config Invalid Page", /* 0Fh */
6471 "Discovery SATA Init Timeout", /* 10h */
6472 "Reset", /* 11h */
6473 "Abort", /* 12h */
6474 "IO Not Yet Executed", /* 13h */
6475 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006476 "Persistent Reservation Out Not Affiliation "
6477 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006478 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006479 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006480 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006481 NULL, /* 19h */
6482 NULL, /* 1Ah */
6483 NULL, /* 1Bh */
6484 NULL, /* 1Ch */
6485 NULL, /* 1Dh */
6486 NULL, /* 1Eh */
6487 NULL, /* 1Fh */
6488 "Enclosure Management" /* 20h */
6489 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006490 static char *ir_code_str[] = {
6491 "Raid Action Error", /* 00h */
6492 NULL, /* 00h */
6493 NULL, /* 01h */
6494 NULL, /* 02h */
6495 NULL, /* 03h */
6496 NULL, /* 04h */
6497 NULL, /* 05h */
6498 NULL, /* 06h */
6499 NULL /* 07h */
6500 };
6501 static char *raid_sub_code_str[] = {
6502 NULL, /* 00h */
6503 "Volume Creation Failed: Data Passed too "
6504 "Large", /* 01h */
6505 "Volume Creation Failed: Duplicate Volumes "
6506 "Attempted", /* 02h */
6507 "Volume Creation Failed: Max Number "
6508 "Supported Volumes Exceeded", /* 03h */
6509 "Volume Creation Failed: DMA Error", /* 04h */
6510 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6511 "Volume Creation Failed: Error Reading "
6512 "MFG Page 4", /* 06h */
6513 "Volume Creation Failed: Creating Internal "
6514 "Structures", /* 07h */
6515 NULL, /* 08h */
6516 NULL, /* 09h */
6517 NULL, /* 0Ah */
6518 NULL, /* 0Bh */
6519 NULL, /* 0Ch */
6520 NULL, /* 0Dh */
6521 NULL, /* 0Eh */
6522 NULL, /* 0Fh */
6523 "Activation failed: Already Active Volume", /* 10h */
6524 "Activation failed: Unsupported Volume Type", /* 11h */
6525 "Activation failed: Too Many Active Volumes", /* 12h */
6526 "Activation failed: Volume ID in Use", /* 13h */
6527 "Activation failed: Reported Failure", /* 14h */
6528 "Activation failed: Importing a Volume", /* 15h */
6529 NULL, /* 16h */
6530 NULL, /* 17h */
6531 NULL, /* 18h */
6532 NULL, /* 19h */
6533 NULL, /* 1Ah */
6534 NULL, /* 1Bh */
6535 NULL, /* 1Ch */
6536 NULL, /* 1Dh */
6537 NULL, /* 1Eh */
6538 NULL, /* 1Fh */
6539 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6540 "Phys Disk failed: Data Passed too Large", /* 21h */
6541 "Phys Disk failed: DMA Error", /* 22h */
6542 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6543 "Phys Disk failed: Creating Phys Disk Config "
6544 "Page", /* 24h */
6545 NULL, /* 25h */
6546 NULL, /* 26h */
6547 NULL, /* 27h */
6548 NULL, /* 28h */
6549 NULL, /* 29h */
6550 NULL, /* 2Ah */
6551 NULL, /* 2Bh */
6552 NULL, /* 2Ch */
6553 NULL, /* 2Dh */
6554 NULL, /* 2Eh */
6555 NULL, /* 2Fh */
6556 "Compatibility Error: IR Disabled", /* 30h */
6557 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6558 "Compatibility Error: Device not Direct Access "
6559 "Device ", /* 32h */
6560 "Compatibility Error: Removable Device Found", /* 33h */
6561 "Compatibility Error: Device SCSI Version not "
6562 "2 or Higher", /* 34h */
6563 "Compatibility Error: SATA Device, 48 BIT LBA "
6564 "not Supported", /* 35h */
6565 "Compatibility Error: Device doesn't have "
6566 "512 Byte Block Sizes", /* 36h */
6567 "Compatibility Error: Volume Type Check Failed", /* 37h */
6568 "Compatibility Error: Volume Type is "
6569 "Unsupported by FW", /* 38h */
6570 "Compatibility Error: Disk Drive too Small for "
6571 "use in Volume", /* 39h */
6572 "Compatibility Error: Phys Disk for Create "
6573 "Volume not Found", /* 3Ah */
6574 "Compatibility Error: Too Many or too Few "
6575 "Disks for Volume Type", /* 3Bh */
6576 "Compatibility Error: Disk stripe Sizes "
6577 "Must be 64KB", /* 3Ch */
6578 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6579 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006580
6581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006582/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006583 * mpt_sas_log_info - Log information returned from SAS IOC.
6584 * @ioc: Pointer to MPT_ADAPTER structure
6585 * @log_info: U32 LogInfo reply word from the IOC
6586 *
6587 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006588 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006589static void
6590mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6591{
6592union loginfo_type {
6593 u32 loginfo;
6594 struct {
6595 u32 subcode:16;
6596 u32 code:8;
6597 u32 originator:4;
6598 u32 bus_type:4;
6599 }dw;
6600};
6601 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006602 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006603 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07006604 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006605
6606 sas_loginfo.loginfo = log_info;
6607 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6608 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6609 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07006610
6611 originator_desc = originator_str[sas_loginfo.dw.originator];
6612
6613 switch (sas_loginfo.dw.originator) {
6614
6615 case 0: /* IOP */
6616 if (sas_loginfo.dw.code <
6617 sizeof(iop_code_str)/sizeof(char*))
6618 code_desc = iop_code_str[sas_loginfo.dw.code];
6619 break;
6620 case 1: /* PL */
6621 if (sas_loginfo.dw.code <
6622 sizeof(pl_code_str)/sizeof(char*))
6623 code_desc = pl_code_str[sas_loginfo.dw.code];
6624 break;
6625 case 2: /* IR */
6626 if (sas_loginfo.dw.code >=
6627 sizeof(ir_code_str)/sizeof(char*))
6628 break;
6629 code_desc = ir_code_str[sas_loginfo.dw.code];
6630 if (sas_loginfo.dw.subcode >=
6631 sizeof(raid_sub_code_str)/sizeof(char*))
6632 break;
6633 if (sas_loginfo.dw.code == 0)
6634 sub_code_desc =
6635 raid_sub_code_str[sas_loginfo.dw.subcode];
6636 break;
6637 default:
6638 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006639 }
6640
Eric Moorec6c727a2007-01-29 09:44:54 -07006641 if (sub_code_desc != NULL)
6642 printk(MYIOC_s_INFO_FMT
6643 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6644 " SubCode={%s}\n",
6645 ioc->name, log_info, originator_desc, code_desc,
6646 sub_code_desc);
6647 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006648 printk(MYIOC_s_INFO_FMT
6649 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6650 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07006651 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006652 sas_loginfo.dw.subcode);
6653 else
6654 printk(MYIOC_s_INFO_FMT
6655 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6656 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07006657 ioc->name, log_info, originator_desc,
6658 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006659}
6660
Eric Moorec6c727a2007-01-29 09:44:54 -07006661#ifdef MPT_DEBUG_REPLY
Linus Torvalds1da177e2005-04-16 15:20:36 -07006662/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006663/**
Eric Moorec6c727a2007-01-29 09:44:54 -07006664 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
6665 * @ioc: Pointer to MPT_ADAPTER structure
6666 * ioc_status: U32 IOCStatus word from IOC
6667 * @mf: Pointer to MPT request frame
6668 *
6669 * Refer to lsi/mpi.h.
6670 **/
6671static void
6672mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6673{
6674 Config_t *pReq = (Config_t *)mf;
6675 char extend_desc[EVENT_DESCR_STR_SZ];
6676 char *desc = NULL;
6677 u32 form;
6678 u8 page_type;
6679
6680 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
6681 page_type = pReq->ExtPageType;
6682 else
6683 page_type = pReq->Header.PageType;
6684
6685 /*
6686 * ignore invalid page messages for GET_NEXT_HANDLE
6687 */
6688 form = le32_to_cpu(pReq->PageAddress);
6689 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
6690 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
6691 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
6692 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
6693 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
6694 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
6695 return;
6696 }
6697 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
6698 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
6699 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
6700 return;
6701 }
6702
6703 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
6704 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
6705 page_type, pReq->Header.PageNumber, pReq->Action, form);
6706
6707 switch (ioc_status) {
6708
6709 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6710 desc = "Config Page Invalid Action";
6711 break;
6712
6713 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6714 desc = "Config Page Invalid Type";
6715 break;
6716
6717 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6718 desc = "Config Page Invalid Page";
6719 break;
6720
6721 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6722 desc = "Config Page Invalid Data";
6723 break;
6724
6725 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6726 desc = "Config Page No Defaults";
6727 break;
6728
6729 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6730 desc = "Config Page Can't Commit";
6731 break;
6732 }
6733
6734 if (!desc)
6735 return;
6736
6737 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
6738 ioc->name, ioc_status, desc, extend_desc);
6739}
6740
6741/**
6742 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743 * @ioc: Pointer to MPT_ADAPTER structure
6744 * @ioc_status: U32 IOCStatus word from IOC
6745 * @mf: Pointer to MPT request frame
6746 *
6747 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006748 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07006749static void
Eric Moorec6c727a2007-01-29 09:44:54 -07006750mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751{
6752 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06006753 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006754
6755 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07006756
6757/****************************************************************************/
6758/* Common IOCStatus values for all replies */
6759/****************************************************************************/
6760
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6762 desc = "Invalid Function";
6763 break;
6764
6765 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6766 desc = "Busy";
6767 break;
6768
6769 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6770 desc = "Invalid SGL";
6771 break;
6772
6773 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6774 desc = "Internal Error";
6775 break;
6776
6777 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6778 desc = "Reserved";
6779 break;
6780
6781 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6782 desc = "Insufficient Resources";
6783 break;
6784
6785 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6786 desc = "Invalid Field";
6787 break;
6788
6789 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6790 desc = "Invalid State";
6791 break;
6792
Eric Moorec6c727a2007-01-29 09:44:54 -07006793/****************************************************************************/
6794/* Config IOCStatus values */
6795/****************************************************************************/
6796
Linus Torvalds1da177e2005-04-16 15:20:36 -07006797 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6798 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6799 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6800 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6801 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6802 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07006803 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006804 break;
6805
Eric Moorec6c727a2007-01-29 09:44:54 -07006806/****************************************************************************/
6807/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
6808/* */
6809/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
6810/* */
6811/****************************************************************************/
6812
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07006815 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6816 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6817 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6818 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006819 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006820 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006821 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006822 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006823 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006824 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07006825 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006826 break;
6827
Eric Moorec6c727a2007-01-29 09:44:54 -07006828/****************************************************************************/
6829/* SCSI Target values */
6830/****************************************************************************/
6831
6832 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
6833 desc = "Target: Priority IO";
6834 break;
6835
6836 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
6837 desc = "Target: Invalid Port";
6838 break;
6839
6840 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
6841 desc = "Target Invalid IO Index:";
6842 break;
6843
6844 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
6845 desc = "Target: Aborted";
6846 break;
6847
6848 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
6849 desc = "Target: No Conn Retryable";
6850 break;
6851
6852 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
6853 desc = "Target: No Connection";
6854 break;
6855
6856 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
6857 desc = "Target: Transfer Count Mismatch";
6858 break;
6859
6860 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
6861 desc = "Target: STS Data not Sent";
6862 break;
6863
6864 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
6865 desc = "Target: Data Offset Error";
6866 break;
6867
6868 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
6869 desc = "Target: Too Much Write Data";
6870 break;
6871
6872 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
6873 desc = "Target: IU Too Short";
6874 break;
6875
6876 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
6877 desc = "Target: ACK NAK Timeout";
6878 break;
6879
6880 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
6881 desc = "Target: Nak Received";
6882 break;
6883
6884/****************************************************************************/
6885/* Fibre Channel Direct Access values */
6886/****************************************************************************/
6887
6888 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
6889 desc = "FC: Aborted";
6890 break;
6891
6892 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
6893 desc = "FC: RX ID Invalid";
6894 break;
6895
6896 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
6897 desc = "FC: DID Invalid";
6898 break;
6899
6900 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
6901 desc = "FC: Node Logged Out";
6902 break;
6903
6904 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
6905 desc = "FC: Exchange Canceled";
6906 break;
6907
6908/****************************************************************************/
6909/* LAN values */
6910/****************************************************************************/
6911
6912 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
6913 desc = "LAN: Device not Found";
6914 break;
6915
6916 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
6917 desc = "LAN: Device Failure";
6918 break;
6919
6920 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
6921 desc = "LAN: Transmit Error";
6922 break;
6923
6924 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
6925 desc = "LAN: Transmit Aborted";
6926 break;
6927
6928 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
6929 desc = "LAN: Receive Error";
6930 break;
6931
6932 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
6933 desc = "LAN: Receive Aborted";
6934 break;
6935
6936 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
6937 desc = "LAN: Partial Packet";
6938 break;
6939
6940 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
6941 desc = "LAN: Canceled";
6942 break;
6943
6944/****************************************************************************/
6945/* Serial Attached SCSI values */
6946/****************************************************************************/
6947
6948 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
6949 desc = "SAS: SMP Request Failed";
6950 break;
6951
6952 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
6953 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006954 break;
6955
6956 default:
6957 desc = "Others";
6958 break;
6959 }
Eric Moorec6c727a2007-01-29 09:44:54 -07006960
6961 if (!desc)
6962 return;
6963
6964 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006965}
Eric Moorec6c727a2007-01-29 09:44:54 -07006966#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006967
6968/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006969EXPORT_SYMBOL(mpt_attach);
6970EXPORT_SYMBOL(mpt_detach);
6971#ifdef CONFIG_PM
6972EXPORT_SYMBOL(mpt_resume);
6973EXPORT_SYMBOL(mpt_suspend);
6974#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006975EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006976EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006977EXPORT_SYMBOL(mpt_register);
6978EXPORT_SYMBOL(mpt_deregister);
6979EXPORT_SYMBOL(mpt_event_register);
6980EXPORT_SYMBOL(mpt_event_deregister);
6981EXPORT_SYMBOL(mpt_reset_register);
6982EXPORT_SYMBOL(mpt_reset_deregister);
6983EXPORT_SYMBOL(mpt_device_driver_register);
6984EXPORT_SYMBOL(mpt_device_driver_deregister);
6985EXPORT_SYMBOL(mpt_get_msg_frame);
6986EXPORT_SYMBOL(mpt_put_msg_frame);
6987EXPORT_SYMBOL(mpt_free_msg_frame);
6988EXPORT_SYMBOL(mpt_add_sge);
6989EXPORT_SYMBOL(mpt_send_handshake_request);
6990EXPORT_SYMBOL(mpt_verify_adapter);
6991EXPORT_SYMBOL(mpt_GetIocState);
6992EXPORT_SYMBOL(mpt_print_ioc_summary);
6993EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006994EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006995EXPORT_SYMBOL(mpt_HardResetHandler);
6996EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006997EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006998EXPORT_SYMBOL(mpt_alloc_fw_memory);
6999EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007000EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007001EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007002
Linus Torvalds1da177e2005-04-16 15:20:36 -07007003/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007004/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007005 * fusion_init - Fusion MPT base driver initialization routine.
7006 *
7007 * Returns 0 for success, non-zero for failure.
7008 */
7009static int __init
7010fusion_init(void)
7011{
7012 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007013
7014 show_mptmod_ver(my_NAME, my_VERSION);
7015 printk(KERN_INFO COPYRIGHT "\n");
7016
7017 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
7018 MptCallbacks[i] = NULL;
7019 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
7020 MptEvHandlers[i] = NULL;
7021 MptResetHandlers[i] = NULL;
7022 }
7023
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007024 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007025 * EventNotification handling.
7026 */
7027 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7028
7029 /* Register for hard reset handling callbacks.
7030 */
7031 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
7032 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
7033 } else {
7034 /* FIXME! */
7035 }
7036
7037#ifdef CONFIG_PROC_FS
7038 (void) procmpt_create();
7039#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007040 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007041}
7042
7043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007044/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007045 * fusion_exit - Perform driver unload cleanup.
7046 *
7047 * This routine frees all resources associated with each MPT adapter
7048 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7049 */
7050static void __exit
7051fusion_exit(void)
7052{
7053
7054 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
7055
Linus Torvalds1da177e2005-04-16 15:20:36 -07007056 mpt_reset_deregister(mpt_base_index);
7057
7058#ifdef CONFIG_PROC_FS
7059 procmpt_destroy();
7060#endif
7061}
7062
Linus Torvalds1da177e2005-04-16 15:20:36 -07007063module_init(fusion_init);
7064module_exit(fusion_exit);