blob: a07f0f81f96bd49ffb0615f3f66f97500fcc1103 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * (mailto:mpt_linux_developer@lsil.com)
10 *
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);
180static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
181static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700182static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600183static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700184static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static int __init fusion_init (void);
188static void __exit fusion_exit (void);
189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#define CHIPREG_READ32(addr) readl_relaxed(addr)
191#define CHIPREG_READ32_dmasync(addr) readl(addr)
192#define CHIPREG_WRITE32(addr,val) writel(val, addr)
193#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
194#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
195
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600196static void
197pci_disable_io_access(struct pci_dev *pdev)
198{
199 u16 command_reg;
200
201 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
202 command_reg &= ~1;
203 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
204}
205
206static void
207pci_enable_io_access(struct pci_dev *pdev)
208{
209 u16 command_reg;
210
211 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
212 command_reg |= 1;
213 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
214}
215
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600216/*
217 * Process turbo (context) reply...
218 */
219static void
220mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
221{
222 MPT_FRAME_HDR *mf = NULL;
223 MPT_FRAME_HDR *mr = NULL;
224 int req_idx = 0;
225 int cb_idx;
226
227 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
228 ioc->name, pa));
229
230 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
231 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
232 req_idx = pa & 0x0000FFFF;
233 cb_idx = (pa & 0x00FF0000) >> 16;
234 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
235 break;
236 case MPI_CONTEXT_REPLY_TYPE_LAN:
237 cb_idx = mpt_lan_index;
238 /*
239 * Blind set of mf to NULL here was fatal
240 * after lan_reply says "freeme"
241 * Fix sort of combined with an optimization here;
242 * added explicit check for case where lan_reply
243 * was just returning 1 and doing nothing else.
244 * For this case skip the callback, but set up
245 * proper mf value first here:-)
246 */
247 if ((pa & 0x58000000) == 0x58000000) {
248 req_idx = pa & 0x0000FFFF;
249 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
250 mpt_free_msg_frame(ioc, mf);
251 mb();
252 return;
253 break;
254 }
255 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
256 break;
257 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
258 cb_idx = mpt_stm_index;
259 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
260 break;
261 default:
262 cb_idx = 0;
263 BUG();
264 }
265
266 /* Check for (valid) IO callback! */
267 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
268 MptCallbacks[cb_idx] == NULL) {
269 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
270 __FUNCTION__, ioc->name, cb_idx);
271 goto out;
272 }
273
274 if (MptCallbacks[cb_idx](ioc, mf, mr))
275 mpt_free_msg_frame(ioc, mf);
276 out:
277 mb();
278}
279
280static void
281mpt_reply(MPT_ADAPTER *ioc, u32 pa)
282{
283 MPT_FRAME_HDR *mf;
284 MPT_FRAME_HDR *mr;
285 int req_idx;
286 int cb_idx;
287 int freeme;
288
289 u32 reply_dma_low;
290 u16 ioc_stat;
291
292 /* non-TURBO reply! Hmmm, something may be up...
293 * Newest turbo reply mechanism; get address
294 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
295 */
296
297 /* Map DMA address of reply header to cpu address.
298 * pa is 32 bits - but the dma address may be 32 or 64 bits
299 * get offset based only only the low addresses
300 */
301
302 reply_dma_low = (pa <<= 1);
303 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
304 (reply_dma_low - ioc->reply_frames_low_dma));
305
306 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
307 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
308 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
309
310 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
311 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
312 DBG_DUMP_REPLY_FRAME(mr)
313
314 /* Check/log IOC log info
315 */
316 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
317 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
318 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
319 if (ioc->bus_type == FC)
320 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700321 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700322 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600323 else if (ioc->bus_type == SAS)
324 mpt_sas_log_info(ioc, log_info);
325 }
326 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700327 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600328 cb_idx != mpt_stm_index &&
329 cb_idx != mpt_lan_index)
330 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
331 }
332
333
334 /* Check for (valid) IO callback! */
335 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
336 MptCallbacks[cb_idx] == NULL) {
337 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
338 __FUNCTION__, ioc->name, cb_idx);
339 freeme = 0;
340 goto out;
341 }
342
343 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
344
345 out:
346 /* Flush (non-TURBO) reply with a WRITE! */
347 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
348
349 if (freeme)
350 mpt_free_msg_frame(ioc, mf);
351 mb();
352}
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800355/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
357 * @irq: irq number (not used)
358 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 *
360 * This routine is registered via the request_irq() kernel API call,
361 * and handles all interrupts generated from a specific MPT adapter
362 * (also referred to as a IO Controller or IOC).
363 * This routine must clear the interrupt from the adapter and does
364 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200365 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 *
367 * This routine handles register-level access of the adapter but
368 * dispatches (calls) a protocol-specific callback routine to handle
369 * the protocol-specific details of the MPT request completion.
370 */
371static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100372mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600374 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600375 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
376
377 if (pa == 0xFFFFFFFF)
378 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 /*
381 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600383 do {
384 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600385 mpt_reply(ioc, pa);
386 else
387 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600388 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
389 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
391 return IRQ_HANDLED;
392}
393
394/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800395/**
396 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 * @ioc: Pointer to MPT_ADAPTER structure
398 * @mf: Pointer to original MPT request frame
399 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
400 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800401 * MPT base driver's callback routine; all base driver
402 * "internal" request/reply processing is routed here.
403 * Currently used for EventNotification and EventAck handling.
404 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200405 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 * should be freed, or 0 if it shouldn't.
407 */
408static int
409mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
410{
411 int freereq = 1;
412 u8 func;
413
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200414 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200416#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
418 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
419 DBG_DUMP_REQUEST_FRAME_HDR(mf)
420 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200421#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
423 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200424 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 ioc->name, func));
426
427 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
428 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
429 int evHandlers = 0;
430 int results;
431
432 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
433 if (results != evHandlers) {
434 /* CHECKME! Any special handling needed here? */
Moore, Eric3a892be2006-03-14 09:14:03 -0700435 devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 ioc->name, evHandlers, results));
437 }
438
439 /*
440 * Hmmm... It seems that EventNotificationReply is an exception
441 * to the rule of one reply per request.
442 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200443 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200445 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700446 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200447 ioc->name, pEvReply));
448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450#ifdef CONFIG_PROC_FS
451// LogEvent(ioc, pEvReply);
452#endif
453
454 } else if (func == MPI_FUNCTION_EVENT_ACK) {
455 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
456 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700457 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 CONFIGPARMS *pCfg;
459 unsigned long flags;
460
461 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
462 ioc->name, mf, reply));
463
464 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
465
466 if (pCfg) {
467 /* disable timer and remove from linked list */
468 del_timer(&pCfg->timer);
469
470 spin_lock_irqsave(&ioc->FreeQlock, flags);
471 list_del(&pCfg->linkage);
472 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
473
474 /*
475 * If IOC Status is SUCCESS, save the header
476 * and set the status code to GOOD.
477 */
478 pCfg->status = MPT_CONFIG_ERROR;
479 if (reply) {
480 ConfigReply_t *pReply = (ConfigReply_t *)reply;
481 u16 status;
482
483 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
484 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
485 status, le32_to_cpu(pReply->IOCLogInfo)));
486
487 pCfg->status = status;
488 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200489 if ((pReply->Header.PageType &
490 MPI_CONFIG_PAGETYPE_MASK) ==
491 MPI_CONFIG_PAGETYPE_EXTENDED) {
492 pCfg->cfghdr.ehdr->ExtPageLength =
493 le16_to_cpu(pReply->ExtPageLength);
494 pCfg->cfghdr.ehdr->ExtPageType =
495 pReply->ExtPageType;
496 }
497 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
498
499 /* If this is a regular header, save PageLength. */
500 /* LMP Do this better so not using a reserved field! */
501 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
502 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
503 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 }
505 }
506
507 /*
508 * Wake up the original calling thread
509 */
510 pCfg->wait_done = 1;
511 wake_up(&mpt_waitq);
512 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200513 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
514 /* we should be always getting a reply frame */
515 memcpy(ioc->persist_reply_frame, reply,
516 min(MPT_DEFAULT_FRAME_SIZE,
517 4*reply->u.reply.MsgLength));
518 del_timer(&ioc->persist_timer);
519 ioc->persist_wait_done = 1;
520 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 } else {
522 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
523 ioc->name, func);
524 }
525
526 /*
527 * Conditionally tell caller to free the original
528 * EventNotification/EventAck/unexpected request frame!
529 */
530 return freereq;
531}
532
533/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
534/**
535 * mpt_register - Register protocol-specific main callback handler.
536 * @cbfunc: callback function pointer
537 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
538 *
539 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800540 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 * protocol-specific driver must do this before it will be able to
542 * use any IOC resources, such as obtaining request frames.
543 *
544 * NOTES: The SCSI protocol driver currently calls this routine thrice
545 * in order to register separate callbacks; one for "normal" SCSI IO;
546 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
547 *
548 * Returns a positive integer valued "handle" in the
549 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
550 * Any non-positive return value (including zero!) should be considered
551 * an error by the caller.
552 */
553int
554mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
555{
556 int i;
557
558 last_drv_idx = -1;
559
560 /*
561 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
562 * (slot/handle 0 is reserved!)
563 */
564 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
565 if (MptCallbacks[i] == NULL) {
566 MptCallbacks[i] = cbfunc;
567 MptDriverClass[i] = dclass;
568 MptEvHandlers[i] = NULL;
569 last_drv_idx = i;
570 break;
571 }
572 }
573
574 return last_drv_idx;
575}
576
577/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
578/**
579 * mpt_deregister - Deregister a protocol drivers resources.
580 * @cb_idx: previously registered callback handle
581 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800582 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 * module is unloaded.
584 */
585void
586mpt_deregister(int cb_idx)
587{
588 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
589 MptCallbacks[cb_idx] = NULL;
590 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
591 MptEvHandlers[cb_idx] = NULL;
592
593 last_drv_idx++;
594 }
595}
596
597/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
598/**
599 * mpt_event_register - Register protocol-specific event callback
600 * handler.
601 * @cb_idx: previously registered (via mpt_register) callback handle
602 * @ev_cbfunc: callback function
603 *
604 * This routine can be called by one or more protocol-specific drivers
605 * if/when they choose to be notified of MPT events.
606 *
607 * Returns 0 for success.
608 */
609int
610mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
611{
612 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
613 return -1;
614
615 MptEvHandlers[cb_idx] = ev_cbfunc;
616 return 0;
617}
618
619/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
620/**
621 * mpt_event_deregister - Deregister protocol-specific event callback
622 * handler.
623 * @cb_idx: previously registered callback handle
624 *
625 * Each protocol-specific driver should call this routine
626 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800627 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 */
629void
630mpt_event_deregister(int cb_idx)
631{
632 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
633 return;
634
635 MptEvHandlers[cb_idx] = NULL;
636}
637
638/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
639/**
640 * mpt_reset_register - Register protocol-specific IOC reset handler.
641 * @cb_idx: previously registered (via mpt_register) callback handle
642 * @reset_func: reset function
643 *
644 * This routine can be called by one or more protocol-specific drivers
645 * if/when they choose to be notified of IOC resets.
646 *
647 * Returns 0 for success.
648 */
649int
650mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
651{
652 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
653 return -1;
654
655 MptResetHandlers[cb_idx] = reset_func;
656 return 0;
657}
658
659/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
660/**
661 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
662 * @cb_idx: previously registered callback handle
663 *
664 * Each protocol-specific driver should call this routine
665 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800666 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 */
668void
669mpt_reset_deregister(int cb_idx)
670{
671 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
672 return;
673
674 MptResetHandlers[cb_idx] = NULL;
675}
676
677/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
678/**
679 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800680 * @dd_cbfunc: driver callbacks struct
681 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 */
683int
684mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
685{
686 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600687 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Eric Moored58b2722006-07-11 17:23:23 -0600689 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400690 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
693
694 /* call per pci device probe entry point */
695 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600696 id = ioc->pcidev->driver ?
697 ioc->pcidev->driver->id_table : NULL;
698 if (dd_cbfunc->probe)
699 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 }
701
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400702 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703}
704
705/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
706/**
707 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800708 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 */
710void
711mpt_device_driver_deregister(int cb_idx)
712{
713 struct mpt_pci_driver *dd_cbfunc;
714 MPT_ADAPTER *ioc;
715
716 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
717 return;
718
719 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
720
721 list_for_each_entry(ioc, &ioc_list, list) {
722 if (dd_cbfunc->remove)
723 dd_cbfunc->remove(ioc->pcidev);
724 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 MptDeviceDriverHandlers[cb_idx] = NULL;
727}
728
729
730/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
731/**
732 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
733 * allocated per MPT adapter.
734 * @handle: Handle of registered MPT protocol driver
735 * @ioc: Pointer to MPT adapter structure
736 *
737 * Returns pointer to a MPT request frame or %NULL if none are available
738 * or IOC is not active.
739 */
740MPT_FRAME_HDR*
741mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
742{
743 MPT_FRAME_HDR *mf;
744 unsigned long flags;
745 u16 req_idx; /* Request index */
746
747 /* validate handle and ioc identifier */
748
749#ifdef MFCNT
750 if (!ioc->active)
751 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
752#endif
753
754 /* If interrupts are not attached, do not return a request frame */
755 if (!ioc->active)
756 return NULL;
757
758 spin_lock_irqsave(&ioc->FreeQlock, flags);
759 if (!list_empty(&ioc->FreeQ)) {
760 int req_offset;
761
762 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
763 u.frame.linkage.list);
764 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200765 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
767 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
768 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500769 req_idx = req_offset / ioc->req_sz;
770 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
772 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
773#ifdef MFCNT
774 ioc->mfcnt++;
775#endif
776 }
777 else
778 mf = NULL;
779 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
780
781#ifdef MFCNT
782 if (mf == NULL)
783 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
784 mfcounter++;
785 if (mfcounter == PRINT_MF_COUNT)
786 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
787#endif
788
789 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
790 ioc->name, handle, ioc->id, mf));
791 return mf;
792}
793
794/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
795/**
796 * mpt_put_msg_frame - Send a protocol specific MPT request frame
797 * to a IOC.
798 * @handle: Handle of registered MPT protocol driver
799 * @ioc: Pointer to MPT adapter structure
800 * @mf: Pointer to MPT request frame
801 *
802 * This routine posts a MPT request frame to the request post FIFO of a
803 * specific MPT adapter.
804 */
805void
806mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
807{
808 u32 mf_dma_addr;
809 int req_offset;
810 u16 req_idx; /* Request index */
811
812 /* ensure values are reset properly! */
813 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
814 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
815 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500816 req_idx = req_offset / ioc->req_sz;
817 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
819
820#ifdef MPT_DEBUG_MSG_FRAME
821 {
822 u32 *m = mf->u.frame.hwhdr.__hdr;
823 int ii, n;
824
825 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
826 ioc->name, m);
827 n = ioc->req_sz/4 - 1;
828 while (m[n] == 0)
829 n--;
830 for (ii=0; ii<=n; ii++) {
831 if (ii && ((ii%8)==0))
832 printk("\n" KERN_INFO " ");
833 printk(" %08x", le32_to_cpu(m[ii]));
834 }
835 printk("\n");
836 }
837#endif
838
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200839 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 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]));
841 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
842}
843
844/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
845/**
846 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
847 * @handle: Handle of registered MPT protocol driver
848 * @ioc: Pointer to MPT adapter structure
849 * @mf: Pointer to MPT request frame
850 *
851 * This routine places a MPT request frame back on the MPT adapter's
852 * FreeQ.
853 */
854void
855mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
856{
857 unsigned long flags;
858
859 /* Put Request back on FreeQ! */
860 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200861 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
863#ifdef MFCNT
864 ioc->mfcnt--;
865#endif
866 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
867}
868
869/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
870/**
871 * mpt_add_sge - Place a simple SGE at address pAddr.
872 * @pAddr: virtual address for SGE
873 * @flagslength: SGE flags and data transfer length
874 * @dma_addr: Physical address
875 *
876 * This routine places a MPT request frame back on the MPT adapter's
877 * FreeQ.
878 */
879void
880mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
881{
882 if (sizeof(dma_addr_t) == sizeof(u64)) {
883 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
884 u32 tmp = dma_addr & 0xFFFFFFFF;
885
886 pSge->FlagsLength = cpu_to_le32(flagslength);
887 pSge->Address.Low = cpu_to_le32(tmp);
888 tmp = (u32) ((u64)dma_addr >> 32);
889 pSge->Address.High = cpu_to_le32(tmp);
890
891 } else {
892 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
893 pSge->FlagsLength = cpu_to_le32(flagslength);
894 pSge->Address = cpu_to_le32(dma_addr);
895 }
896}
897
898/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
899/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800900 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 * @handle: Handle of registered MPT protocol driver
902 * @ioc: Pointer to MPT adapter structure
903 * @reqBytes: Size of the request in bytes
904 * @req: Pointer to MPT request frame
905 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
906 *
907 * This routine is used exclusively to send MptScsiTaskMgmt
908 * requests since they are required to be sent via doorbell handshake.
909 *
910 * NOTE: It is the callers responsibility to byte-swap fields in the
911 * request which are greater than 1 byte in size.
912 *
913 * Returns 0 for success, non-zero for failure.
914 */
915int
916mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
917{
918 int r = 0;
919 u8 *req_as_bytes;
920 int ii;
921
922 /* State is known to be good upon entering
923 * this function so issue the bus reset
924 * request.
925 */
926
927 /*
928 * Emulate what mpt_put_msg_frame() does /wrt to sanity
929 * setting cb_idx/req_idx. But ONLY if this request
930 * is in proper (pre-alloc'd) request buffer range...
931 */
932 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
933 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
934 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
935 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
936 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
937 }
938
939 /* Make sure there are no doorbells */
940 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200941
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 CHIPREG_WRITE32(&ioc->chip->Doorbell,
943 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
944 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
945
946 /* Wait for IOC doorbell int */
947 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
948 return ii;
949 }
950
951 /* Read doorbell and check for active bit */
952 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
953 return -5;
954
955 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200956 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
959
960 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
961 return -2;
962 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 /* Send request via doorbell handshake */
965 req_as_bytes = (u8 *) req;
966 for (ii = 0; ii < reqBytes/4; ii++) {
967 u32 word;
968
969 word = ((req_as_bytes[(ii*4) + 0] << 0) |
970 (req_as_bytes[(ii*4) + 1] << 8) |
971 (req_as_bytes[(ii*4) + 2] << 16) |
972 (req_as_bytes[(ii*4) + 3] << 24));
973 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
974 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
975 r = -3;
976 break;
977 }
978 }
979
980 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
981 r = 0;
982 else
983 r = -4;
984
985 /* Make sure there are no doorbells */
986 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 return r;
989}
990
991/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
992/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800993 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200994 * @ioc: Pointer to MPT adapter structure
995 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800996 * @sleepFlag: Specifies whether the process can sleep
997 *
998 * Provides mechanism for the host driver to control the IOC's
999 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001000 *
1001 * Access Control Value - bits[15:12]
1002 * 0h Reserved
1003 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1004 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1005 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1006 *
1007 * Returns 0 for success, non-zero for failure.
1008 */
1009
1010static int
1011mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1012{
1013 int r = 0;
1014
1015 /* return if in use */
1016 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1017 & MPI_DOORBELL_ACTIVE)
1018 return -1;
1019
1020 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1021
1022 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1023 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1024 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1025 (access_control_value<<12)));
1026
1027 /* Wait for IOC to clear Doorbell Status bit */
1028 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1029 return -2;
1030 }else
1031 return 0;
1032}
1033
1034/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1035/**
1036 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001037 * @ioc: Pointer to pointer to IOC adapter
1038 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001039 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001040 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001041 * Returns 0 for success, non-zero for failure.
1042 */
1043static int
1044mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1045{
1046 char *psge;
1047 int flags_length;
1048 u32 host_page_buffer_sz=0;
1049
1050 if(!ioc->HostPageBuffer) {
1051
1052 host_page_buffer_sz =
1053 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1054
1055 if(!host_page_buffer_sz)
1056 return 0; /* fw doesn't need any host buffers */
1057
1058 /* spin till we get enough memory */
1059 while(host_page_buffer_sz > 0) {
1060
1061 if((ioc->HostPageBuffer = pci_alloc_consistent(
1062 ioc->pcidev,
1063 host_page_buffer_sz,
1064 &ioc->HostPageBuffer_dma)) != NULL) {
1065
1066 dinitprintk((MYIOC_s_INFO_FMT
1067 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001068 ioc->name, ioc->HostPageBuffer,
1069 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001070 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001071 ioc->alloc_total += host_page_buffer_sz;
1072 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1073 break;
1074 }
1075
1076 host_page_buffer_sz -= (4*1024);
1077 }
1078 }
1079
1080 if(!ioc->HostPageBuffer) {
1081 printk(MYIOC_s_ERR_FMT
1082 "Failed to alloc memory for host_page_buffer!\n",
1083 ioc->name);
1084 return -999;
1085 }
1086
1087 psge = (char *)&ioc_init->HostPageBufferSGE;
1088 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1089 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1090 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1091 MPI_SGE_FLAGS_HOST_TO_IOC |
1092 MPI_SGE_FLAGS_END_OF_BUFFER;
1093 if (sizeof(dma_addr_t) == sizeof(u64)) {
1094 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1095 }
1096 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1097 flags_length |= ioc->HostPageBuffer_sz;
1098 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1099 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1100
1101return 0;
1102}
1103
1104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1105/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001106 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 * @iocid: IOC unique identifier (integer)
1108 * @iocpp: Pointer to pointer to IOC adapter
1109 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001110 * Given a unique IOC identifier, set pointer to the associated MPT
1111 * adapter structure.
1112 *
1113 * Returns iocid and sets iocpp if iocid is found.
1114 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 */
1116int
1117mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1118{
1119 MPT_ADAPTER *ioc;
1120
1121 list_for_each_entry(ioc,&ioc_list,list) {
1122 if (ioc->id == iocid) {
1123 *iocpp =ioc;
1124 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 *iocpp = NULL;
1129 return -1;
1130}
1131
1132/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001133/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001134 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001136 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 *
1138 * This routine performs all the steps necessary to bring the IOC of
1139 * a MPT adapter to a OPERATIONAL state. This includes registering
1140 * memory regions, registering the interrupt, and allocating request
1141 * and reply memory pools.
1142 *
1143 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1144 * MPT adapter.
1145 *
1146 * Returns 0 for success, non-zero for failure.
1147 *
1148 * TODO: Add support for polled controllers
1149 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001150int
1151mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152{
1153 MPT_ADAPTER *ioc;
1154 u8 __iomem *mem;
1155 unsigned long mem_phys;
1156 unsigned long port;
1157 u32 msize;
1158 u32 psize;
1159 int ii;
1160 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 u8 revision;
1162 u8 pcixcmd;
1163 static int mpt_ids = 0;
1164#ifdef CONFIG_PROC_FS
1165 struct proc_dir_entry *dent, *ent;
1166#endif
1167
1168 if (pci_enable_device(pdev))
1169 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001170
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001172
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001173 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 dprintk((KERN_INFO MYNAM
1175 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001176 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1178 return r;
1179 }
1180
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001181 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 dprintk((KERN_INFO MYNAM
1183 ": Using 64 bit consistent mask\n"));
1184 else
1185 dprintk((KERN_INFO MYNAM
1186 ": Not using 64 bit consistent mask\n"));
1187
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001188 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 if (ioc == NULL) {
1190 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1191 return -ENOMEM;
1192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 ioc->alloc_total = sizeof(MPT_ADAPTER);
1194 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1195 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 ioc->pcidev = pdev;
1198 ioc->diagPending = 0;
1199 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001200 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
1202 /* Initialize the event logging.
1203 */
1204 ioc->eventTypes = 0; /* None */
1205 ioc->eventContext = 0;
1206 ioc->eventLogSize = 0;
1207 ioc->events = NULL;
1208
1209#ifdef MFCNT
1210 ioc->mfcnt = 0;
1211#endif
1212
1213 ioc->cached_fw = NULL;
1214
1215 /* Initilize SCSI Config Data structure
1216 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001217 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
1219 /* Initialize the running configQ head.
1220 */
1221 INIT_LIST_HEAD(&ioc->configQ);
1222
Michael Reed05e8ec12006-01-13 14:31:54 -06001223 /* Initialize the fc rport list head.
1224 */
1225 INIT_LIST_HEAD(&ioc->fc_rports);
1226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 /* Find lookup slot. */
1228 INIT_LIST_HEAD(&ioc->list);
1229 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001230
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 mem_phys = msize = 0;
1232 port = psize = 0;
1233 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1234 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001235 if (psize)
1236 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 /* Get I/O space! */
1238 port = pci_resource_start(pdev, ii);
1239 psize = pci_resource_len(pdev,ii);
1240 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001241 if (msize)
1242 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 /* Get memmap */
1244 mem_phys = pci_resource_start(pdev, ii);
1245 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 }
1247 }
1248 ioc->mem_size = msize;
1249
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 mem = NULL;
1251 /* Get logical ptr for PciMem0 space */
1252 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001253 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 if (mem == NULL) {
1255 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1256 kfree(ioc);
1257 return -EINVAL;
1258 }
1259 ioc->memmap = mem;
1260 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1261
1262 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1263 &ioc->facts, &ioc->pfacts[0]));
1264
1265 ioc->mem_phys = mem_phys;
1266 ioc->chip = (SYSIF_REGS __iomem *)mem;
1267
1268 /* Save Port IO values in case we need to do downloadboot */
1269 {
1270 u8 *pmem = (u8*)port;
1271 ioc->pio_mem_phys = port;
1272 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1273 }
1274
1275 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1276 ioc->prod_name = "LSIFC909";
1277 ioc->bus_type = FC;
1278 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001279 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 ioc->prod_name = "LSIFC929";
1281 ioc->bus_type = FC;
1282 }
1283 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1284 ioc->prod_name = "LSIFC919";
1285 ioc->bus_type = FC;
1286 }
1287 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1288 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1289 ioc->bus_type = FC;
1290 if (revision < XL_929) {
1291 ioc->prod_name = "LSIFC929X";
1292 /* 929X Chip Fix. Set Split transactions level
1293 * for PCIX. Set MOST bits to zero.
1294 */
1295 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1296 pcixcmd &= 0x8F;
1297 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1298 } else {
1299 ioc->prod_name = "LSIFC929XL";
1300 /* 929XL Chip Fix. Set MMRBC to 0x08.
1301 */
1302 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1303 pcixcmd |= 0x08;
1304 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1305 }
1306 }
1307 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1308 ioc->prod_name = "LSIFC919X";
1309 ioc->bus_type = FC;
1310 /* 919X Chip Fix. Set Split transactions level
1311 * for PCIX. Set MOST bits to zero.
1312 */
1313 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1314 pcixcmd &= 0x8F;
1315 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1316 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001317 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1318 ioc->prod_name = "LSIFC939X";
1319 ioc->bus_type = FC;
1320 ioc->errata_flag_1064 = 1;
1321 }
1322 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1323 ioc->prod_name = "LSIFC949X";
1324 ioc->bus_type = FC;
1325 ioc->errata_flag_1064 = 1;
1326 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001327 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1328 ioc->prod_name = "LSIFC949E";
1329 ioc->bus_type = FC;
1330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1332 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001333 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 /* 1030 Chip Fix. Disable Split transactions
1335 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1336 */
1337 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1338 if (revision < C0_1030) {
1339 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1340 pcixcmd &= 0x8F;
1341 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1342 }
1343 }
1344 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1345 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001346 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001348 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1349 ioc->prod_name = "LSISAS1064";
1350 ioc->bus_type = SAS;
1351 ioc->errata_flag_1064 = 1;
1352 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001353 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1354 ioc->prod_name = "LSISAS1068";
1355 ioc->bus_type = SAS;
1356 ioc->errata_flag_1064 = 1;
1357 }
1358 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1359 ioc->prod_name = "LSISAS1064E";
1360 ioc->bus_type = SAS;
1361 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001362 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1363 ioc->prod_name = "LSISAS1068E";
1364 ioc->bus_type = SAS;
1365 }
Eric Moore87cf8982006-06-27 16:09:26 -06001366 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
1367 ioc->prod_name = "LSISAS1078";
1368 ioc->bus_type = SAS;
1369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001371 if (ioc->errata_flag_1064)
1372 pci_disable_io_access(pdev);
1373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 sprintf(ioc->name, "ioc%d", ioc->id);
1375
1376 spin_lock_init(&ioc->FreeQlock);
1377
1378 /* Disable all! */
1379 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1380 ioc->active = 0;
1381 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1382
1383 /* Set lookup ptr. */
1384 list_add_tail(&ioc->list, &ioc_list);
1385
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001386 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 */
1388 mpt_detect_bound_ports(ioc, pdev);
1389
James Bottomleyc92f2222006-03-01 09:02:49 -06001390 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1391 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 printk(KERN_WARNING MYNAM
1393 ": WARNING - %s did not initialize properly! (%d)\n",
1394 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001397 if (ioc->alt_ioc)
1398 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 iounmap(mem);
1400 kfree(ioc);
1401 pci_set_drvdata(pdev, NULL);
1402 return r;
1403 }
1404
1405 /* call per device driver probe entry point */
1406 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1407 if(MptDeviceDriverHandlers[ii] &&
1408 MptDeviceDriverHandlers[ii]->probe) {
1409 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1410 }
1411 }
1412
1413#ifdef CONFIG_PROC_FS
1414 /*
1415 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1416 */
1417 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1418 if (dent) {
1419 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1420 if (ent) {
1421 ent->read_proc = procmpt_iocinfo_read;
1422 ent->data = ioc;
1423 }
1424 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1425 if (ent) {
1426 ent->read_proc = procmpt_summary_read;
1427 ent->data = ioc;
1428 }
1429 }
1430#endif
1431
1432 return 0;
1433}
1434
1435/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001436/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001437 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 */
1440
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001441void
1442mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443{
1444 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1445 char pname[32];
1446 int ii;
1447
1448 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1449 remove_proc_entry(pname, NULL);
1450 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1451 remove_proc_entry(pname, NULL);
1452 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1453 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 /* call per device driver remove entry point */
1456 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1457 if(MptDeviceDriverHandlers[ii] &&
1458 MptDeviceDriverHandlers[ii]->remove) {
1459 MptDeviceDriverHandlers[ii]->remove(pdev);
1460 }
1461 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001462
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 /* Disable interrupts! */
1464 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1465
1466 ioc->active = 0;
1467 synchronize_irq(pdev->irq);
1468
1469 /* Clear any lingering interrupt */
1470 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1471
1472 CHIPREG_READ32(&ioc->chip->IntStatus);
1473
1474 mpt_adapter_dispose(ioc);
1475
1476 pci_set_drvdata(pdev, NULL);
1477}
1478
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479/**************************************************************************
1480 * Power Management
1481 */
1482#ifdef CONFIG_PM
1483/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001484/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001485 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001486 * @pdev: Pointer to pci_dev structure
1487 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001489int
1490mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491{
1492 u32 device_state;
1493 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
Pavel Machek2a569572005-07-07 17:56:40 -07001495 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496
1497 printk(MYIOC_s_INFO_FMT
1498 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1499 ioc->name, pdev, pci_name(pdev), device_state);
1500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 pci_save_state(pdev);
1502
1503 /* put ioc into READY_STATE */
1504 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1505 printk(MYIOC_s_ERR_FMT
1506 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1507 }
1508
1509 /* disable interrupts */
1510 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1511 ioc->active = 0;
1512
1513 /* Clear any lingering interrupt */
1514 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1515
1516 pci_disable_device(pdev);
1517 pci_set_power_state(pdev, device_state);
1518
1519 return 0;
1520}
1521
1522/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001523/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001524 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001525 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001527int
1528mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529{
1530 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1531 u32 device_state = pdev->current_state;
1532 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001533
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 printk(MYIOC_s_INFO_FMT
1535 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1536 ioc->name, pdev, pci_name(pdev), device_state);
1537
1538 pci_set_power_state(pdev, 0);
1539 pci_restore_state(pdev);
1540 pci_enable_device(pdev);
1541
1542 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001543 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 ioc->active = 1;
1545
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 printk(MYIOC_s_INFO_FMT
1547 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1548 ioc->name,
1549 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1550 CHIPREG_READ32(&ioc->chip->Doorbell));
1551
1552 /* bring ioc to operational state */
1553 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1554 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1555 printk(MYIOC_s_INFO_FMT
1556 "pci-resume: Cannot recover, error:[%x]\n",
1557 ioc->name, recovery_state);
1558 } else {
1559 printk(MYIOC_s_INFO_FMT
1560 "pci-resume: success\n", ioc->name);
1561 }
1562
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 return 0;
1564}
1565#endif
1566
James Bottomley4ff42a62006-05-17 18:06:52 -05001567static int
1568mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1569{
1570 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1571 ioc->bus_type != SPI) ||
1572 (MptDriverClass[index] == MPTFC_DRIVER &&
1573 ioc->bus_type != FC) ||
1574 (MptDriverClass[index] == MPTSAS_DRIVER &&
1575 ioc->bus_type != SAS))
1576 /* make sure we only call the relevant reset handler
1577 * for the bus */
1578 return 0;
1579 return (MptResetHandlers[index])(ioc, reset_phase);
1580}
1581
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001583/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1585 * @ioc: Pointer to MPT adapter structure
1586 * @reason: Event word / reason
1587 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1588 *
1589 * This routine performs all the steps necessary to bring the IOC
1590 * to a OPERATIONAL state.
1591 *
1592 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1593 * MPT adapter.
1594 *
1595 * Returns:
1596 * 0 for success
1597 * -1 if failed to get board READY
1598 * -2 if READY but IOCFacts Failed
1599 * -3 if READY but PrimeIOCFifos Failed
1600 * -4 if READY but IOCInit Failed
1601 */
1602static int
1603mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1604{
1605 int hard_reset_done = 0;
1606 int alt_ioc_ready = 0;
1607 int hard;
1608 int rc=0;
1609 int ii;
1610 int handlers;
1611 int ret = 0;
1612 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001613 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
1615 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1616 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1617
1618 /* Disable reply interrupts (also blocks FreeQ) */
1619 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1620 ioc->active = 0;
1621
1622 if (ioc->alt_ioc) {
1623 if (ioc->alt_ioc->active)
1624 reset_alt_ioc_active = 1;
1625
1626 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1627 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1628 ioc->alt_ioc->active = 0;
1629 }
1630
1631 hard = 1;
1632 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1633 hard = 0;
1634
1635 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1636 if (hard_reset_done == -4) {
1637 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1638 ioc->name);
1639
1640 if (reset_alt_ioc_active && ioc->alt_ioc) {
1641 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1642 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1643 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001644 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 ioc->alt_ioc->active = 1;
1646 }
1647
1648 } else {
1649 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1650 ioc->name);
1651 }
1652 return -1;
1653 }
1654
1655 /* hard_reset_done = 0 if a soft reset was performed
1656 * and 1 if a hard reset was performed.
1657 */
1658 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1659 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1660 alt_ioc_ready = 1;
1661 else
1662 printk(KERN_WARNING MYNAM
1663 ": alt-%s: Not ready WARNING!\n",
1664 ioc->alt_ioc->name);
1665 }
1666
1667 for (ii=0; ii<5; ii++) {
1668 /* Get IOC facts! Allow 5 retries */
1669 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1670 break;
1671 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
1674 if (ii == 5) {
1675 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1676 ret = -2;
1677 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1678 MptDisplayIocCapabilities(ioc);
1679 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 if (alt_ioc_ready) {
1682 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1683 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1684 /* Retry - alt IOC was initialized once
1685 */
1686 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1687 }
1688 if (rc) {
1689 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1690 alt_ioc_ready = 0;
1691 reset_alt_ioc_active = 0;
1692 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1693 MptDisplayIocCapabilities(ioc->alt_ioc);
1694 }
1695 }
1696
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001697 /*
1698 * Device is reset now. It must have de-asserted the interrupt line
1699 * (if it was asserted) and it should be safe to register for the
1700 * interrupt now.
1701 */
1702 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1703 ioc->pci_irq = -1;
1704 if (ioc->pcidev->irq) {
1705 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1706 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1707 ioc->name);
1708 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001709 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001710 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001711 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1712 "interrupt %d!\n", ioc->name,
1713 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001714 if (mpt_msi_enable)
1715 pci_disable_msi(ioc->pcidev);
1716 return -EBUSY;
1717 }
1718 irq_allocated = 1;
1719 ioc->pci_irq = ioc->pcidev->irq;
1720 pci_set_master(ioc->pcidev); /* ?? */
1721 pci_set_drvdata(ioc->pcidev, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001722 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1723 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001724 }
1725 }
1726
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 /* Prime reply & request queues!
1728 * (mucho alloc's) Must be done prior to
1729 * init as upper addresses are needed for init.
1730 * If fails, continue with alt-ioc processing
1731 */
1732 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1733 ret = -3;
1734
1735 /* May need to check/upload firmware & data here!
1736 * If fails, continue with alt-ioc processing
1737 */
1738 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1739 ret = -4;
1740// NEW!
1741 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1742 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1743 ioc->alt_ioc->name, rc);
1744 alt_ioc_ready = 0;
1745 reset_alt_ioc_active = 0;
1746 }
1747
1748 if (alt_ioc_ready) {
1749 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1750 alt_ioc_ready = 0;
1751 reset_alt_ioc_active = 0;
1752 printk(KERN_WARNING MYNAM
1753 ": alt-%s: (%d) init failure WARNING!\n",
1754 ioc->alt_ioc->name, rc);
1755 }
1756 }
1757
1758 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1759 if (ioc->upload_fw) {
1760 ddlprintk((MYIOC_s_INFO_FMT
1761 "firmware upload required!\n", ioc->name));
1762
1763 /* Controller is not operational, cannot do upload
1764 */
1765 if (ret == 0) {
1766 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001767 if (rc == 0) {
1768 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1769 /*
1770 * Maintain only one pointer to FW memory
1771 * so there will not be two attempt to
1772 * downloadboot onboard dual function
1773 * chips (mpt_adapter_disable,
1774 * mpt_diag_reset)
1775 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001776 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1777 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06001778 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001779 }
1780 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001782 ret = -5;
1783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 }
1785 }
1786 }
1787
1788 if (ret == 0) {
1789 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001790 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 ioc->active = 1;
1792 }
1793
1794 if (reset_alt_ioc_active && ioc->alt_ioc) {
1795 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001796 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001798 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 ioc->alt_ioc->active = 1;
1800 }
1801
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001802 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 * and EventAck handling.
1804 */
1805 if ((ret == 0) && (!ioc->facts.EventState))
1806 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1807
1808 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1809 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1810
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001811 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1813 * recursive scenario; GetLanConfigPages times out, timer expired
1814 * routine calls HardResetHandler, which calls into here again,
1815 * and we try GetLanConfigPages again...
1816 */
1817 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001818 if (ioc->bus_type == SAS) {
1819
1820 /* clear persistency table */
1821 if(ioc->facts.IOCExceptions &
1822 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1823 ret = mptbase_sas_persist_operation(ioc,
1824 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1825 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001826 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001827 }
1828
1829 /* Find IM volumes
1830 */
1831 mpt_findImVolumes(ioc);
1832
1833 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1835 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1836 /*
1837 * Pre-fetch the ports LAN MAC address!
1838 * (LANPage1_t stuff)
1839 */
1840 (void) GetLanConfigPages(ioc);
1841#ifdef MPT_DEBUG
1842 {
1843 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1844 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1845 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1846 }
1847#endif
1848 }
1849 } else {
1850 /* Get NVRAM and adapter maximums from SPP 0 and 2
1851 */
1852 mpt_GetScsiPortSettings(ioc, 0);
1853
1854 /* Get version and length of SDP 1
1855 */
1856 mpt_readScsiDevicePageHeaders(ioc, 0);
1857
1858 /* Find IM volumes
1859 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001860 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 mpt_findImVolumes(ioc);
1862
1863 /* Check, and possibly reset, the coalescing value
1864 */
1865 mpt_read_ioc_pg_1(ioc);
1866
1867 mpt_read_ioc_pg_4(ioc);
1868 }
1869
1870 GetIoUnitPage2(ioc);
1871 }
1872
1873 /*
1874 * Call each currently registered protocol IOC reset handler
1875 * with post-reset indication.
1876 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1877 * MptResetHandlers[] registered yet.
1878 */
1879 if (hard_reset_done) {
1880 rc = handlers = 0;
1881 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1882 if ((ret == 0) && MptResetHandlers[ii]) {
1883 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1884 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001885 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 handlers++;
1887 }
1888
1889 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001890 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001892 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 handlers++;
1894 }
1895 }
1896 /* FIXME? Examine results here? */
1897 }
1898
Eric Moore0ccdb002006-07-11 17:33:13 -06001899 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001900 if ((ret != 0) && irq_allocated) {
1901 free_irq(ioc->pci_irq, ioc);
1902 if (mpt_msi_enable)
1903 pci_disable_msi(ioc->pcidev);
1904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 return ret;
1906}
1907
1908/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001909/**
1910 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 * @ioc: Pointer to MPT adapter structure
1912 * @pdev: Pointer to (struct pci_dev) structure
1913 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001914 * Search for PCI bus/dev_function which matches
1915 * PCI bus/dev_function (+/-1) for newly discovered 929,
1916 * 929X, 1030 or 1035.
1917 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1919 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1920 */
1921static void
1922mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1923{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001924 struct pci_dev *peer=NULL;
1925 unsigned int slot = PCI_SLOT(pdev->devfn);
1926 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 MPT_ADAPTER *ioc_srch;
1928
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001929 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1930 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001931 ioc->name, pci_name(pdev), pdev->bus->number,
1932 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001933
1934 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1935 if (!peer) {
1936 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1937 if (!peer)
1938 return;
1939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
1941 list_for_each_entry(ioc_srch, &ioc_list, list) {
1942 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001943 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 /* Paranoia checks */
1945 if (ioc->alt_ioc != NULL) {
1946 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001947 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 break;
1949 } else if (ioc_srch->alt_ioc != NULL) {
1950 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001951 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 break;
1953 }
1954 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001955 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 ioc_srch->alt_ioc = ioc;
1957 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 }
1959 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001960 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961}
1962
1963/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001964/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001966 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 */
1968static void
1969mpt_adapter_disable(MPT_ADAPTER *ioc)
1970{
1971 int sz;
1972 int ret;
1973
1974 if (ioc->cached_fw != NULL) {
1975 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001976 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 printk(KERN_WARNING MYNAM
1978 ": firmware downloadboot failure (%d)!\n", ret);
1979 }
1980 }
1981
1982 /* Disable adapter interrupts! */
1983 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1984 ioc->active = 0;
1985 /* Clear any lingering interrupt */
1986 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1987
1988 if (ioc->alloc != NULL) {
1989 sz = ioc->alloc_sz;
1990 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1991 ioc->name, ioc->alloc, ioc->alloc_sz));
1992 pci_free_consistent(ioc->pcidev, sz,
1993 ioc->alloc, ioc->alloc_dma);
1994 ioc->reply_frames = NULL;
1995 ioc->req_frames = NULL;
1996 ioc->alloc = NULL;
1997 ioc->alloc_total -= sz;
1998 }
1999
2000 if (ioc->sense_buf_pool != NULL) {
2001 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2002 pci_free_consistent(ioc->pcidev, sz,
2003 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2004 ioc->sense_buf_pool = NULL;
2005 ioc->alloc_total -= sz;
2006 }
2007
2008 if (ioc->events != NULL){
2009 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2010 kfree(ioc->events);
2011 ioc->events = NULL;
2012 ioc->alloc_total -= sz;
2013 }
2014
2015 if (ioc->cached_fw != NULL) {
2016 sz = ioc->facts.FWImageSize;
2017 pci_free_consistent(ioc->pcidev, sz,
2018 ioc->cached_fw, ioc->cached_fw_dma);
2019 ioc->cached_fw = NULL;
2020 ioc->alloc_total -= sz;
2021 }
2022
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002023 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002024 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002025 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002026 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
2028 if (ioc->spi_data.pIocPg4 != NULL) {
2029 sz = ioc->spi_data.IocPg4Sz;
2030 pci_free_consistent(ioc->pcidev, sz,
2031 ioc->spi_data.pIocPg4,
2032 ioc->spi_data.IocPg4_dma);
2033 ioc->spi_data.pIocPg4 = NULL;
2034 ioc->alloc_total -= sz;
2035 }
2036
2037 if (ioc->ReqToChain != NULL) {
2038 kfree(ioc->ReqToChain);
2039 kfree(ioc->RequestNB);
2040 ioc->ReqToChain = NULL;
2041 }
2042
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002043 kfree(ioc->ChainToChain);
2044 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002045
2046 if (ioc->HostPageBuffer != NULL) {
2047 if((ret = mpt_host_page_access_control(ioc,
2048 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2049 printk(KERN_ERR MYNAM
2050 ": %s: host page buffers free failed (%d)!\n",
2051 __FUNCTION__, ret);
2052 }
2053 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2054 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2055 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2056 ioc->HostPageBuffer,
2057 ioc->HostPageBuffer_dma);
2058 ioc->HostPageBuffer = NULL;
2059 ioc->HostPageBuffer_sz = 0;
2060 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062}
2063
2064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002065/**
2066 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 * @ioc: Pointer to MPT adapter structure
2068 *
2069 * This routine unregisters h/w resources and frees all alloc'd memory
2070 * associated with a MPT adapter structure.
2071 */
2072static void
2073mpt_adapter_dispose(MPT_ADAPTER *ioc)
2074{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002075 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002077 if (ioc == NULL)
2078 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002080 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002082 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002084 if (ioc->pci_irq != -1) {
2085 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002086 if (mpt_msi_enable)
2087 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002088 ioc->pci_irq = -1;
2089 }
2090
2091 if (ioc->memmap != NULL) {
2092 iounmap(ioc->memmap);
2093 ioc->memmap = NULL;
2094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
2096#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002097 if (ioc->mtrr_reg > 0) {
2098 mtrr_del(ioc->mtrr_reg, 0, 0);
2099 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101#endif
2102
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002103 /* Zap the adapter lookup ptr! */
2104 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002106 sz_last = ioc->alloc_total;
2107 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2108 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002109
2110 if (ioc->alt_ioc)
2111 ioc->alt_ioc->alt_ioc = NULL;
2112
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002113 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114}
2115
2116/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002117/**
2118 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 * @ioc: Pointer to MPT adapter structure
2120 */
2121static void
2122MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2123{
2124 int i = 0;
2125
2126 printk(KERN_INFO "%s: ", ioc->name);
2127 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2128 printk("%s: ", ioc->prod_name+3);
2129 printk("Capabilities={");
2130
2131 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2132 printk("Initiator");
2133 i++;
2134 }
2135
2136 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2137 printk("%sTarget", i ? "," : "");
2138 i++;
2139 }
2140
2141 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2142 printk("%sLAN", i ? "," : "");
2143 i++;
2144 }
2145
2146#if 0
2147 /*
2148 * This would probably evoke more questions than it's worth
2149 */
2150 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2151 printk("%sLogBusAddr", i ? "," : "");
2152 i++;
2153 }
2154#endif
2155
2156 printk("}\n");
2157}
2158
2159/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002160/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2162 * @ioc: Pointer to MPT_ADAPTER structure
2163 * @force: Force hard KickStart of IOC
2164 * @sleepFlag: Specifies whether the process can sleep
2165 *
2166 * Returns:
2167 * 1 - DIAG reset and READY
2168 * 0 - READY initially OR soft reset and READY
2169 * -1 - Any failure on KickStart
2170 * -2 - Msg Unit Reset Failed
2171 * -3 - IO Unit Reset Failed
2172 * -4 - IOC owned by a PEER
2173 */
2174static int
2175MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2176{
2177 u32 ioc_state;
2178 int statefault = 0;
2179 int cntdn;
2180 int hard_reset_done = 0;
2181 int r;
2182 int ii;
2183 int whoinit;
2184
2185 /* Get current [raw] IOC state */
2186 ioc_state = mpt_GetIocState(ioc, 0);
2187 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2188
2189 /*
2190 * Check to see if IOC got left/stuck in doorbell handshake
2191 * grip of death. If so, hard reset the IOC.
2192 */
2193 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2194 statefault = 1;
2195 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2196 ioc->name);
2197 }
2198
2199 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002200 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 return 0;
2202
2203 /*
2204 * Check to see if IOC is in FAULT state.
2205 */
2206 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2207 statefault = 2;
2208 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2209 ioc->name);
2210 printk(KERN_WARNING " FAULT code = %04xh\n",
2211 ioc_state & MPI_DOORBELL_DATA_MASK);
2212 }
2213
2214 /*
2215 * Hmmm... Did it get left operational?
2216 */
2217 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002218 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 ioc->name));
2220
2221 /* Check WhoInit.
2222 * If PCI Peer, exit.
2223 * Else, if no fault conditions are present, issue a MessageUnitReset
2224 * Else, fall through to KickStart case
2225 */
2226 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002227 dinitprintk((KERN_INFO MYNAM
2228 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 whoinit, statefault, force));
2230 if (whoinit == MPI_WHOINIT_PCI_PEER)
2231 return -4;
2232 else {
2233 if ((statefault == 0 ) && (force == 0)) {
2234 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2235 return 0;
2236 }
2237 statefault = 3;
2238 }
2239 }
2240
2241 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2242 if (hard_reset_done < 0)
2243 return -1;
2244
2245 /*
2246 * Loop here waiting for IOC to come READY.
2247 */
2248 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002249 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
2251 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2252 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2253 /*
2254 * BIOS or previous driver load left IOC in OP state.
2255 * Reset messaging FIFOs.
2256 */
2257 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2258 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2259 return -2;
2260 }
2261 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2262 /*
2263 * Something is wrong. Try to get IOC back
2264 * to a known state.
2265 */
2266 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2267 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2268 return -3;
2269 }
2270 }
2271
2272 ii++; cntdn--;
2273 if (!cntdn) {
2274 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2275 ioc->name, (int)((ii+5)/HZ));
2276 return -ETIME;
2277 }
2278
2279 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002280 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 } else {
2282 mdelay (1); /* 1 msec delay */
2283 }
2284
2285 }
2286
2287 if (statefault < 3) {
2288 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2289 ioc->name,
2290 statefault==1 ? "stuck handshake" : "IOC FAULT");
2291 }
2292
2293 return hard_reset_done;
2294}
2295
2296/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002297/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 * mpt_GetIocState - Get the current state of a MPT adapter.
2299 * @ioc: Pointer to MPT_ADAPTER structure
2300 * @cooked: Request raw or cooked IOC state
2301 *
2302 * Returns all IOC Doorbell register bits if cooked==0, else just the
2303 * Doorbell bits in MPI_IOC_STATE_MASK.
2304 */
2305u32
2306mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2307{
2308 u32 s, sc;
2309
2310 /* Get! */
2311 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2312// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2313 sc = s & MPI_IOC_STATE_MASK;
2314
2315 /* Save! */
2316 ioc->last_state = sc;
2317
2318 return cooked ? sc : s;
2319}
2320
2321/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002322/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 * GetIocFacts - Send IOCFacts request to MPT adapter.
2324 * @ioc: Pointer to MPT_ADAPTER structure
2325 * @sleepFlag: Specifies whether the process can sleep
2326 * @reason: If recovery, only update facts.
2327 *
2328 * Returns 0 for success, non-zero for failure.
2329 */
2330static int
2331GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2332{
2333 IOCFacts_t get_facts;
2334 IOCFactsReply_t *facts;
2335 int r;
2336 int req_sz;
2337 int reply_sz;
2338 int sz;
2339 u32 status, vv;
2340 u8 shiftFactor=1;
2341
2342 /* IOC *must* NOT be in RESET state! */
2343 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2344 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2345 ioc->name,
2346 ioc->last_state );
2347 return -44;
2348 }
2349
2350 facts = &ioc->facts;
2351
2352 /* Destination (reply area)... */
2353 reply_sz = sizeof(*facts);
2354 memset(facts, 0, reply_sz);
2355
2356 /* Request area (get_facts on the stack right now!) */
2357 req_sz = sizeof(get_facts);
2358 memset(&get_facts, 0, req_sz);
2359
2360 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2361 /* Assert: All other get_facts fields are zero! */
2362
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002363 dinitprintk((MYIOC_s_INFO_FMT
2364 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 ioc->name, req_sz, reply_sz));
2366
2367 /* No non-zero fields in the get_facts request are greater than
2368 * 1 byte in size, so we can just fire it off as is.
2369 */
2370 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2371 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2372 if (r != 0)
2373 return r;
2374
2375 /*
2376 * Now byte swap (GRRR) the necessary fields before any further
2377 * inspection of reply contents.
2378 *
2379 * But need to do some sanity checks on MsgLength (byte) field
2380 * to make sure we don't zero IOC's req_sz!
2381 */
2382 /* Did we get a valid reply? */
2383 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2384 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2385 /*
2386 * If not been here, done that, save off first WhoInit value
2387 */
2388 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2389 ioc->FirstWhoInit = facts->WhoInit;
2390 }
2391
2392 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2393 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2394 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2395 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2396 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002397 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 /* CHECKME! IOCStatus, IOCLogInfo */
2399
2400 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2401 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2402
2403 /*
2404 * FC f/w version changed between 1.1 and 1.2
2405 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2406 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2407 */
2408 if (facts->MsgVersion < 0x0102) {
2409 /*
2410 * Handle old FC f/w style, convert to new...
2411 */
2412 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2413 facts->FWVersion.Word =
2414 ((oldv<<12) & 0xFF000000) |
2415 ((oldv<<8) & 0x000FFF00);
2416 } else
2417 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2418
2419 facts->ProductID = le16_to_cpu(facts->ProductID);
2420 facts->CurrentHostMfaHighAddr =
2421 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2422 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2423 facts->CurrentSenseBufferHighAddr =
2424 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2425 facts->CurReplyFrameSize =
2426 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002427 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
2429 /*
2430 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2431 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2432 * to 14 in MPI-1.01.0x.
2433 */
2434 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2435 facts->MsgVersion > 0x0100) {
2436 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2437 }
2438
2439 sz = facts->FWImageSize;
2440 if ( sz & 0x01 )
2441 sz += 1;
2442 if ( sz & 0x02 )
2443 sz += 2;
2444 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002445
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 if (!facts->RequestFrameSize) {
2447 /* Something is wrong! */
2448 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2449 ioc->name);
2450 return -55;
2451 }
2452
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002453 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 vv = ((63 / (sz * 4)) + 1) & 0x03;
2455 ioc->NB_for_64_byte_frame = vv;
2456 while ( sz )
2457 {
2458 shiftFactor++;
2459 sz = sz >> 1;
2460 }
2461 ioc->NBShiftFactor = shiftFactor;
2462 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2463 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002464
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2466 /*
2467 * Set values for this IOC's request & reply frame sizes,
2468 * and request & reply queue depths...
2469 */
2470 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2471 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2472 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2473 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2474
2475 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2476 ioc->name, ioc->reply_sz, ioc->reply_depth));
2477 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2478 ioc->name, ioc->req_sz, ioc->req_depth));
2479
2480 /* Get port facts! */
2481 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2482 return r;
2483 }
2484 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002485 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2487 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2488 RequestFrameSize)/sizeof(u32)));
2489 return -66;
2490 }
2491
2492 return 0;
2493}
2494
2495/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002496/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 * GetPortFacts - Send PortFacts request to MPT adapter.
2498 * @ioc: Pointer to MPT_ADAPTER structure
2499 * @portnum: Port number
2500 * @sleepFlag: Specifies whether the process can sleep
2501 *
2502 * Returns 0 for success, non-zero for failure.
2503 */
2504static int
2505GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2506{
2507 PortFacts_t get_pfacts;
2508 PortFactsReply_t *pfacts;
2509 int ii;
2510 int req_sz;
2511 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002512 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
2514 /* IOC *must* NOT be in RESET state! */
2515 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2516 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2517 ioc->name,
2518 ioc->last_state );
2519 return -4;
2520 }
2521
2522 pfacts = &ioc->pfacts[portnum];
2523
2524 /* Destination (reply area)... */
2525 reply_sz = sizeof(*pfacts);
2526 memset(pfacts, 0, reply_sz);
2527
2528 /* Request area (get_pfacts on the stack right now!) */
2529 req_sz = sizeof(get_pfacts);
2530 memset(&get_pfacts, 0, req_sz);
2531
2532 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2533 get_pfacts.PortNumber = portnum;
2534 /* Assert: All other get_pfacts fields are zero! */
2535
2536 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2537 ioc->name, portnum));
2538
2539 /* No non-zero fields in the get_pfacts request are greater than
2540 * 1 byte in size, so we can just fire it off as is.
2541 */
2542 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2543 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2544 if (ii != 0)
2545 return ii;
2546
2547 /* Did we get a valid reply? */
2548
2549 /* Now byte swap the necessary fields in the response. */
2550 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2551 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2552 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2553 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2554 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2555 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2556 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2557 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2558 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2559
Eric Moore793955f2007-01-29 09:42:20 -07002560 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2561 pfacts->MaxDevices;
2562 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2563 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2564
2565 /*
2566 * Place all the devices on channels
2567 *
2568 * (for debuging)
2569 */
2570 if (mpt_channel_mapping) {
2571 ioc->devices_per_bus = 1;
2572 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2573 }
2574
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 return 0;
2576}
2577
2578/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002579/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 * SendIocInit - Send IOCInit request to MPT adapter.
2581 * @ioc: Pointer to MPT_ADAPTER structure
2582 * @sleepFlag: Specifies whether the process can sleep
2583 *
2584 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2585 *
2586 * Returns 0 for success, non-zero for failure.
2587 */
2588static int
2589SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2590{
2591 IOCInit_t ioc_init;
2592 MPIDefaultReply_t init_reply;
2593 u32 state;
2594 int r;
2595 int count;
2596 int cntdn;
2597
2598 memset(&ioc_init, 0, sizeof(ioc_init));
2599 memset(&init_reply, 0, sizeof(init_reply));
2600
2601 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2602 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2603
2604 /* If we are in a recovery mode and we uploaded the FW image,
2605 * then this pointer is not NULL. Skip the upload a second time.
2606 * Set this flag if cached_fw set for either IOC.
2607 */
2608 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2609 ioc->upload_fw = 1;
2610 else
2611 ioc->upload_fw = 0;
2612 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2613 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2614
Eric Moore793955f2007-01-29 09:42:20 -07002615 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2616 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002617 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2618 ioc->name, ioc->facts.MsgVersion));
2619 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2620 // set MsgVersion and HeaderVersion host driver was built with
2621 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2622 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002624 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2625 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2626 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2627 return -99;
2628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2630
2631 if (sizeof(dma_addr_t) == sizeof(u64)) {
2632 /* Save the upper 32-bits of the request
2633 * (reply) and sense buffers.
2634 */
2635 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2636 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2637 } else {
2638 /* Force 32-bit addressing */
2639 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2640 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2641 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2644 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002645 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2646 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647
2648 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2649 ioc->name, &ioc_init));
2650
2651 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2652 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002653 if (r != 0) {
2654 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
2658 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002659 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 */
2661
2662 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2663 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002664
2665 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2666 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
2670 /* YIKES! SUPER IMPORTANT!!!
2671 * Poll IocState until _OPERATIONAL while IOC is doing
2672 * LoopInit and TargetDiscovery!
2673 */
2674 count = 0;
2675 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2676 state = mpt_GetIocState(ioc, 1);
2677 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2678 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002679 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 } else {
2681 mdelay(1);
2682 }
2683
2684 if (!cntdn) {
2685 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2686 ioc->name, (int)((count+5)/HZ));
2687 return -9;
2688 }
2689
2690 state = mpt_GetIocState(ioc, 1);
2691 count++;
2692 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002693 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 ioc->name, count));
2695
Eric Mooreba856d32006-07-11 17:34:01 -06002696 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 return r;
2698}
2699
2700/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002701/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 * SendPortEnable - Send PortEnable request to MPT adapter port.
2703 * @ioc: Pointer to MPT_ADAPTER structure
2704 * @portnum: Port number to enable
2705 * @sleepFlag: Specifies whether the process can sleep
2706 *
2707 * Send PortEnable to bring IOC to OPERATIONAL state.
2708 *
2709 * Returns 0 for success, non-zero for failure.
2710 */
2711static int
2712SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2713{
2714 PortEnable_t port_enable;
2715 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002716 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 int req_sz;
2718 int reply_sz;
2719
2720 /* Destination... */
2721 reply_sz = sizeof(MPIDefaultReply_t);
2722 memset(&reply_buf, 0, reply_sz);
2723
2724 req_sz = sizeof(PortEnable_t);
2725 memset(&port_enable, 0, req_sz);
2726
2727 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2728 port_enable.PortNumber = portnum;
2729/* port_enable.ChainOffset = 0; */
2730/* port_enable.MsgFlags = 0; */
2731/* port_enable.MsgContext = 0; */
2732
2733 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2734 ioc->name, portnum, &port_enable));
2735
2736 /* RAID FW may take a long time to enable
2737 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002738 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2739 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2740 (ioc->bus_type == SAS)) {
2741 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2742 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2743 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002744 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002745 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2746 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2747 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002749 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750}
2751
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002752/**
2753 * mpt_alloc_fw_memory - allocate firmware memory
2754 * @ioc: Pointer to MPT_ADAPTER structure
2755 * @size: total FW bytes
2756 *
2757 * If memory has already been allocated, the same (cached) value
2758 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 */
2760void
2761mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2762{
2763 if (ioc->cached_fw)
2764 return; /* use already allocated memory */
2765 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2766 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2767 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06002768 ioc->alloc_total += size;
2769 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 } else {
2771 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2772 ioc->alloc_total += size;
2773 }
2774}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002775/**
2776 * mpt_free_fw_memory - free firmware memory
2777 * @ioc: Pointer to MPT_ADAPTER structure
2778 *
2779 * If alt_img is NULL, delete from ioc structure.
2780 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 */
2782void
2783mpt_free_fw_memory(MPT_ADAPTER *ioc)
2784{
2785 int sz;
2786
2787 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002788 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2790 pci_free_consistent(ioc->pcidev, sz,
2791 ioc->cached_fw, ioc->cached_fw_dma);
2792 ioc->cached_fw = NULL;
2793
2794 return;
2795}
2796
2797
2798/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002799/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2801 * @ioc: Pointer to MPT_ADAPTER structure
2802 * @sleepFlag: Specifies whether the process can sleep
2803 *
2804 * Returns 0 for success, >0 for handshake failure
2805 * <0 for fw upload failure.
2806 *
2807 * Remark: If bound IOC and a successful FWUpload was performed
2808 * on the bound IOC, the second image is discarded
2809 * and memory is free'd. Both channels must upload to prevent
2810 * IOC from running in degraded mode.
2811 */
2812static int
2813mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2814{
2815 u8 request[ioc->req_sz];
2816 u8 reply[sizeof(FWUploadReply_t)];
2817 FWUpload_t *prequest;
2818 FWUploadReply_t *preply;
2819 FWUploadTCSGE_t *ptcsge;
2820 int sgeoffset;
2821 u32 flagsLength;
2822 int ii, sz, reply_sz;
2823 int cmdStatus;
2824
2825 /* If the image size is 0, we are done.
2826 */
2827 if ((sz = ioc->facts.FWImageSize) == 0)
2828 return 0;
2829
2830 mpt_alloc_fw_memory(ioc, sz);
2831
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002832 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002834
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 if (ioc->cached_fw == NULL) {
2836 /* Major Failure.
2837 */
2838 return -ENOMEM;
2839 }
2840
2841 prequest = (FWUpload_t *)&request;
2842 preply = (FWUploadReply_t *)&reply;
2843
2844 /* Destination... */
2845 memset(prequest, 0, ioc->req_sz);
2846
2847 reply_sz = sizeof(reply);
2848 memset(preply, 0, reply_sz);
2849
2850 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2851 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2852
2853 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2854 ptcsge->DetailsLength = 12;
2855 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2856 ptcsge->ImageSize = cpu_to_le32(sz);
2857
2858 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2859
2860 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2861 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2862
2863 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002864 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 prequest, sgeoffset));
2866 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2867
2868 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2869 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2870
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002871 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872
2873 cmdStatus = -EFAULT;
2874 if (ii == 0) {
2875 /* Handshake transfer was complete and successful.
2876 * Check the Reply Frame.
2877 */
2878 int status, transfer_sz;
2879 status = le16_to_cpu(preply->IOCStatus);
2880 if (status == MPI_IOCSTATUS_SUCCESS) {
2881 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2882 if (transfer_sz == sz)
2883 cmdStatus = 0;
2884 }
2885 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002886 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 ioc->name, cmdStatus));
2888
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002889
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 if (cmdStatus) {
2891
2892 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2893 ioc->name));
2894 mpt_free_fw_memory(ioc);
2895 }
2896
2897 return cmdStatus;
2898}
2899
2900/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002901/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 * mpt_downloadboot - DownloadBoot code
2903 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002904 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 * @sleepFlag: Specifies whether the process can sleep
2906 *
2907 * FwDownloadBoot requires Programmed IO access.
2908 *
2909 * Returns 0 for success
2910 * -1 FW Image size is 0
2911 * -2 No valid cached_fw Pointer
2912 * <0 for fw upload failure.
2913 */
2914static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002915mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 MpiExtImageHeader_t *pExtImage;
2918 u32 fwSize;
2919 u32 diag0val;
2920 int count;
2921 u32 *ptrFw;
2922 u32 diagRwData;
2923 u32 nextImage;
2924 u32 load_addr;
2925 u32 ioc_state=0;
2926
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002927 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2928 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002929
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2931 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2932 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2933 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2934 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2935 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2936
2937 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2938
2939 /* wait 1 msec */
2940 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002941 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 } else {
2943 mdelay (1);
2944 }
2945
2946 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2947 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2948
2949 for (count = 0; count < 30; count ++) {
2950 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2951 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2952 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2953 ioc->name, count));
2954 break;
2955 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002956 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002958 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002960 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 }
2962 }
2963
2964 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002965 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2966 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 ioc->name, diag0val));
2968 return -3;
2969 }
2970
2971 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2972 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2973 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2974 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2975 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2976 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2977
2978 /* Set the DiagRwEn and Disable ARM bits */
2979 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2980
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 fwSize = (pFwHeader->ImageSize + 3)/4;
2982 ptrFw = (u32 *) pFwHeader;
2983
2984 /* Write the LoadStartAddress to the DiagRw Address Register
2985 * using Programmed IO
2986 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002987 if (ioc->errata_flag_1064)
2988 pci_enable_io_access(ioc->pcidev);
2989
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2991 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2992 ioc->name, pFwHeader->LoadStartAddress));
2993
2994 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2995 ioc->name, fwSize*4, ptrFw));
2996 while (fwSize--) {
2997 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2998 }
2999
3000 nextImage = pFwHeader->NextImageHeaderOffset;
3001 while (nextImage) {
3002 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3003
3004 load_addr = pExtImage->LoadStartAddress;
3005
3006 fwSize = (pExtImage->ImageSize + 3) >> 2;
3007 ptrFw = (u32 *)pExtImage;
3008
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003009 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
3010 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3012
3013 while (fwSize--) {
3014 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3015 }
3016 nextImage = pExtImage->NextImageHeaderOffset;
3017 }
3018
3019 /* Write the IopResetVectorRegAddr */
3020 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3021 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3022
3023 /* Write the IopResetVectorValue */
3024 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3025 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3026
3027 /* Clear the internal flash bad bit - autoincrementing register,
3028 * so must do two writes.
3029 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003030 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003031 /*
3032 * 1030 and 1035 H/W errata, workaround to access
3033 * the ClearFlashBadSignatureBit
3034 */
3035 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3036 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3037 diagRwData |= 0x40000000;
3038 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3039 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3040
3041 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3042 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3043 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3044 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3045
3046 /* wait 1 msec */
3047 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003048 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003049 } else {
3050 mdelay (1);
3051 }
3052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003054 if (ioc->errata_flag_1064)
3055 pci_disable_io_access(ioc->pcidev);
3056
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003058 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3059 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003061 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3063 ioc->name, diag0val));
3064 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3065
3066 /* Write 0xFF to reset the sequencer */
3067 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3068
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003069 if (ioc->bus_type == SAS) {
3070 ioc_state = mpt_GetIocState(ioc, 0);
3071 if ( (GetIocFacts(ioc, sleepFlag,
3072 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3073 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3074 ioc->name, ioc_state));
3075 return -EFAULT;
3076 }
3077 }
3078
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 for (count=0; count<HZ*20; count++) {
3080 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3081 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3082 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003083 if (ioc->bus_type == SAS) {
3084 return 0;
3085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3087 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3088 ioc->name));
3089 return -EFAULT;
3090 }
3091 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3092 ioc->name));
3093 return 0;
3094 }
3095 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003096 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 } else {
3098 mdelay (10);
3099 }
3100 }
3101 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3102 ioc->name, ioc_state));
3103 return -EFAULT;
3104}
3105
3106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003107/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 * KickStart - Perform hard reset of MPT adapter.
3109 * @ioc: Pointer to MPT_ADAPTER structure
3110 * @force: Force hard reset
3111 * @sleepFlag: Specifies whether the process can sleep
3112 *
3113 * This routine places MPT adapter in diagnostic mode via the
3114 * WriteSequence register, and then performs a hard reset of adapter
3115 * via the Diagnostic register.
3116 *
3117 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3118 * or NO_SLEEP (interrupt thread, use mdelay)
3119 * force - 1 if doorbell active, board fault state
3120 * board operational, IOC_RECOVERY or
3121 * IOC_BRINGUP and there is an alt_ioc.
3122 * 0 else
3123 *
3124 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003125 * 1 - hard reset, READY
3126 * 0 - no reset due to History bit, READY
3127 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 * OR reset but failed to come READY
3129 * -2 - no reset, could not enter DIAG mode
3130 * -3 - reset but bad FW bit
3131 */
3132static int
3133KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3134{
3135 int hard_reset_done = 0;
3136 u32 ioc_state=0;
3137 int cnt,cntdn;
3138
3139 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003140 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 /* Always issue a Msg Unit Reset first. This will clear some
3142 * SCSI bus hang conditions.
3143 */
3144 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3145
3146 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003147 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 } else {
3149 mdelay (1000);
3150 }
3151 }
3152
3153 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3154 if (hard_reset_done < 0)
3155 return hard_reset_done;
3156
3157 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3158 ioc->name));
3159
3160 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3161 for (cnt=0; cnt<cntdn; cnt++) {
3162 ioc_state = mpt_GetIocState(ioc, 1);
3163 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3164 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3165 ioc->name, cnt));
3166 return hard_reset_done;
3167 }
3168 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003169 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 } else {
3171 mdelay (10);
3172 }
3173 }
3174
3175 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3176 ioc->name, ioc_state);
3177 return -1;
3178}
3179
3180/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003181/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 * mpt_diag_reset - Perform hard reset of the adapter.
3183 * @ioc: Pointer to MPT_ADAPTER structure
3184 * @ignore: Set if to honor and clear to ignore
3185 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003186 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 * else set to NO_SLEEP (use mdelay instead)
3188 *
3189 * This routine places the adapter in diagnostic mode via the
3190 * WriteSequence register and then performs a hard reset of adapter
3191 * via the Diagnostic register. Adapter should be in ready state
3192 * upon successful completion.
3193 *
3194 * Returns: 1 hard reset successful
3195 * 0 no reset performed because reset history bit set
3196 * -2 enabling diagnostic mode failed
3197 * -3 diagnostic reset failed
3198 */
3199static int
3200mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3201{
Eric Moore0ccdb002006-07-11 17:33:13 -06003202 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 u32 diag0val;
3204 u32 doorbell;
3205 int hard_reset_done = 0;
3206 int count = 0;
3207#ifdef MPT_DEBUG
3208 u32 diag1val = 0;
3209#endif
3210
Eric Moore87cf8982006-06-27 16:09:26 -06003211 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
3212 drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
3213 "address=%p\n", ioc->name, __FUNCTION__,
3214 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3215 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3216 if (sleepFlag == CAN_SLEEP)
3217 msleep(1);
3218 else
3219 mdelay(1);
3220
3221 for (count = 0; count < 60; count ++) {
3222 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3223 doorbell &= MPI_IOC_STATE_MASK;
3224
3225 drsprintk((MYIOC_s_INFO_FMT
3226 "looking for READY STATE: doorbell=%x"
3227 " count=%d\n",
3228 ioc->name, doorbell, count));
3229 if (doorbell == MPI_IOC_STATE_READY) {
3230 return 0;
3231 }
3232
3233 /* wait 1 sec */
3234 if (sleepFlag == CAN_SLEEP)
3235 msleep(1000);
3236 else
3237 mdelay(1000);
3238 }
3239 return -1;
3240 }
3241
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 /* Clear any existing interrupts */
3243 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3244
3245 /* Use "Diagnostic reset" method! (only thing available!) */
3246 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3247
3248#ifdef MPT_DEBUG
3249 if (ioc->alt_ioc)
3250 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3251 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3252 ioc->name, diag0val, diag1val));
3253#endif
3254
3255 /* Do the reset if we are told to ignore the reset history
3256 * or if the reset history is 0
3257 */
3258 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3259 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3260 /* Write magic sequence to WriteSequence register
3261 * Loop until in diagnostic mode
3262 */
3263 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3264 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3265 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3266 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3267 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3268 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3269
3270 /* wait 100 msec */
3271 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003272 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 } else {
3274 mdelay (100);
3275 }
3276
3277 count++;
3278 if (count > 20) {
3279 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3280 ioc->name, diag0val);
3281 return -2;
3282
3283 }
3284
3285 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3286
3287 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3288 ioc->name, diag0val));
3289 }
3290
3291#ifdef MPT_DEBUG
3292 if (ioc->alt_ioc)
3293 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3294 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3295 ioc->name, diag0val, diag1val));
3296#endif
3297 /*
3298 * Disable the ARM (Bug fix)
3299 *
3300 */
3301 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003302 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303
3304 /*
3305 * Now hit the reset bit in the Diagnostic register
3306 * (THE BIG HAMMER!) (Clears DRWE bit).
3307 */
3308 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3309 hard_reset_done = 1;
3310 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3311 ioc->name));
3312
3313 /*
3314 * Call each currently registered protocol IOC reset handler
3315 * with pre-reset indication.
3316 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3317 * MptResetHandlers[] registered yet.
3318 */
3319 {
3320 int ii;
3321 int r = 0;
3322
3323 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3324 if (MptResetHandlers[ii]) {
3325 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3326 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003327 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 if (ioc->alt_ioc) {
3329 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3330 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003331 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 }
3333 }
3334 }
3335 /* FIXME? Examine results here? */
3336 }
3337
Eric Moore0ccdb002006-07-11 17:33:13 -06003338 if (ioc->cached_fw)
3339 iocp = ioc;
3340 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3341 iocp = ioc->alt_ioc;
3342 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 /* If the DownloadBoot operation fails, the
3344 * IOC will be left unusable. This is a fatal error
3345 * case. _diag_reset will return < 0
3346 */
3347 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003348 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3350 break;
3351 }
3352
Eric Moore0ccdb002006-07-11 17:33:13 -06003353 dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n",
3354 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 /* wait 1 sec */
3356 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003357 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 } else {
3359 mdelay (1000);
3360 }
3361 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003362 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003363 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 printk(KERN_WARNING MYNAM
3365 ": firmware downloadboot failure (%d)!\n", count);
3366 }
3367
3368 } else {
3369 /* Wait for FW to reload and for board
3370 * to go to the READY state.
3371 * Maximum wait is 60 seconds.
3372 * If fail, no error will check again
3373 * with calling program.
3374 */
3375 for (count = 0; count < 60; count ++) {
3376 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3377 doorbell &= MPI_IOC_STATE_MASK;
3378
3379 if (doorbell == MPI_IOC_STATE_READY) {
3380 break;
3381 }
3382
3383 /* wait 1 sec */
3384 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003385 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 } else {
3387 mdelay (1000);
3388 }
3389 }
3390 }
3391 }
3392
3393 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3394#ifdef MPT_DEBUG
3395 if (ioc->alt_ioc)
3396 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3397 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3398 ioc->name, diag0val, diag1val));
3399#endif
3400
3401 /* Clear RESET_HISTORY bit! Place board in the
3402 * diagnostic mode to update the diag register.
3403 */
3404 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3405 count = 0;
3406 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3407 /* Write magic sequence to WriteSequence register
3408 * Loop until in diagnostic mode
3409 */
3410 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3411 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3412 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3413 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3414 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3415 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3416
3417 /* wait 100 msec */
3418 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003419 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 } else {
3421 mdelay (100);
3422 }
3423
3424 count++;
3425 if (count > 20) {
3426 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3427 ioc->name, diag0val);
3428 break;
3429 }
3430 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3431 }
3432 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3433 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3434 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3435 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3436 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3437 ioc->name);
3438 }
3439
3440 /* Disable Diagnostic Mode
3441 */
3442 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3443
3444 /* Check FW reload status flags.
3445 */
3446 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3447 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3448 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3449 ioc->name, diag0val);
3450 return -3;
3451 }
3452
3453#ifdef MPT_DEBUG
3454 if (ioc->alt_ioc)
3455 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3456 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3457 ioc->name, diag0val, diag1val));
3458#endif
3459
3460 /*
3461 * Reset flag that says we've enabled event notification
3462 */
3463 ioc->facts.EventState = 0;
3464
3465 if (ioc->alt_ioc)
3466 ioc->alt_ioc->facts.EventState = 0;
3467
3468 return hard_reset_done;
3469}
3470
3471/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003472/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 * SendIocReset - Send IOCReset request to MPT adapter.
3474 * @ioc: Pointer to MPT_ADAPTER structure
3475 * @reset_type: reset type, expected values are
3476 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003477 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 *
3479 * Send IOCReset request to the MPT adapter.
3480 *
3481 * Returns 0 for success, non-zero for failure.
3482 */
3483static int
3484SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3485{
3486 int r;
3487 u32 state;
3488 int cntdn, count;
3489
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003490 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 ioc->name, reset_type));
3492 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3493 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3494 return r;
3495
3496 /* FW ACK'd request, wait for READY state
3497 */
3498 count = 0;
3499 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3500
3501 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3502 cntdn--;
3503 count++;
3504 if (!cntdn) {
3505 if (sleepFlag != CAN_SLEEP)
3506 count *= 10;
3507
3508 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3509 ioc->name, (int)((count+5)/HZ));
3510 return -ETIME;
3511 }
3512
3513 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003514 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 } else {
3516 mdelay (1); /* 1 msec delay */
3517 }
3518 }
3519
3520 /* TODO!
3521 * Cleanup all event stuff for this IOC; re-issue EventNotification
3522 * request if needed.
3523 */
3524 if (ioc->facts.Function)
3525 ioc->facts.EventState = 0;
3526
3527 return 0;
3528}
3529
3530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003531/**
3532 * initChainBuffers - Allocate memory for and initialize chain buffers
3533 * @ioc: Pointer to MPT_ADAPTER structure
3534 *
3535 * Allocates memory for and initializes chain buffers,
3536 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 */
3538static int
3539initChainBuffers(MPT_ADAPTER *ioc)
3540{
3541 u8 *mem;
3542 int sz, ii, num_chain;
3543 int scale, num_sge, numSGE;
3544
3545 /* ReqToChain size must equal the req_depth
3546 * index = req_idx
3547 */
3548 if (ioc->ReqToChain == NULL) {
3549 sz = ioc->req_depth * sizeof(int);
3550 mem = kmalloc(sz, GFP_ATOMIC);
3551 if (mem == NULL)
3552 return -1;
3553
3554 ioc->ReqToChain = (int *) mem;
3555 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3556 ioc->name, mem, sz));
3557 mem = kmalloc(sz, GFP_ATOMIC);
3558 if (mem == NULL)
3559 return -1;
3560
3561 ioc->RequestNB = (int *) mem;
3562 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3563 ioc->name, mem, sz));
3564 }
3565 for (ii = 0; ii < ioc->req_depth; ii++) {
3566 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3567 }
3568
3569 /* ChainToChain size must equal the total number
3570 * of chain buffers to be allocated.
3571 * index = chain_idx
3572 *
3573 * Calculate the number of chain buffers needed(plus 1) per I/O
3574 * then multiply the the maximum number of simultaneous cmds
3575 *
3576 * num_sge = num sge in request frame + last chain buffer
3577 * scale = num sge per chain buffer if no chain element
3578 */
3579 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3580 if (sizeof(dma_addr_t) == sizeof(u64))
3581 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3582 else
3583 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3584
3585 if (sizeof(dma_addr_t) == sizeof(u64)) {
3586 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3587 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3588 } else {
3589 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3590 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3591 }
3592 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3593 ioc->name, num_sge, numSGE));
3594
3595 if ( numSGE > MPT_SCSI_SG_DEPTH )
3596 numSGE = MPT_SCSI_SG_DEPTH;
3597
3598 num_chain = 1;
3599 while (numSGE - num_sge > 0) {
3600 num_chain++;
3601 num_sge += (scale - 1);
3602 }
3603 num_chain++;
3604
3605 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3606 ioc->name, numSGE, num_sge, num_chain));
3607
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003608 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 num_chain *= MPT_SCSI_CAN_QUEUE;
3610 else
3611 num_chain *= MPT_FC_CAN_QUEUE;
3612
3613 ioc->num_chain = num_chain;
3614
3615 sz = num_chain * sizeof(int);
3616 if (ioc->ChainToChain == NULL) {
3617 mem = kmalloc(sz, GFP_ATOMIC);
3618 if (mem == NULL)
3619 return -1;
3620
3621 ioc->ChainToChain = (int *) mem;
3622 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3623 ioc->name, mem, sz));
3624 } else {
3625 mem = (u8 *) ioc->ChainToChain;
3626 }
3627 memset(mem, 0xFF, sz);
3628 return num_chain;
3629}
3630
3631/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003632/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3634 * @ioc: Pointer to MPT_ADAPTER structure
3635 *
3636 * This routine allocates memory for the MPT reply and request frame
3637 * pools (if necessary), and primes the IOC reply FIFO with
3638 * reply frames.
3639 *
3640 * Returns 0 for success, non-zero for failure.
3641 */
3642static int
3643PrimeIocFifos(MPT_ADAPTER *ioc)
3644{
3645 MPT_FRAME_HDR *mf;
3646 unsigned long flags;
3647 dma_addr_t alloc_dma;
3648 u8 *mem;
3649 int i, reply_sz, sz, total_size, num_chain;
3650
3651 /* Prime reply FIFO... */
3652
3653 if (ioc->reply_frames == NULL) {
3654 if ( (num_chain = initChainBuffers(ioc)) < 0)
3655 return -1;
3656
3657 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3658 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3659 ioc->name, ioc->reply_sz, ioc->reply_depth));
3660 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3661 ioc->name, reply_sz, reply_sz));
3662
3663 sz = (ioc->req_sz * ioc->req_depth);
3664 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3665 ioc->name, ioc->req_sz, ioc->req_depth));
3666 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3667 ioc->name, sz, sz));
3668 total_size += sz;
3669
3670 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3671 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3672 ioc->name, ioc->req_sz, num_chain));
3673 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3674 ioc->name, sz, sz, num_chain));
3675
3676 total_size += sz;
3677 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3678 if (mem == NULL) {
3679 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3680 ioc->name);
3681 goto out_fail;
3682 }
3683
3684 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3685 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3686
3687 memset(mem, 0, total_size);
3688 ioc->alloc_total += total_size;
3689 ioc->alloc = mem;
3690 ioc->alloc_dma = alloc_dma;
3691 ioc->alloc_sz = total_size;
3692 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3693 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3694
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003695 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3696 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3697
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 alloc_dma += reply_sz;
3699 mem += reply_sz;
3700
3701 /* Request FIFO - WE manage this! */
3702
3703 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3704 ioc->req_frames_dma = alloc_dma;
3705
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003706 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 ioc->name, mem, (void *)(ulong)alloc_dma));
3708
3709 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3710
3711#if defined(CONFIG_MTRR) && 0
3712 /*
3713 * Enable Write Combining MTRR for IOC's memory region.
3714 * (at least as much as we can; "size and base must be
3715 * multiples of 4 kiB"
3716 */
3717 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3718 sz,
3719 MTRR_TYPE_WRCOMB, 1);
3720 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3721 ioc->name, ioc->req_frames_dma, sz));
3722#endif
3723
3724 for (i = 0; i < ioc->req_depth; i++) {
3725 alloc_dma += ioc->req_sz;
3726 mem += ioc->req_sz;
3727 }
3728
3729 ioc->ChainBuffer = mem;
3730 ioc->ChainBufferDMA = alloc_dma;
3731
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003732 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3734
3735 /* Initialize the free chain Q.
3736 */
3737
3738 INIT_LIST_HEAD(&ioc->FreeChainQ);
3739
3740 /* Post the chain buffers to the FreeChainQ.
3741 */
3742 mem = (u8 *)ioc->ChainBuffer;
3743 for (i=0; i < num_chain; i++) {
3744 mf = (MPT_FRAME_HDR *) mem;
3745 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3746 mem += ioc->req_sz;
3747 }
3748
3749 /* Initialize Request frames linked list
3750 */
3751 alloc_dma = ioc->req_frames_dma;
3752 mem = (u8 *) ioc->req_frames;
3753
3754 spin_lock_irqsave(&ioc->FreeQlock, flags);
3755 INIT_LIST_HEAD(&ioc->FreeQ);
3756 for (i = 0; i < ioc->req_depth; i++) {
3757 mf = (MPT_FRAME_HDR *) mem;
3758
3759 /* Queue REQUESTs *internally*! */
3760 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3761
3762 mem += ioc->req_sz;
3763 }
3764 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3765
3766 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3767 ioc->sense_buf_pool =
3768 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3769 if (ioc->sense_buf_pool == NULL) {
3770 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3771 ioc->name);
3772 goto out_fail;
3773 }
3774
3775 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3776 ioc->alloc_total += sz;
3777 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3778 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3779
3780 }
3781
3782 /* Post Reply frames to FIFO
3783 */
3784 alloc_dma = ioc->alloc_dma;
3785 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3786 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3787
3788 for (i = 0; i < ioc->reply_depth; i++) {
3789 /* Write each address to the IOC! */
3790 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3791 alloc_dma += ioc->reply_sz;
3792 }
3793
3794 return 0;
3795
3796out_fail:
3797 if (ioc->alloc != NULL) {
3798 sz = ioc->alloc_sz;
3799 pci_free_consistent(ioc->pcidev,
3800 sz,
3801 ioc->alloc, ioc->alloc_dma);
3802 ioc->reply_frames = NULL;
3803 ioc->req_frames = NULL;
3804 ioc->alloc_total -= sz;
3805 }
3806 if (ioc->sense_buf_pool != NULL) {
3807 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3808 pci_free_consistent(ioc->pcidev,
3809 sz,
3810 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3811 ioc->sense_buf_pool = NULL;
3812 }
3813 return -1;
3814}
3815
3816/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3817/**
3818 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3819 * from IOC via doorbell handshake method.
3820 * @ioc: Pointer to MPT_ADAPTER structure
3821 * @reqBytes: Size of the request in bytes
3822 * @req: Pointer to MPT request frame
3823 * @replyBytes: Expected size of the reply in bytes
3824 * @u16reply: Pointer to area where reply should be written
3825 * @maxwait: Max wait time for a reply (in seconds)
3826 * @sleepFlag: Specifies whether the process can sleep
3827 *
3828 * NOTES: It is the callers responsibility to byte-swap fields in the
3829 * request which are greater than 1 byte in size. It is also the
3830 * callers responsibility to byte-swap response fields which are
3831 * greater than 1 byte in size.
3832 *
3833 * Returns 0 for success, non-zero for failure.
3834 */
3835static int
3836mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003837 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838{
3839 MPIDefaultReply_t *mptReply;
3840 int failcnt = 0;
3841 int t;
3842
3843 /*
3844 * Get ready to cache a handshake reply
3845 */
3846 ioc->hs_reply_idx = 0;
3847 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3848 mptReply->MsgLength = 0;
3849
3850 /*
3851 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3852 * then tell IOC that we want to handshake a request of N words.
3853 * (WRITE u32val to Doorbell reg).
3854 */
3855 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3856 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3857 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3858 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3859
3860 /*
3861 * Wait for IOC's doorbell handshake int
3862 */
3863 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3864 failcnt++;
3865
3866 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3867 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3868
3869 /* Read doorbell and check for active bit */
3870 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3871 return -1;
3872
3873 /*
3874 * Clear doorbell int (WRITE 0 to IntStatus reg),
3875 * then wait for IOC to ACKnowledge that it's ready for
3876 * our handshake request.
3877 */
3878 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3879 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3880 failcnt++;
3881
3882 if (!failcnt) {
3883 int ii;
3884 u8 *req_as_bytes = (u8 *) req;
3885
3886 /*
3887 * Stuff request words via doorbell handshake,
3888 * with ACK from IOC for each.
3889 */
3890 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3891 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3892 (req_as_bytes[(ii*4) + 1] << 8) |
3893 (req_as_bytes[(ii*4) + 2] << 16) |
3894 (req_as_bytes[(ii*4) + 3] << 24));
3895
3896 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3897 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3898 failcnt++;
3899 }
3900
3901 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3902 DBG_DUMP_REQUEST_FRAME_HDR(req)
3903
3904 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3905 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3906
3907 /*
3908 * Wait for completion of doorbell handshake reply from the IOC
3909 */
3910 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3911 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003912
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3914 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3915
3916 /*
3917 * Copy out the cached reply...
3918 */
3919 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3920 u16reply[ii] = ioc->hs_reply[ii];
3921 } else {
3922 return -99;
3923 }
3924
3925 return -failcnt;
3926}
3927
3928/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003929/**
3930 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 * @ioc: Pointer to MPT_ADAPTER structure
3932 * @howlong: How long to wait (in seconds)
3933 * @sleepFlag: Specifies whether the process can sleep
3934 *
3935 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003936 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
3937 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 *
3939 * Returns a negative value on failure, else wait loop count.
3940 */
3941static int
3942WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3943{
3944 int cntdn;
3945 int count = 0;
3946 u32 intstat=0;
3947
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003948 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949
3950 if (sleepFlag == CAN_SLEEP) {
3951 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003952 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3954 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3955 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 count++;
3957 }
3958 } else {
3959 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003960 mdelay (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3962 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3963 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 count++;
3965 }
3966 }
3967
3968 if (cntdn) {
3969 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3970 ioc->name, count));
3971 return count;
3972 }
3973
3974 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3975 ioc->name, count, intstat);
3976 return -1;
3977}
3978
3979/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003980/**
3981 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 * @ioc: Pointer to MPT_ADAPTER structure
3983 * @howlong: How long to wait (in seconds)
3984 * @sleepFlag: Specifies whether the process can sleep
3985 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003986 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
3987 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 *
3989 * Returns a negative value on failure, else wait loop count.
3990 */
3991static int
3992WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3993{
3994 int cntdn;
3995 int count = 0;
3996 u32 intstat=0;
3997
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003998 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 if (sleepFlag == CAN_SLEEP) {
4000 while (--cntdn) {
4001 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4002 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4003 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004004 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 count++;
4006 }
4007 } else {
4008 while (--cntdn) {
4009 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4010 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4011 break;
4012 mdelay(1);
4013 count++;
4014 }
4015 }
4016
4017 if (cntdn) {
4018 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
4019 ioc->name, count, howlong));
4020 return count;
4021 }
4022
4023 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4024 ioc->name, count, intstat);
4025 return -1;
4026}
4027
4028/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004029/**
4030 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 * @ioc: Pointer to MPT_ADAPTER structure
4032 * @howlong: How long to wait (in seconds)
4033 * @sleepFlag: Specifies whether the process can sleep
4034 *
4035 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4036 * Reply is cached to IOC private area large enough to hold a maximum
4037 * of 128 bytes of reply data.
4038 *
4039 * Returns a negative value on failure, else size of reply in WORDS.
4040 */
4041static int
4042WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4043{
4044 int u16cnt = 0;
4045 int failcnt = 0;
4046 int t;
4047 u16 *hs_reply = ioc->hs_reply;
4048 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4049 u16 hword;
4050
4051 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4052
4053 /*
4054 * Get first two u16's so we can look at IOC's intended reply MsgLength
4055 */
4056 u16cnt=0;
4057 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4058 failcnt++;
4059 } else {
4060 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4061 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4062 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4063 failcnt++;
4064 else {
4065 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4066 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4067 }
4068 }
4069
4070 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004071 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4073
4074 /*
4075 * If no error (and IOC said MsgLength is > 0), piece together
4076 * reply 16 bits at a time.
4077 */
4078 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4079 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4080 failcnt++;
4081 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4082 /* don't overflow our IOC hs_reply[] buffer! */
4083 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4084 hs_reply[u16cnt] = hword;
4085 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4086 }
4087
4088 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4089 failcnt++;
4090 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4091
4092 if (failcnt) {
4093 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4094 ioc->name);
4095 return -failcnt;
4096 }
4097#if 0
4098 else if (u16cnt != (2 * mptReply->MsgLength)) {
4099 return -101;
4100 }
4101 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4102 return -102;
4103 }
4104#endif
4105
4106 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4107 DBG_DUMP_REPLY_FRAME(mptReply)
4108
4109 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4110 ioc->name, t, u16cnt/2));
4111 return u16cnt/2;
4112}
4113
4114/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004115/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 * GetLanConfigPages - Fetch LANConfig pages.
4117 * @ioc: Pointer to MPT_ADAPTER structure
4118 *
4119 * Return: 0 for success
4120 * -ENOMEM if no memory available
4121 * -EPERM if not allowed due to ISR context
4122 * -EAGAIN if no msg frames currently available
4123 * -EFAULT for non-successful reply or no reply (timeout)
4124 */
4125static int
4126GetLanConfigPages(MPT_ADAPTER *ioc)
4127{
4128 ConfigPageHeader_t hdr;
4129 CONFIGPARMS cfg;
4130 LANPage0_t *ppage0_alloc;
4131 dma_addr_t page0_dma;
4132 LANPage1_t *ppage1_alloc;
4133 dma_addr_t page1_dma;
4134 int rc = 0;
4135 int data_sz;
4136 int copy_sz;
4137
4138 /* Get LAN Page 0 header */
4139 hdr.PageVersion = 0;
4140 hdr.PageLength = 0;
4141 hdr.PageNumber = 0;
4142 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004143 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 cfg.physAddr = -1;
4145 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4146 cfg.dir = 0;
4147 cfg.pageAddr = 0;
4148 cfg.timeout = 0;
4149
4150 if ((rc = mpt_config(ioc, &cfg)) != 0)
4151 return rc;
4152
4153 if (hdr.PageLength > 0) {
4154 data_sz = hdr.PageLength * 4;
4155 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4156 rc = -ENOMEM;
4157 if (ppage0_alloc) {
4158 memset((u8 *)ppage0_alloc, 0, data_sz);
4159 cfg.physAddr = page0_dma;
4160 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4161
4162 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4163 /* save the data */
4164 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4165 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4166
4167 }
4168
4169 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4170
4171 /* FIXME!
4172 * Normalize endianness of structure data,
4173 * by byte-swapping all > 1 byte fields!
4174 */
4175
4176 }
4177
4178 if (rc)
4179 return rc;
4180 }
4181
4182 /* Get LAN Page 1 header */
4183 hdr.PageVersion = 0;
4184 hdr.PageLength = 0;
4185 hdr.PageNumber = 1;
4186 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004187 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 cfg.physAddr = -1;
4189 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4190 cfg.dir = 0;
4191 cfg.pageAddr = 0;
4192
4193 if ((rc = mpt_config(ioc, &cfg)) != 0)
4194 return rc;
4195
4196 if (hdr.PageLength == 0)
4197 return 0;
4198
4199 data_sz = hdr.PageLength * 4;
4200 rc = -ENOMEM;
4201 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4202 if (ppage1_alloc) {
4203 memset((u8 *)ppage1_alloc, 0, data_sz);
4204 cfg.physAddr = page1_dma;
4205 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4206
4207 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4208 /* save the data */
4209 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4210 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4211 }
4212
4213 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4214
4215 /* FIXME!
4216 * Normalize endianness of structure data,
4217 * by byte-swapping all > 1 byte fields!
4218 */
4219
4220 }
4221
4222 return rc;
4223}
4224
4225/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004226/**
4227 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004228 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004229 * @persist_opcode: see below
4230 *
4231 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4232 * devices not currently present.
4233 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4234 *
4235 * NOTE: Don't use not this function during interrupt time.
4236 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004237 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004238 */
4239
4240/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4241int
4242mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4243{
4244 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4245 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4246 MPT_FRAME_HDR *mf = NULL;
4247 MPIHeader_t *mpi_hdr;
4248
4249
4250 /* insure garbage is not sent to fw */
4251 switch(persist_opcode) {
4252
4253 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4254 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4255 break;
4256
4257 default:
4258 return -1;
4259 break;
4260 }
4261
4262 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4263
4264 /* Get a MF for this command.
4265 */
4266 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4267 printk("%s: no msg frames!\n",__FUNCTION__);
4268 return -1;
4269 }
4270
4271 mpi_hdr = (MPIHeader_t *) mf;
4272 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4273 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4274 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4275 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4276 sasIoUnitCntrReq->Operation = persist_opcode;
4277
4278 init_timer(&ioc->persist_timer);
4279 ioc->persist_timer.data = (unsigned long) ioc;
4280 ioc->persist_timer.function = mpt_timer_expired;
4281 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4282 ioc->persist_wait_done=0;
4283 add_timer(&ioc->persist_timer);
4284 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4285 wait_event(mpt_waitq, ioc->persist_wait_done);
4286
4287 sasIoUnitCntrReply =
4288 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4289 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4290 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4291 __FUNCTION__,
4292 sasIoUnitCntrReply->IOCStatus,
4293 sasIoUnitCntrReply->IOCLogInfo);
4294 return -1;
4295 }
4296
4297 printk("%s: success\n",__FUNCTION__);
4298 return 0;
4299}
4300
4301/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004302
4303static void
4304mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4305 MpiEventDataRaid_t * pRaidEventData)
4306{
4307 int volume;
4308 int reason;
4309 int disk;
4310 int status;
4311 int flags;
4312 int state;
4313
4314 volume = pRaidEventData->VolumeID;
4315 reason = pRaidEventData->ReasonCode;
4316 disk = pRaidEventData->PhysDiskNum;
4317 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4318 flags = (status >> 0) & 0xff;
4319 state = (status >> 8) & 0xff;
4320
4321 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4322 return;
4323 }
4324
4325 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4326 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4327 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4328 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4329 ioc->name, disk);
4330 } else {
4331 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4332 ioc->name, volume);
4333 }
4334
4335 switch(reason) {
4336 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4337 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4338 ioc->name);
4339 break;
4340
4341 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4342
4343 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4344 ioc->name);
4345 break;
4346
4347 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4348 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4349 ioc->name);
4350 break;
4351
4352 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4353 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4354 ioc->name,
4355 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4356 ? "optimal"
4357 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4358 ? "degraded"
4359 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4360 ? "failed"
4361 : "state unknown",
4362 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4363 ? ", enabled" : "",
4364 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4365 ? ", quiesced" : "",
4366 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4367 ? ", resync in progress" : "" );
4368 break;
4369
4370 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4371 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4372 ioc->name, disk);
4373 break;
4374
4375 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4376 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4377 ioc->name);
4378 break;
4379
4380 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4381 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4382 ioc->name);
4383 break;
4384
4385 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4386 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4387 ioc->name);
4388 break;
4389
4390 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4391 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4392 ioc->name,
4393 state == MPI_PHYSDISK0_STATUS_ONLINE
4394 ? "online"
4395 : state == MPI_PHYSDISK0_STATUS_MISSING
4396 ? "missing"
4397 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4398 ? "not compatible"
4399 : state == MPI_PHYSDISK0_STATUS_FAILED
4400 ? "failed"
4401 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4402 ? "initializing"
4403 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4404 ? "offline requested"
4405 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4406 ? "failed requested"
4407 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4408 ? "offline"
4409 : "state unknown",
4410 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4411 ? ", out of sync" : "",
4412 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4413 ? ", quiesced" : "" );
4414 break;
4415
4416 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4417 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4418 ioc->name, disk);
4419 break;
4420
4421 case MPI_EVENT_RAID_RC_SMART_DATA:
4422 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4423 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4424 break;
4425
4426 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4427 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4428 ioc->name, disk);
4429 break;
4430 }
4431}
4432
4433/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004434/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4436 * @ioc: Pointer to MPT_ADAPTER structure
4437 *
4438 * Returns: 0 for success
4439 * -ENOMEM if no memory available
4440 * -EPERM if not allowed due to ISR context
4441 * -EAGAIN if no msg frames currently available
4442 * -EFAULT for non-successful reply or no reply (timeout)
4443 */
4444static int
4445GetIoUnitPage2(MPT_ADAPTER *ioc)
4446{
4447 ConfigPageHeader_t hdr;
4448 CONFIGPARMS cfg;
4449 IOUnitPage2_t *ppage_alloc;
4450 dma_addr_t page_dma;
4451 int data_sz;
4452 int rc;
4453
4454 /* Get the page header */
4455 hdr.PageVersion = 0;
4456 hdr.PageLength = 0;
4457 hdr.PageNumber = 2;
4458 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004459 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 cfg.physAddr = -1;
4461 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4462 cfg.dir = 0;
4463 cfg.pageAddr = 0;
4464 cfg.timeout = 0;
4465
4466 if ((rc = mpt_config(ioc, &cfg)) != 0)
4467 return rc;
4468
4469 if (hdr.PageLength == 0)
4470 return 0;
4471
4472 /* Read the config page */
4473 data_sz = hdr.PageLength * 4;
4474 rc = -ENOMEM;
4475 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4476 if (ppage_alloc) {
4477 memset((u8 *)ppage_alloc, 0, data_sz);
4478 cfg.physAddr = page_dma;
4479 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4480
4481 /* If Good, save data */
4482 if ((rc = mpt_config(ioc, &cfg)) == 0)
4483 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4484
4485 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4486 }
4487
4488 return rc;
4489}
4490
4491/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004492/**
4493 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 * @ioc: Pointer to a Adapter Strucutre
4495 * @portnum: IOC port number
4496 *
4497 * Return: -EFAULT if read of config page header fails
4498 * or if no nvram
4499 * If read of SCSI Port Page 0 fails,
4500 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4501 * Adapter settings: async, narrow
4502 * Return 1
4503 * If read of SCSI Port Page 2 fails,
4504 * Adapter settings valid
4505 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4506 * Return 1
4507 * Else
4508 * Both valid
4509 * Return 0
4510 * CHECK - what type of locking mechanisms should be used????
4511 */
4512static int
4513mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4514{
4515 u8 *pbuf;
4516 dma_addr_t buf_dma;
4517 CONFIGPARMS cfg;
4518 ConfigPageHeader_t header;
4519 int ii;
4520 int data, rc = 0;
4521
4522 /* Allocate memory
4523 */
4524 if (!ioc->spi_data.nvram) {
4525 int sz;
4526 u8 *mem;
4527 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4528 mem = kmalloc(sz, GFP_ATOMIC);
4529 if (mem == NULL)
4530 return -EFAULT;
4531
4532 ioc->spi_data.nvram = (int *) mem;
4533
4534 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4535 ioc->name, ioc->spi_data.nvram, sz));
4536 }
4537
4538 /* Invalidate NVRAM information
4539 */
4540 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4541 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4542 }
4543
4544 /* Read SPP0 header, allocate memory, then read page.
4545 */
4546 header.PageVersion = 0;
4547 header.PageLength = 0;
4548 header.PageNumber = 0;
4549 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004550 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 cfg.physAddr = -1;
4552 cfg.pageAddr = portnum;
4553 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4554 cfg.dir = 0;
4555 cfg.timeout = 0; /* use default */
4556 if (mpt_config(ioc, &cfg) != 0)
4557 return -EFAULT;
4558
4559 if (header.PageLength > 0) {
4560 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4561 if (pbuf) {
4562 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4563 cfg.physAddr = buf_dma;
4564 if (mpt_config(ioc, &cfg) != 0) {
4565 ioc->spi_data.maxBusWidth = MPT_NARROW;
4566 ioc->spi_data.maxSyncOffset = 0;
4567 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4568 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4569 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004570 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4571 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 } else {
4573 /* Save the Port Page 0 data
4574 */
4575 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4576 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4577 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4578
4579 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4580 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004581 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 ioc->name, pPP0->Capabilities));
4583 }
4584 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4585 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4586 if (data) {
4587 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4588 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4589 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004590 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4591 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 } else {
4593 ioc->spi_data.maxSyncOffset = 0;
4594 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4595 }
4596
4597 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4598
4599 /* Update the minSyncFactor based on bus type.
4600 */
4601 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4602 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4603
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004604 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004606 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4607 ioc->name, ioc->spi_data.minSyncFactor));
4608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 }
4610 }
4611 if (pbuf) {
4612 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4613 }
4614 }
4615 }
4616
4617 /* SCSI Port Page 2 - Read the header then the page.
4618 */
4619 header.PageVersion = 0;
4620 header.PageLength = 0;
4621 header.PageNumber = 2;
4622 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004623 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 cfg.physAddr = -1;
4625 cfg.pageAddr = portnum;
4626 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4627 cfg.dir = 0;
4628 if (mpt_config(ioc, &cfg) != 0)
4629 return -EFAULT;
4630
4631 if (header.PageLength > 0) {
4632 /* Allocate memory and read SCSI Port Page 2
4633 */
4634 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4635 if (pbuf) {
4636 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4637 cfg.physAddr = buf_dma;
4638 if (mpt_config(ioc, &cfg) != 0) {
4639 /* Nvram data is left with INVALID mark
4640 */
4641 rc = 1;
4642 } else {
4643 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4644 MpiDeviceInfo_t *pdevice = NULL;
4645
Moore, Ericd8e925d2006-01-16 18:53:06 -07004646 /*
4647 * Save "Set to Avoid SCSI Bus Resets" flag
4648 */
4649 ioc->spi_data.bus_reset =
4650 (le32_to_cpu(pPP2->PortFlags) &
4651 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4652 0 : 1 ;
4653
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 /* Save the Port Page 2 data
4655 * (reformat into a 32bit quantity)
4656 */
4657 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4658 ioc->spi_data.PortFlags = data;
4659 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4660 pdevice = &pPP2->DeviceSettings[ii];
4661 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4662 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4663 ioc->spi_data.nvram[ii] = data;
4664 }
4665 }
4666
4667 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4668 }
4669 }
4670
4671 /* Update Adapter limits with those from NVRAM
4672 * Comment: Don't need to do this. Target performance
4673 * parameters will never exceed the adapters limits.
4674 */
4675
4676 return rc;
4677}
4678
4679/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004680/**
4681 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 * @ioc: Pointer to a Adapter Strucutre
4683 * @portnum: IOC port number
4684 *
4685 * Return: -EFAULT if read of config page header fails
4686 * or 0 if success.
4687 */
4688static int
4689mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4690{
4691 CONFIGPARMS cfg;
4692 ConfigPageHeader_t header;
4693
4694 /* Read the SCSI Device Page 1 header
4695 */
4696 header.PageVersion = 0;
4697 header.PageLength = 0;
4698 header.PageNumber = 1;
4699 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004700 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 cfg.physAddr = -1;
4702 cfg.pageAddr = portnum;
4703 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4704 cfg.dir = 0;
4705 cfg.timeout = 0;
4706 if (mpt_config(ioc, &cfg) != 0)
4707 return -EFAULT;
4708
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004709 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4710 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711
4712 header.PageVersion = 0;
4713 header.PageLength = 0;
4714 header.PageNumber = 0;
4715 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4716 if (mpt_config(ioc, &cfg) != 0)
4717 return -EFAULT;
4718
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004719 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4720 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721
4722 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4723 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4724
4725 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4726 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4727 return 0;
4728}
4729
4730/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4731/**
4732 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4733 * @ioc: Pointer to a Adapter Strucutre
4734 * @portnum: IOC port number
4735 *
4736 * Return:
4737 * 0 on success
4738 * -EFAULT if read of config page header fails or data pointer not NULL
4739 * -ENOMEM if pci_alloc failed
4740 */
4741int
4742mpt_findImVolumes(MPT_ADAPTER *ioc)
4743{
4744 IOCPage2_t *pIoc2;
4745 u8 *mem;
4746 ConfigPageIoc2RaidVol_t *pIocRv;
4747 dma_addr_t ioc2_dma;
4748 CONFIGPARMS cfg;
4749 ConfigPageHeader_t header;
4750 int jj;
4751 int rc = 0;
4752 int iocpage2sz;
4753 u8 nVols, nPhys;
4754 u8 vid, vbus, vioc;
4755
4756 /* Read IOCP2 header then the page.
4757 */
4758 header.PageVersion = 0;
4759 header.PageLength = 0;
4760 header.PageNumber = 2;
4761 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004762 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 cfg.physAddr = -1;
4764 cfg.pageAddr = 0;
4765 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4766 cfg.dir = 0;
4767 cfg.timeout = 0;
4768 if (mpt_config(ioc, &cfg) != 0)
4769 return -EFAULT;
4770
4771 if (header.PageLength == 0)
4772 return -EFAULT;
4773
4774 iocpage2sz = header.PageLength * 4;
4775 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4776 if (!pIoc2)
4777 return -ENOMEM;
4778
4779 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4780 cfg.physAddr = ioc2_dma;
4781 if (mpt_config(ioc, &cfg) != 0)
4782 goto done_and_free;
4783
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004784 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4786 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004787 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 } else {
4789 goto done_and_free;
4790 }
4791 }
4792 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4793
4794 /* Identify RAID Volume Id's */
4795 nVols = pIoc2->NumActiveVolumes;
4796 if ( nVols == 0) {
4797 /* No RAID Volume.
4798 */
4799 goto done_and_free;
4800 } else {
4801 /* At least 1 RAID Volume
4802 */
4803 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004804 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4806 vid = pIocRv->VolumeID;
4807 vbus = pIocRv->VolumeBus;
4808 vioc = pIocRv->VolumeIOC;
4809
4810 /* find the match
4811 */
4812 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004813 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 } else {
4815 /* Error! Always bus 0
4816 */
4817 }
4818 }
4819 }
4820
4821 /* Identify Hidden Physical Disk Id's */
4822 nPhys = pIoc2->NumActivePhysDisks;
4823 if (nPhys == 0) {
4824 /* No physical disks.
4825 */
4826 } else {
4827 mpt_read_ioc_pg_3(ioc);
4828 }
4829
4830done_and_free:
4831 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4832
4833 return rc;
4834}
4835
Moore, Ericc972c702006-03-14 09:14:06 -07004836static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4838{
4839 IOCPage3_t *pIoc3;
4840 u8 *mem;
4841 CONFIGPARMS cfg;
4842 ConfigPageHeader_t header;
4843 dma_addr_t ioc3_dma;
4844 int iocpage3sz = 0;
4845
4846 /* Free the old page
4847 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004848 kfree(ioc->raid_data.pIocPg3);
4849 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850
4851 /* There is at least one physical disk.
4852 * Read and save IOC Page 3
4853 */
4854 header.PageVersion = 0;
4855 header.PageLength = 0;
4856 header.PageNumber = 3;
4857 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004858 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 cfg.physAddr = -1;
4860 cfg.pageAddr = 0;
4861 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4862 cfg.dir = 0;
4863 cfg.timeout = 0;
4864 if (mpt_config(ioc, &cfg) != 0)
4865 return 0;
4866
4867 if (header.PageLength == 0)
4868 return 0;
4869
4870 /* Read Header good, alloc memory
4871 */
4872 iocpage3sz = header.PageLength * 4;
4873 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4874 if (!pIoc3)
4875 return 0;
4876
4877 /* Read the Page and save the data
4878 * into malloc'd memory.
4879 */
4880 cfg.physAddr = ioc3_dma;
4881 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4882 if (mpt_config(ioc, &cfg) == 0) {
4883 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4884 if (mem) {
4885 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004886 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 }
4888 }
4889
4890 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4891
4892 return 0;
4893}
4894
4895static void
4896mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4897{
4898 IOCPage4_t *pIoc4;
4899 CONFIGPARMS cfg;
4900 ConfigPageHeader_t header;
4901 dma_addr_t ioc4_dma;
4902 int iocpage4sz;
4903
4904 /* Read and save IOC Page 4
4905 */
4906 header.PageVersion = 0;
4907 header.PageLength = 0;
4908 header.PageNumber = 4;
4909 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004910 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 cfg.physAddr = -1;
4912 cfg.pageAddr = 0;
4913 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4914 cfg.dir = 0;
4915 cfg.timeout = 0;
4916 if (mpt_config(ioc, &cfg) != 0)
4917 return;
4918
4919 if (header.PageLength == 0)
4920 return;
4921
4922 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4923 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4924 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4925 if (!pIoc4)
4926 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06004927 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 } else {
4929 ioc4_dma = ioc->spi_data.IocPg4_dma;
4930 iocpage4sz = ioc->spi_data.IocPg4Sz;
4931 }
4932
4933 /* Read the Page into dma memory.
4934 */
4935 cfg.physAddr = ioc4_dma;
4936 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4937 if (mpt_config(ioc, &cfg) == 0) {
4938 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4939 ioc->spi_data.IocPg4_dma = ioc4_dma;
4940 ioc->spi_data.IocPg4Sz = iocpage4sz;
4941 } else {
4942 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4943 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06004944 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 }
4946}
4947
4948static void
4949mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4950{
4951 IOCPage1_t *pIoc1;
4952 CONFIGPARMS cfg;
4953 ConfigPageHeader_t header;
4954 dma_addr_t ioc1_dma;
4955 int iocpage1sz = 0;
4956 u32 tmp;
4957
4958 /* Check the Coalescing Timeout in IOC Page 1
4959 */
4960 header.PageVersion = 0;
4961 header.PageLength = 0;
4962 header.PageNumber = 1;
4963 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004964 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 cfg.physAddr = -1;
4966 cfg.pageAddr = 0;
4967 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4968 cfg.dir = 0;
4969 cfg.timeout = 0;
4970 if (mpt_config(ioc, &cfg) != 0)
4971 return;
4972
4973 if (header.PageLength == 0)
4974 return;
4975
4976 /* Read Header good, alloc memory
4977 */
4978 iocpage1sz = header.PageLength * 4;
4979 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
4980 if (!pIoc1)
4981 return;
4982
4983 /* Read the Page and check coalescing timeout
4984 */
4985 cfg.physAddr = ioc1_dma;
4986 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4987 if (mpt_config(ioc, &cfg) == 0) {
4988
4989 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
4990 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
4991 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
4992
4993 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
4994 ioc->name, tmp));
4995
4996 if (tmp > MPT_COALESCING_TIMEOUT) {
4997 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
4998
4999 /* Write NVRAM and current
5000 */
5001 cfg.dir = 1;
5002 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5003 if (mpt_config(ioc, &cfg) == 0) {
5004 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5005 ioc->name, MPT_COALESCING_TIMEOUT));
5006
5007 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5008 if (mpt_config(ioc, &cfg) == 0) {
5009 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5010 ioc->name, MPT_COALESCING_TIMEOUT));
5011 } else {
5012 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5013 ioc->name));
5014 }
5015
5016 } else {
5017 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5018 ioc->name));
5019 }
5020 }
5021
5022 } else {
5023 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5024 }
5025 }
5026
5027 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5028
5029 return;
5030}
5031
5032/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005033/**
5034 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035 * @ioc: Pointer to MPT_ADAPTER structure
5036 * @EvSwitch: Event switch flags
5037 */
5038static int
5039SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5040{
5041 EventNotification_t *evnp;
5042
5043 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5044 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005045 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 ioc->name));
5047 return 0;
5048 }
5049 memset(evnp, 0, sizeof(*evnp));
5050
Moore, Eric3a892be2006-03-14 09:14:03 -07005051 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052
5053 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5054 evnp->ChainOffset = 0;
5055 evnp->MsgFlags = 0;
5056 evnp->Switch = EvSwitch;
5057
5058 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5059
5060 return 0;
5061}
5062
5063/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5064/**
5065 * SendEventAck - Send EventAck request to MPT adapter.
5066 * @ioc: Pointer to MPT_ADAPTER structure
5067 * @evnp: Pointer to original EventNotification request
5068 */
5069static int
5070SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5071{
5072 EventAck_t *pAck;
5073
5074 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Eric Moore4f766dc2006-07-11 17:24:07 -06005075 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
5076 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 return -1;
5078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079
Eric Moore4f766dc2006-07-11 17:24:07 -06005080 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081
5082 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5083 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005084 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005086 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 pAck->Event = evnp->Event;
5088 pAck->EventContext = evnp->EventContext;
5089
5090 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5091
5092 return 0;
5093}
5094
5095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5096/**
5097 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005098 * @ioc: Pointer to an adapter structure
5099 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 * action, page address, direction, physical address
5101 * and pointer to a configuration page header
5102 * Page header is updated.
5103 *
5104 * Returns 0 for success
5105 * -EPERM if not allowed due to ISR context
5106 * -EAGAIN if no msg frames currently available
5107 * -EFAULT for non-successful reply or no reply (timeout)
5108 */
5109int
5110mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5111{
5112 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005113 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 MPT_FRAME_HDR *mf;
5115 unsigned long flags;
5116 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005117 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 int in_isr;
5119
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005120 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 * to be in ISR context, because that is fatal!
5122 */
5123 in_isr = in_interrupt();
5124 if (in_isr) {
5125 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5126 ioc->name));
5127 return -EPERM;
5128 }
5129
5130 /* Get and Populate a free Frame
5131 */
5132 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5133 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5134 ioc->name));
5135 return -EAGAIN;
5136 }
5137 pReq = (Config_t *)mf;
5138 pReq->Action = pCfg->action;
5139 pReq->Reserved = 0;
5140 pReq->ChainOffset = 0;
5141 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005142
5143 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 pReq->ExtPageLength = 0;
5145 pReq->ExtPageType = 0;
5146 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005147
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 for (ii=0; ii < 8; ii++)
5149 pReq->Reserved2[ii] = 0;
5150
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005151 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5152 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5153 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5154 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5155
5156 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5157 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5158 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5159 pReq->ExtPageType = pExtHdr->ExtPageType;
5160 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5161
5162 /* Page Length must be treated as a reserved field for the extended header. */
5163 pReq->Header.PageLength = 0;
5164 }
5165
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5167
5168 /* Add a SGE to the config request.
5169 */
5170 if (pCfg->dir)
5171 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5172 else
5173 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5174
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005175 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5176 flagsLength |= pExtHdr->ExtPageLength * 4;
5177
5178 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5179 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5180 }
5181 else {
5182 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5183
5184 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5185 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187
5188 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5189
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 /* Append pCfg pointer to end of mf
5191 */
5192 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5193
5194 /* Initalize the timer
5195 */
5196 init_timer(&pCfg->timer);
5197 pCfg->timer.data = (unsigned long) ioc;
5198 pCfg->timer.function = mpt_timer_expired;
5199 pCfg->wait_done = 0;
5200
5201 /* Set the timer; ensure 10 second minimum */
5202 if (pCfg->timeout < 10)
5203 pCfg->timer.expires = jiffies + HZ*10;
5204 else
5205 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5206
5207 /* Add to end of Q, set timer and then issue this command */
5208 spin_lock_irqsave(&ioc->FreeQlock, flags);
5209 list_add_tail(&pCfg->linkage, &ioc->configQ);
5210 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5211
5212 add_timer(&pCfg->timer);
5213 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5214 wait_event(mpt_waitq, pCfg->wait_done);
5215
5216 /* mf has been freed - do not access */
5217
5218 rc = pCfg->status;
5219
5220 return rc;
5221}
5222
5223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005224/**
5225 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 * Used only internal config functionality.
5227 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5228 */
5229static void
5230mpt_timer_expired(unsigned long data)
5231{
5232 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5233
5234 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5235
5236 /* Perform a FW reload */
5237 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5238 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5239
5240 /* No more processing.
5241 * Hard reset clean-up will wake up
5242 * process and free all resources.
5243 */
5244 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5245
5246 return;
5247}
5248
5249/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005250/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 * mpt_ioc_reset - Base cleanup for hard reset
5252 * @ioc: Pointer to the adapter structure
5253 * @reset_phase: Indicates pre- or post-reset functionality
5254 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005255 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 */
5257static int
5258mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5259{
5260 CONFIGPARMS *pCfg;
5261 unsigned long flags;
5262
5263 dprintk((KERN_WARNING MYNAM
5264 ": IOC %s_reset routed to MPT base driver!\n",
5265 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5266 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5267
5268 if (reset_phase == MPT_IOC_SETUP_RESET) {
5269 ;
5270 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5271 /* If the internal config Q is not empty -
5272 * delete timer. MF resources will be freed when
5273 * the FIFO's are primed.
5274 */
5275 spin_lock_irqsave(&ioc->FreeQlock, flags);
5276 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5277 del_timer(&pCfg->timer);
5278 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5279
5280 } else {
5281 CONFIGPARMS *pNext;
5282
5283 /* Search the configQ for internal commands.
5284 * Flush the Q, and wake up all suspended threads.
5285 */
5286 spin_lock_irqsave(&ioc->FreeQlock, flags);
5287 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5288 list_del(&pCfg->linkage);
5289
5290 pCfg->status = MPT_CONFIG_ERROR;
5291 pCfg->wait_done = 1;
5292 wake_up(&mpt_waitq);
5293 }
5294 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5295 }
5296
5297 return 1; /* currently means nothing really */
5298}
5299
5300
5301#ifdef CONFIG_PROC_FS /* { */
5302/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5303/*
5304 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5305 */
5306/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005307/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5309 *
5310 * Returns 0 for success, non-zero for failure.
5311 */
5312static int
5313procmpt_create(void)
5314{
5315 struct proc_dir_entry *ent;
5316
5317 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5318 if (mpt_proc_root_dir == NULL)
5319 return -ENOTDIR;
5320
5321 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5322 if (ent)
5323 ent->read_proc = procmpt_summary_read;
5324
5325 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5326 if (ent)
5327 ent->read_proc = procmpt_version_read;
5328
5329 return 0;
5330}
5331
5332/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005333/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5335 *
5336 * Returns 0 for success, non-zero for failure.
5337 */
5338static void
5339procmpt_destroy(void)
5340{
5341 remove_proc_entry("version", mpt_proc_root_dir);
5342 remove_proc_entry("summary", mpt_proc_root_dir);
5343 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5344}
5345
5346/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005347/**
5348 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349 * @buf: Pointer to area to write information
5350 * @start: Pointer to start pointer
5351 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005352 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 * @eof: Pointer to EOF integer
5354 * @data: Pointer
5355 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005356 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 * Returns number of characters written to process performing the read.
5358 */
5359static int
5360procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5361{
5362 MPT_ADAPTER *ioc;
5363 char *out = buf;
5364 int len;
5365
5366 if (data) {
5367 int more = 0;
5368
5369 ioc = data;
5370 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5371
5372 out += more;
5373 } else {
5374 list_for_each_entry(ioc, &ioc_list, list) {
5375 int more = 0;
5376
5377 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5378
5379 out += more;
5380 if ((out-buf) >= request)
5381 break;
5382 }
5383 }
5384
5385 len = out - buf;
5386
5387 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5388}
5389
5390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005391/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 * procmpt_version_read - Handle read request from /proc/mpt/version.
5393 * @buf: Pointer to area to write information
5394 * @start: Pointer to start pointer
5395 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005396 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 * @eof: Pointer to EOF integer
5398 * @data: Pointer
5399 *
5400 * Returns number of characters written to process performing the read.
5401 */
5402static int
5403procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5404{
5405 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005406 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 char *drvname;
5408 int len;
5409
5410 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5411 len += sprintf(buf+len, " Fusion MPT base driver\n");
5412
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005413 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5415 drvname = NULL;
5416 if (MptCallbacks[ii]) {
5417 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005418 case MPTSPI_DRIVER:
5419 if (!scsi++) drvname = "SPI host";
5420 break;
5421 case MPTFC_DRIVER:
5422 if (!fc++) drvname = "FC host";
5423 break;
5424 case MPTSAS_DRIVER:
5425 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 break;
5427 case MPTLAN_DRIVER:
5428 if (!lan++) drvname = "LAN";
5429 break;
5430 case MPTSTM_DRIVER:
5431 if (!targ++) drvname = "SCSI target";
5432 break;
5433 case MPTCTL_DRIVER:
5434 if (!ctl++) drvname = "ioctl";
5435 break;
5436 }
5437
5438 if (drvname)
5439 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5440 }
5441 }
5442
5443 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5444}
5445
5446/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005447/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5449 * @buf: Pointer to area to write information
5450 * @start: Pointer to start pointer
5451 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005452 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 * @eof: Pointer to EOF integer
5454 * @data: Pointer
5455 *
5456 * Returns number of characters written to process performing the read.
5457 */
5458static int
5459procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5460{
5461 MPT_ADAPTER *ioc = data;
5462 int len;
5463 char expVer[32];
5464 int sz;
5465 int p;
5466
5467 mpt_get_fw_exp_ver(expVer, ioc);
5468
5469 len = sprintf(buf, "%s:", ioc->name);
5470 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5471 len += sprintf(buf+len, " (f/w download boot flag set)");
5472// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5473// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5474
5475 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5476 ioc->facts.ProductID,
5477 ioc->prod_name);
5478 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5479 if (ioc->facts.FWImageSize)
5480 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5481 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5482 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5483 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5484
5485 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5486 ioc->facts.CurrentHostMfaHighAddr);
5487 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5488 ioc->facts.CurrentSenseBufferHighAddr);
5489
5490 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5491 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5492
5493 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5494 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5495 /*
5496 * Rounding UP to nearest 4-kB boundary here...
5497 */
5498 sz = (ioc->req_sz * ioc->req_depth) + 128;
5499 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5500 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5501 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5502 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5503 4*ioc->facts.RequestFrameSize,
5504 ioc->facts.GlobalCredits);
5505
5506 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5507 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5508 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5509 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5510 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5511 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5512 ioc->facts.CurReplyFrameSize,
5513 ioc->facts.ReplyQueueDepth);
5514
5515 len += sprintf(buf+len, " MaxDevices = %d\n",
5516 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5517 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5518
5519 /* per-port info */
5520 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5521 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5522 p+1,
5523 ioc->facts.NumberOfPorts);
5524 if (ioc->bus_type == FC) {
5525 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5526 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5527 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5528 a[5], a[4], a[3], a[2], a[1], a[0]);
5529 }
5530 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5531 ioc->fc_port_page0[p].WWNN.High,
5532 ioc->fc_port_page0[p].WWNN.Low,
5533 ioc->fc_port_page0[p].WWPN.High,
5534 ioc->fc_port_page0[p].WWPN.Low);
5535 }
5536 }
5537
5538 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5539}
5540
5541#endif /* CONFIG_PROC_FS } */
5542
5543/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5544static void
5545mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5546{
5547 buf[0] ='\0';
5548 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5549 sprintf(buf, " (Exp %02d%02d)",
5550 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5551 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5552
5553 /* insider hack! */
5554 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5555 strcat(buf, " [MDBG]");
5556 }
5557}
5558
5559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5560/**
5561 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5562 * @ioc: Pointer to MPT_ADAPTER structure
5563 * @buffer: Pointer to buffer where IOC summary info should be written
5564 * @size: Pointer to number of bytes we wrote (set by this routine)
5565 * @len: Offset at which to start writing in buffer
5566 * @showlan: Display LAN stuff?
5567 *
5568 * This routine writes (english readable) ASCII text, which represents
5569 * a summary of IOC information, to a buffer.
5570 */
5571void
5572mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5573{
5574 char expVer[32];
5575 int y;
5576
5577 mpt_get_fw_exp_ver(expVer, ioc);
5578
5579 /*
5580 * Shorter summary of attached ioc's...
5581 */
5582 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5583 ioc->name,
5584 ioc->prod_name,
5585 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5586 ioc->facts.FWVersion.Word,
5587 expVer,
5588 ioc->facts.NumberOfPorts,
5589 ioc->req_depth);
5590
5591 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5592 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5593 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5594 a[5], a[4], a[3], a[2], a[1], a[0]);
5595 }
5596
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598
5599 if (!ioc->active)
5600 y += sprintf(buffer+len+y, " (disabled)");
5601
5602 y += sprintf(buffer+len+y, "\n");
5603
5604 *size = y;
5605}
5606
5607/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5608/*
5609 * Reset Handling
5610 */
5611/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5612/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005613 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 * @ioc: Pointer to MPT_ADAPTER structure
5615 * @sleepFlag: Indicates if sleep or schedule must be called.
5616 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005617 * Issues SCSI Task Management call based on input arg values.
5618 * If TaskMgmt fails, returns associated SCSI request.
5619 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5621 * or a non-interrupt thread. In the former, must not call schedule().
5622 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005623 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 * FW reload/initialization failed.
5625 *
5626 * Returns 0 for SUCCESS or -1 if FAILED.
5627 */
5628int
5629mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5630{
5631 int rc;
5632 unsigned long flags;
5633
5634 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5635#ifdef MFCNT
5636 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5637 printk("MF count 0x%x !\n", ioc->mfcnt);
5638#endif
5639
5640 /* Reset the adapter. Prevent more than 1 call to
5641 * mpt_do_ioc_recovery at any instant in time.
5642 */
5643 spin_lock_irqsave(&ioc->diagLock, flags);
5644 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5645 spin_unlock_irqrestore(&ioc->diagLock, flags);
5646 return 0;
5647 } else {
5648 ioc->diagPending = 1;
5649 }
5650 spin_unlock_irqrestore(&ioc->diagLock, flags);
5651
5652 /* FIXME: If do_ioc_recovery fails, repeat....
5653 */
5654
5655 /* The SCSI driver needs to adjust timeouts on all current
5656 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02005657 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 * For all other protocol drivers, this is a no-op.
5659 */
5660 {
5661 int ii;
5662 int r = 0;
5663
5664 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5665 if (MptResetHandlers[ii]) {
5666 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5667 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005668 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 if (ioc->alt_ioc) {
5670 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5671 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005672 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 }
5674 }
5675 }
5676 }
5677
5678 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5679 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5680 rc, ioc->name);
5681 }
5682 ioc->reload_fw = 0;
5683 if (ioc->alt_ioc)
5684 ioc->alt_ioc->reload_fw = 0;
5685
5686 spin_lock_irqsave(&ioc->diagLock, flags);
5687 ioc->diagPending = 0;
5688 if (ioc->alt_ioc)
5689 ioc->alt_ioc->diagPending = 0;
5690 spin_unlock_irqrestore(&ioc->diagLock, flags);
5691
5692 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5693
5694 return rc;
5695}
5696
Eric Moore509e5e52006-04-26 13:22:37 -06005697# define EVENT_DESCR_STR_SZ 100
5698
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005700static void
5701EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702{
Eric Moore509e5e52006-04-26 13:22:37 -06005703 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704
5705 switch(event) {
5706 case MPI_EVENT_NONE:
5707 ds = "None";
5708 break;
5709 case MPI_EVENT_LOG_DATA:
5710 ds = "Log Data";
5711 break;
5712 case MPI_EVENT_STATE_CHANGE:
5713 ds = "State Change";
5714 break;
5715 case MPI_EVENT_UNIT_ATTENTION:
5716 ds = "Unit Attention";
5717 break;
5718 case MPI_EVENT_IOC_BUS_RESET:
5719 ds = "IOC Bus Reset";
5720 break;
5721 case MPI_EVENT_EXT_BUS_RESET:
5722 ds = "External Bus Reset";
5723 break;
5724 case MPI_EVENT_RESCAN:
5725 ds = "Bus Rescan Event";
5726 /* Ok, do we need to do anything here? As far as
5727 I can tell, this is when a new device gets added
5728 to the loop. */
5729 break;
5730 case MPI_EVENT_LINK_STATUS_CHANGE:
5731 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5732 ds = "Link Status(FAILURE) Change";
5733 else
5734 ds = "Link Status(ACTIVE) Change";
5735 break;
5736 case MPI_EVENT_LOOP_STATE_CHANGE:
5737 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5738 ds = "Loop State(LIP) Change";
5739 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005740 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 else
Eric Moore509e5e52006-04-26 13:22:37 -06005742 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 break;
5744 case MPI_EVENT_LOGOUT:
5745 ds = "Logout";
5746 break;
5747 case MPI_EVENT_EVENT_CHANGE:
5748 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06005749 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 else
Eric Moore4f766dc2006-07-11 17:24:07 -06005751 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752 break;
5753 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005754 {
5755 u8 ReasonCode = (u8)(evData0 >> 16);
5756 switch (ReasonCode) {
5757 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5758 ds = "Integrated Raid: Volume Created";
5759 break;
5760 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5761 ds = "Integrated Raid: Volume Deleted";
5762 break;
5763 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5764 ds = "Integrated Raid: Volume Settings Changed";
5765 break;
5766 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5767 ds = "Integrated Raid: Volume Status Changed";
5768 break;
5769 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5770 ds = "Integrated Raid: Volume Physdisk Changed";
5771 break;
5772 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5773 ds = "Integrated Raid: Physdisk Created";
5774 break;
5775 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5776 ds = "Integrated Raid: Physdisk Deleted";
5777 break;
5778 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5779 ds = "Integrated Raid: Physdisk Settings Changed";
5780 break;
5781 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5782 ds = "Integrated Raid: Physdisk Status Changed";
5783 break;
5784 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5785 ds = "Integrated Raid: Domain Validation Needed";
5786 break;
5787 case MPI_EVENT_RAID_RC_SMART_DATA :
5788 ds = "Integrated Raid; Smart Data";
5789 break;
5790 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5791 ds = "Integrated Raid: Replace Action Started";
5792 break;
5793 default:
5794 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005796 }
5797 break;
5798 }
5799 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5800 ds = "SCSI Device Status Change";
5801 break;
5802 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5803 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005804 u8 id = (u8)(evData0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005805 u8 ReasonCode = (u8)(evData0 >> 16);
5806 switch (ReasonCode) {
5807 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005808 snprintf(evStr, EVENT_DESCR_STR_SZ,
5809 "SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005810 break;
5811 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005812 snprintf(evStr, EVENT_DESCR_STR_SZ,
5813 "SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005814 break;
5815 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005816 snprintf(evStr, EVENT_DESCR_STR_SZ,
5817 "SAS Device Status Change: SMART Data: id=%d",
5818 id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005819 break;
5820 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005821 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moore4f766dc2006-07-11 17:24:07 -06005822 "SAS Device Status Change: No Persistancy: id=%d", id);
5823 break;
5824 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
5825 snprintf(evStr, EVENT_DESCR_STR_SZ,
5826 "SAS Device Status Change: Internal Device Reset : id=%d", id);
5827 break;
5828 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
5829 snprintf(evStr, EVENT_DESCR_STR_SZ,
5830 "SAS Device Status Change: Internal Task Abort : id=%d", id);
5831 break;
5832 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
5833 snprintf(evStr, EVENT_DESCR_STR_SZ,
5834 "SAS Device Status Change: Internal Abort Task Set : id=%d", id);
5835 break;
5836 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
5837 snprintf(evStr, EVENT_DESCR_STR_SZ,
5838 "SAS Device Status Change: Internal Clear Task Set : id=%d", id);
5839 break;
5840 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
5841 snprintf(evStr, EVENT_DESCR_STR_SZ,
5842 "SAS Device Status Change: Internal Query Task : id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005843 break;
5844 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005845 snprintf(evStr, EVENT_DESCR_STR_SZ,
5846 "SAS Device Status Change: Unknown: id=%d", id);
5847 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005848 }
5849 break;
5850 }
5851 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5852 ds = "Bus Timer Expired";
5853 break;
5854 case MPI_EVENT_QUEUE_FULL:
5855 ds = "Queue Full";
5856 break;
5857 case MPI_EVENT_SAS_SES:
5858 ds = "SAS SES Event";
5859 break;
5860 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5861 ds = "Persistent Table Full";
5862 break;
5863 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005864 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005865 u8 LinkRates = (u8)(evData0 >> 8);
5866 u8 PhyNumber = (u8)(evData0);
5867 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5868 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5869 switch (LinkRates) {
5870 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06005871 snprintf(evStr, EVENT_DESCR_STR_SZ,
5872 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005873 " Rate Unknown",PhyNumber);
5874 break;
5875 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06005876 snprintf(evStr, EVENT_DESCR_STR_SZ,
5877 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005878 " Phy Disabled",PhyNumber);
5879 break;
5880 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06005881 snprintf(evStr, EVENT_DESCR_STR_SZ,
5882 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005883 " Failed Speed Nego",PhyNumber);
5884 break;
5885 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06005886 snprintf(evStr, EVENT_DESCR_STR_SZ,
5887 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005888 " Sata OOB Completed",PhyNumber);
5889 break;
5890 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06005891 snprintf(evStr, EVENT_DESCR_STR_SZ,
5892 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005893 " Rate 1.5 Gbps",PhyNumber);
5894 break;
5895 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06005896 snprintf(evStr, EVENT_DESCR_STR_SZ,
5897 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005898 " Rate 3.0 Gpbs",PhyNumber);
5899 break;
5900 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005901 snprintf(evStr, EVENT_DESCR_STR_SZ,
5902 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07005903 break;
5904 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005905 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005906 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005907 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5908 ds = "SAS Discovery Error";
5909 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005910 case MPI_EVENT_IR_RESYNC_UPDATE:
5911 {
5912 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06005913 snprintf(evStr, EVENT_DESCR_STR_SZ,
5914 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07005915 break;
5916 }
5917 case MPI_EVENT_IR2:
5918 {
5919 u8 ReasonCode = (u8)(evData0 >> 16);
5920 switch (ReasonCode) {
5921 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5922 ds = "IR2: LD State Changed";
5923 break;
5924 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5925 ds = "IR2: PD State Changed";
5926 break;
5927 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5928 ds = "IR2: Bad Block Table Full";
5929 break;
5930 case MPI_EVENT_IR2_RC_PD_INSERTED:
5931 ds = "IR2: PD Inserted";
5932 break;
5933 case MPI_EVENT_IR2_RC_PD_REMOVED:
5934 ds = "IR2: PD Removed";
5935 break;
5936 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5937 ds = "IR2: Foreign CFG Detected";
5938 break;
5939 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5940 ds = "IR2: Rebuild Medium Error";
5941 break;
5942 default:
5943 ds = "IR2";
5944 break;
5945 }
5946 break;
5947 }
5948 case MPI_EVENT_SAS_DISCOVERY:
5949 {
5950 if (evData0)
5951 ds = "SAS Discovery: Start";
5952 else
5953 ds = "SAS Discovery: Stop";
5954 break;
5955 }
5956 case MPI_EVENT_LOG_ENTRY_ADDED:
5957 ds = "SAS Log Entry Added";
5958 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005959
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 /*
5961 * MPT base "custom" events may be added here...
5962 */
5963 default:
5964 ds = "Unknown";
5965 break;
5966 }
Eric Moore509e5e52006-04-26 13:22:37 -06005967 if (ds)
5968 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969}
5970
5971/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005972/**
5973 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974 * @ioc: Pointer to MPT_ADAPTER structure
5975 * @pEventReply: Pointer to EventNotification reply frame
5976 * @evHandlers: Pointer to integer, number of event handlers
5977 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005978 * Routes a received EventNotificationReply to all currently registered
5979 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 * Returns sum of event handlers return values.
5981 */
5982static int
5983ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5984{
5985 u16 evDataLen;
5986 u32 evData0 = 0;
5987// u32 evCtx;
5988 int ii;
5989 int r = 0;
5990 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06005991 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 u8 event;
5993
5994 /*
5995 * Do platform normalization of values
5996 */
5997 event = le32_to_cpu(pEventReply->Event) & 0xFF;
5998// evCtx = le32_to_cpu(pEventReply->EventContext);
5999 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6000 if (evDataLen) {
6001 evData0 = le32_to_cpu(pEventReply->Data[0]);
6002 }
6003
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006004 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07006005 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006007 event,
6008 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009
Moore, Eric3a892be2006-03-14 09:14:03 -07006010#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6012 for (ii = 0; ii < evDataLen; ii++)
6013 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6014 printk("\n");
6015#endif
6016
6017 /*
6018 * Do general / base driver event processing
6019 */
6020 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6022 if (evDataLen) {
6023 u8 evState = evData0 & 0xFF;
6024
6025 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6026
6027 /* Update EventState field in cached IocFacts */
6028 if (ioc->facts.Function) {
6029 ioc->facts.EventState = evState;
6030 }
6031 }
6032 break;
Moore, Ericece50912006-01-16 18:53:19 -07006033 case MPI_EVENT_INTEGRATED_RAID:
6034 mptbase_raid_process_event_data(ioc,
6035 (MpiEventDataRaid_t *)pEventReply->Data);
6036 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006037 default:
6038 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039 }
6040
6041 /*
6042 * Should this event be logged? Events are written sequentially.
6043 * When buffer is full, start again at the top.
6044 */
6045 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6046 int idx;
6047
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006048 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049
6050 ioc->events[idx].event = event;
6051 ioc->events[idx].eventContext = ioc->eventContext;
6052
6053 for (ii = 0; ii < 2; ii++) {
6054 if (ii < evDataLen)
6055 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6056 else
6057 ioc->events[idx].data[ii] = 0;
6058 }
6059
6060 ioc->eventContext++;
6061 }
6062
6063
6064 /*
6065 * Call each currently registered protocol event handler.
6066 */
6067 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6068 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006069 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 ioc->name, ii));
6071 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6072 handlers++;
6073 }
6074 }
6075 /* FIXME? Examine results here? */
6076
6077 /*
6078 * If needed, send (a single) EventAck.
6079 */
6080 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006081 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006082 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006084 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 ioc->name, ii));
6086 }
6087 }
6088
6089 *evHandlers = handlers;
6090 return r;
6091}
6092
6093/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006094/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6096 * @ioc: Pointer to MPT_ADAPTER structure
6097 * @log_info: U32 LogInfo reply word from the IOC
6098 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006099 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100 */
6101static void
6102mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6103{
6104 static char *subcl_str[8] = {
6105 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6106 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6107 };
6108 u8 subcl = (log_info >> 24) & 0x7;
6109
6110 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6111 ioc->name, log_info, subcl_str[subcl]);
6112}
6113
6114/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006115/**
Moore, Eric335a9412006-01-17 17:06:23 -07006116 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006117 * @ioc: Pointer to MPT_ADAPTER structure
6118 * @mr: Pointer to MPT reply frame
6119 * @log_info: U32 LogInfo word from the IOC
6120 *
6121 * Refer to lsi/sp_log.h.
6122 */
6123static void
Moore, Eric335a9412006-01-17 17:06:23 -07006124mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125{
6126 u32 info = log_info & 0x00FF0000;
6127 char *desc = "unknown";
6128
6129 switch (info) {
6130 case 0x00010000:
6131 desc = "bug! MID not found";
6132 if (ioc->reload_fw == 0)
6133 ioc->reload_fw++;
6134 break;
6135
6136 case 0x00020000:
6137 desc = "Parity Error";
6138 break;
6139
6140 case 0x00030000:
6141 desc = "ASYNC Outbound Overrun";
6142 break;
6143
6144 case 0x00040000:
6145 desc = "SYNC Offset Error";
6146 break;
6147
6148 case 0x00050000:
6149 desc = "BM Change";
6150 break;
6151
6152 case 0x00060000:
6153 desc = "Msg In Overflow";
6154 break;
6155
6156 case 0x00070000:
6157 desc = "DMA Error";
6158 break;
6159
6160 case 0x00080000:
6161 desc = "Outbound DMA Overrun";
6162 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006163
Linus Torvalds1da177e2005-04-16 15:20:36 -07006164 case 0x00090000:
6165 desc = "Task Management";
6166 break;
6167
6168 case 0x000A0000:
6169 desc = "Device Problem";
6170 break;
6171
6172 case 0x000B0000:
6173 desc = "Invalid Phase Change";
6174 break;
6175
6176 case 0x000C0000:
6177 desc = "Untagged Table Size";
6178 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006179
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180 }
6181
6182 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6183}
6184
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006185/* strings for sas loginfo */
6186 static char *originator_str[] = {
6187 "IOP", /* 00h */
6188 "PL", /* 01h */
6189 "IR" /* 02h */
6190 };
6191 static char *iop_code_str[] = {
6192 NULL, /* 00h */
6193 "Invalid SAS Address", /* 01h */
6194 NULL, /* 02h */
6195 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006196 "Diag Message Error", /* 04h */
6197 "Task Terminated", /* 05h */
6198 "Enclosure Management", /* 06h */
6199 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006200 };
6201 static char *pl_code_str[] = {
6202 NULL, /* 00h */
6203 "Open Failure", /* 01h */
6204 "Invalid Scatter Gather List", /* 02h */
6205 "Wrong Relative Offset or Frame Length", /* 03h */
6206 "Frame Transfer Error", /* 04h */
6207 "Transmit Frame Connected Low", /* 05h */
6208 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6209 "SATA Read Log Receive Data Error", /* 07h */
6210 "SATA NCQ Fail All Commands After Error", /* 08h */
6211 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6212 "Receive Frame Invalid Message", /* 0Ah */
6213 "Receive Context Message Valid Error", /* 0Bh */
6214 "Receive Frame Current Frame Error", /* 0Ch */
6215 "SATA Link Down", /* 0Dh */
6216 "Discovery SATA Init W IOS", /* 0Eh */
6217 "Config Invalid Page", /* 0Fh */
6218 "Discovery SATA Init Timeout", /* 10h */
6219 "Reset", /* 11h */
6220 "Abort", /* 12h */
6221 "IO Not Yet Executed", /* 13h */
6222 "IO Executed", /* 14h */
Jan Engelhardt03a67a42006-11-30 05:32:19 +01006223 "Persistent Reservation Out Not Affiliation Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006224 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006225 "IO Device Missing Delay Retry", /* 17h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006226 NULL, /* 18h */
6227 NULL, /* 19h */
6228 NULL, /* 1Ah */
6229 NULL, /* 1Bh */
6230 NULL, /* 1Ch */
6231 NULL, /* 1Dh */
6232 NULL, /* 1Eh */
6233 NULL, /* 1Fh */
6234 "Enclosure Management" /* 20h */
6235 };
6236
6237/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006238/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006239 * mpt_sas_log_info - Log information returned from SAS IOC.
6240 * @ioc: Pointer to MPT_ADAPTER structure
6241 * @log_info: U32 LogInfo reply word from the IOC
6242 *
6243 * Refer to lsi/mpi_log_sas.h.
6244 */
6245static void
6246mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6247{
6248union loginfo_type {
6249 u32 loginfo;
6250 struct {
6251 u32 subcode:16;
6252 u32 code:8;
6253 u32 originator:4;
6254 u32 bus_type:4;
6255 }dw;
6256};
6257 union loginfo_type sas_loginfo;
6258 char *code_desc = NULL;
6259
6260 sas_loginfo.loginfo = log_info;
6261 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6262 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6263 return;
6264 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6265 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6266 code_desc = iop_code_str[sas_loginfo.dw.code];
6267 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6268 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6269 code_desc = pl_code_str[sas_loginfo.dw.code];
6270 }
6271
6272 if (code_desc != NULL)
6273 printk(MYIOC_s_INFO_FMT
6274 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6275 " SubCode(0x%04x)\n",
6276 ioc->name,
6277 log_info,
6278 originator_str[sas_loginfo.dw.originator],
6279 code_desc,
6280 sas_loginfo.dw.subcode);
6281 else
6282 printk(MYIOC_s_INFO_FMT
6283 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6284 " SubCode(0x%04x)\n",
6285 ioc->name,
6286 log_info,
6287 originator_str[sas_loginfo.dw.originator],
6288 sas_loginfo.dw.code,
6289 sas_loginfo.dw.subcode);
6290}
6291
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006293/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6295 * @ioc: Pointer to MPT_ADAPTER structure
6296 * @ioc_status: U32 IOCStatus word from IOC
6297 * @mf: Pointer to MPT request frame
6298 *
6299 * Refer to lsi/mpi.h.
6300 */
6301static void
6302mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6303{
6304 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06006305 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306
6307 switch (status) {
6308 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6309 desc = "Invalid Function";
6310 break;
6311
6312 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6313 desc = "Busy";
6314 break;
6315
6316 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6317 desc = "Invalid SGL";
6318 break;
6319
6320 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6321 desc = "Internal Error";
6322 break;
6323
6324 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6325 desc = "Reserved";
6326 break;
6327
6328 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6329 desc = "Insufficient Resources";
6330 break;
6331
6332 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6333 desc = "Invalid Field";
6334 break;
6335
6336 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6337 desc = "Invalid State";
6338 break;
6339
6340 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6341 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6342 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6343 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6344 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6345 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6346 /* No message for Config IOCStatus values */
6347 break;
6348
6349 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6350 /* No message for recovered error
6351 desc = "SCSI Recovered Error";
6352 */
6353 break;
6354
6355 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6356 desc = "SCSI Invalid Bus";
6357 break;
6358
6359 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6360 desc = "SCSI Invalid TargetID";
6361 break;
6362
6363 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6364 {
6365 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6366 U8 cdb = pScsiReq->CDB[0];
6367 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6368 desc = "SCSI Device Not There";
6369 }
6370 break;
6371 }
6372
6373 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6374 desc = "SCSI Data Overrun";
6375 break;
6376
6377 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006378 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379 desc = "SCSI Data Underrun";
6380 */
6381 break;
6382
6383 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6384 desc = "SCSI I/O Data Error";
6385 break;
6386
6387 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6388 desc = "SCSI Protocol Error";
6389 break;
6390
6391 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6392 desc = "SCSI Task Terminated";
6393 break;
6394
6395 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6396 desc = "SCSI Residual Mismatch";
6397 break;
6398
6399 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6400 desc = "SCSI Task Management Failed";
6401 break;
6402
6403 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6404 desc = "SCSI IOC Terminated";
6405 break;
6406
6407 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6408 desc = "SCSI Ext Terminated";
6409 break;
6410
6411 default:
6412 desc = "Others";
6413 break;
6414 }
Eric Moore4f766dc2006-07-11 17:24:07 -06006415 if (desc != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6417}
6418
6419/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006420EXPORT_SYMBOL(mpt_attach);
6421EXPORT_SYMBOL(mpt_detach);
6422#ifdef CONFIG_PM
6423EXPORT_SYMBOL(mpt_resume);
6424EXPORT_SYMBOL(mpt_suspend);
6425#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006426EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006427EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428EXPORT_SYMBOL(mpt_register);
6429EXPORT_SYMBOL(mpt_deregister);
6430EXPORT_SYMBOL(mpt_event_register);
6431EXPORT_SYMBOL(mpt_event_deregister);
6432EXPORT_SYMBOL(mpt_reset_register);
6433EXPORT_SYMBOL(mpt_reset_deregister);
6434EXPORT_SYMBOL(mpt_device_driver_register);
6435EXPORT_SYMBOL(mpt_device_driver_deregister);
6436EXPORT_SYMBOL(mpt_get_msg_frame);
6437EXPORT_SYMBOL(mpt_put_msg_frame);
6438EXPORT_SYMBOL(mpt_free_msg_frame);
6439EXPORT_SYMBOL(mpt_add_sge);
6440EXPORT_SYMBOL(mpt_send_handshake_request);
6441EXPORT_SYMBOL(mpt_verify_adapter);
6442EXPORT_SYMBOL(mpt_GetIocState);
6443EXPORT_SYMBOL(mpt_print_ioc_summary);
6444EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006445EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446EXPORT_SYMBOL(mpt_HardResetHandler);
6447EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449EXPORT_SYMBOL(mpt_alloc_fw_memory);
6450EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006451EXPORT_SYMBOL(mptbase_sas_persist_operation);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006454/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006455 * fusion_init - Fusion MPT base driver initialization routine.
6456 *
6457 * Returns 0 for success, non-zero for failure.
6458 */
6459static int __init
6460fusion_init(void)
6461{
6462 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006463
6464 show_mptmod_ver(my_NAME, my_VERSION);
6465 printk(KERN_INFO COPYRIGHT "\n");
6466
6467 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6468 MptCallbacks[i] = NULL;
6469 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6470 MptEvHandlers[i] = NULL;
6471 MptResetHandlers[i] = NULL;
6472 }
6473
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006474 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006475 * EventNotification handling.
6476 */
6477 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6478
6479 /* Register for hard reset handling callbacks.
6480 */
6481 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6482 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6483 } else {
6484 /* FIXME! */
6485 }
6486
6487#ifdef CONFIG_PROC_FS
6488 (void) procmpt_create();
6489#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006490 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491}
6492
6493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006494/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495 * fusion_exit - Perform driver unload cleanup.
6496 *
6497 * This routine frees all resources associated with each MPT adapter
6498 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6499 */
6500static void __exit
6501fusion_exit(void)
6502{
6503
6504 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6505
Linus Torvalds1da177e2005-04-16 15:20:36 -07006506 mpt_reset_deregister(mpt_base_index);
6507
6508#ifdef CONFIG_PROC_FS
6509 procmpt_destroy();
6510#endif
6511}
6512
Linus Torvalds1da177e2005-04-16 15:20:36 -07006513module_init(fusion_init);
6514module_exit(fusion_exit);