blob: a3f9275ebe58236f376a3b4b23bd345ded72aae7 [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 *
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008 * Copyright (c) 1999-2005 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");
76
77/*
78 * cmd line parameters
79 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000080static int mpt_msi_enable;
81module_param(mpt_msi_enable, int, 0);
82MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084#ifdef MFCNT
85static int mfcounter = 0;
86#define PRINT_MF_COUNT 20000
87#endif
88
89/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
90/*
91 * Public data...
92 */
93int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080094int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Linus Torvaldsf7473072005-11-29 14:21:57 -080096struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98#define WHOINIT_UNKNOWN 0xAA
99
100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
101/*
102 * Private data...
103 */
104 /* Adapter link list */
105LIST_HEAD(ioc_list);
106 /* Callback lookup table */
107static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
108 /* Protocol driver class lookup table */
109static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
110 /* Event handler lookup table */
111static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
112 /* Reset handler lookup table */
113static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
114static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
115
116static int mpt_base_index = -1;
117static int last_drv_idx = -1;
118
119static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
120
121/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
122/*
123 * Forward protos...
124 */
125static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
126static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
127static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
128 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
129 int sleepFlag);
130static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
131static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
132static void mpt_adapter_disable(MPT_ADAPTER *ioc);
133static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
134
135static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
136static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
138static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
139static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
140static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
141static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200142static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
144static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
145static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
146static int PrimeIocFifos(MPT_ADAPTER *ioc);
147static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
148static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
149static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
150static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200152int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
154static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
155static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
156static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
157static void mpt_timer_expired(unsigned long data);
158static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
159static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200160static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
161static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163#ifdef CONFIG_PROC_FS
164static int procmpt_summary_read(char *buf, char **start, off_t offset,
165 int request, int *eof, void *data);
166static int procmpt_version_read(char *buf, char **start, off_t offset,
167 int request, int *eof, void *data);
168static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
169 int request, int *eof, void *data);
170#endif
171static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
172
173//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
174static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
175static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
176static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700177static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600178static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700179static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182static int __init fusion_init (void);
183static void __exit fusion_exit (void);
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185#define CHIPREG_READ32(addr) readl_relaxed(addr)
186#define CHIPREG_READ32_dmasync(addr) readl(addr)
187#define CHIPREG_WRITE32(addr,val) writel(val, addr)
188#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
189#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
190
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600191static void
192pci_disable_io_access(struct pci_dev *pdev)
193{
194 u16 command_reg;
195
196 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
197 command_reg &= ~1;
198 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
199}
200
201static void
202pci_enable_io_access(struct pci_dev *pdev)
203{
204 u16 command_reg;
205
206 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
207 command_reg |= 1;
208 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
209}
210
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600211/*
212 * Process turbo (context) reply...
213 */
214static void
215mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
216{
217 MPT_FRAME_HDR *mf = NULL;
218 MPT_FRAME_HDR *mr = NULL;
219 int req_idx = 0;
220 int cb_idx;
221
222 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
223 ioc->name, pa));
224
225 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
226 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
227 req_idx = pa & 0x0000FFFF;
228 cb_idx = (pa & 0x00FF0000) >> 16;
229 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
230 break;
231 case MPI_CONTEXT_REPLY_TYPE_LAN:
232 cb_idx = mpt_lan_index;
233 /*
234 * Blind set of mf to NULL here was fatal
235 * after lan_reply says "freeme"
236 * Fix sort of combined with an optimization here;
237 * added explicit check for case where lan_reply
238 * was just returning 1 and doing nothing else.
239 * For this case skip the callback, but set up
240 * proper mf value first here:-)
241 */
242 if ((pa & 0x58000000) == 0x58000000) {
243 req_idx = pa & 0x0000FFFF;
244 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
245 mpt_free_msg_frame(ioc, mf);
246 mb();
247 return;
248 break;
249 }
250 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
251 break;
252 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
253 cb_idx = mpt_stm_index;
254 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
255 break;
256 default:
257 cb_idx = 0;
258 BUG();
259 }
260
261 /* Check for (valid) IO callback! */
262 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
263 MptCallbacks[cb_idx] == NULL) {
264 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
265 __FUNCTION__, ioc->name, cb_idx);
266 goto out;
267 }
268
269 if (MptCallbacks[cb_idx](ioc, mf, mr))
270 mpt_free_msg_frame(ioc, mf);
271 out:
272 mb();
273}
274
275static void
276mpt_reply(MPT_ADAPTER *ioc, u32 pa)
277{
278 MPT_FRAME_HDR *mf;
279 MPT_FRAME_HDR *mr;
280 int req_idx;
281 int cb_idx;
282 int freeme;
283
284 u32 reply_dma_low;
285 u16 ioc_stat;
286
287 /* non-TURBO reply! Hmmm, something may be up...
288 * Newest turbo reply mechanism; get address
289 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
290 */
291
292 /* Map DMA address of reply header to cpu address.
293 * pa is 32 bits - but the dma address may be 32 or 64 bits
294 * get offset based only only the low addresses
295 */
296
297 reply_dma_low = (pa <<= 1);
298 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
299 (reply_dma_low - ioc->reply_frames_low_dma));
300
301 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
302 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
303 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
304
305 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
306 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
307 DBG_DUMP_REPLY_FRAME(mr)
308
309 /* Check/log IOC log info
310 */
311 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
312 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
313 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
314 if (ioc->bus_type == FC)
315 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700316 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700317 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600318 else if (ioc->bus_type == SAS)
319 mpt_sas_log_info(ioc, log_info);
320 }
321 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700322 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600323 cb_idx != mpt_stm_index &&
324 cb_idx != mpt_lan_index)
325 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
326 }
327
328
329 /* Check for (valid) IO callback! */
330 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
331 MptCallbacks[cb_idx] == NULL) {
332 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
333 __FUNCTION__, ioc->name, cb_idx);
334 freeme = 0;
335 goto out;
336 }
337
338 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
339
340 out:
341 /* Flush (non-TURBO) reply with a WRITE! */
342 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
343
344 if (freeme)
345 mpt_free_msg_frame(ioc, mf);
346 mb();
347}
348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
350/*
351 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
352 * @irq: irq number (not used)
353 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
354 * @r: pt_regs pointer (not used)
355 *
356 * This routine is registered via the request_irq() kernel API call,
357 * and handles all interrupts generated from a specific MPT adapter
358 * (also referred to as a IO Controller or IOC).
359 * This routine must clear the interrupt from the adapter and does
360 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200361 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 *
363 * This routine handles register-level access of the adapter but
364 * dispatches (calls) a protocol-specific callback routine to handle
365 * the protocol-specific details of the MPT request completion.
366 */
367static irqreturn_t
368mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
369{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600370 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600371 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
372
373 if (pa == 0xFFFFFFFF)
374 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 /*
377 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600379 do {
380 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600381 mpt_reply(ioc, pa);
382 else
383 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600384 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
385 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 return IRQ_HANDLED;
388}
389
390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
391/*
392 * mpt_base_reply - MPT base driver's callback routine; all base driver
393 * "internal" request/reply processing is routed here.
394 * Currently used for EventNotification and EventAck handling.
395 * @ioc: Pointer to MPT_ADAPTER structure
396 * @mf: Pointer to original MPT request frame
397 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
398 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200399 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 * should be freed, or 0 if it shouldn't.
401 */
402static int
403mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
404{
405 int freereq = 1;
406 u8 func;
407
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200408 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200410#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
412 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
413 DBG_DUMP_REQUEST_FRAME_HDR(mf)
414 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200415#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
417 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200418 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 ioc->name, func));
420
421 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
422 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
423 int evHandlers = 0;
424 int results;
425
426 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
427 if (results != evHandlers) {
428 /* CHECKME! Any special handling needed here? */
Moore, Eric3a892be2006-03-14 09:14:03 -0700429 devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 ioc->name, evHandlers, results));
431 }
432
433 /*
434 * Hmmm... It seems that EventNotificationReply is an exception
435 * to the rule of one reply per request.
436 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200437 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200439 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700440 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200441 ioc->name, pEvReply));
442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444#ifdef CONFIG_PROC_FS
445// LogEvent(ioc, pEvReply);
446#endif
447
448 } else if (func == MPI_FUNCTION_EVENT_ACK) {
449 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
450 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700451 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 CONFIGPARMS *pCfg;
453 unsigned long flags;
454
455 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
456 ioc->name, mf, reply));
457
458 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
459
460 if (pCfg) {
461 /* disable timer and remove from linked list */
462 del_timer(&pCfg->timer);
463
464 spin_lock_irqsave(&ioc->FreeQlock, flags);
465 list_del(&pCfg->linkage);
466 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
467
468 /*
469 * If IOC Status is SUCCESS, save the header
470 * and set the status code to GOOD.
471 */
472 pCfg->status = MPT_CONFIG_ERROR;
473 if (reply) {
474 ConfigReply_t *pReply = (ConfigReply_t *)reply;
475 u16 status;
476
477 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
478 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
479 status, le32_to_cpu(pReply->IOCLogInfo)));
480
481 pCfg->status = status;
482 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200483 if ((pReply->Header.PageType &
484 MPI_CONFIG_PAGETYPE_MASK) ==
485 MPI_CONFIG_PAGETYPE_EXTENDED) {
486 pCfg->cfghdr.ehdr->ExtPageLength =
487 le16_to_cpu(pReply->ExtPageLength);
488 pCfg->cfghdr.ehdr->ExtPageType =
489 pReply->ExtPageType;
490 }
491 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
492
493 /* If this is a regular header, save PageLength. */
494 /* LMP Do this better so not using a reserved field! */
495 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
496 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
497 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 }
499 }
500
501 /*
502 * Wake up the original calling thread
503 */
504 pCfg->wait_done = 1;
505 wake_up(&mpt_waitq);
506 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200507 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
508 /* we should be always getting a reply frame */
509 memcpy(ioc->persist_reply_frame, reply,
510 min(MPT_DEFAULT_FRAME_SIZE,
511 4*reply->u.reply.MsgLength));
512 del_timer(&ioc->persist_timer);
513 ioc->persist_wait_done = 1;
514 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 } else {
516 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
517 ioc->name, func);
518 }
519
520 /*
521 * Conditionally tell caller to free the original
522 * EventNotification/EventAck/unexpected request frame!
523 */
524 return freereq;
525}
526
527/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
528/**
529 * mpt_register - Register protocol-specific main callback handler.
530 * @cbfunc: callback function pointer
531 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
532 *
533 * This routine is called by a protocol-specific driver (SCSI host,
534 * LAN, SCSI target) to register it's reply callback routine. Each
535 * protocol-specific driver must do this before it will be able to
536 * use any IOC resources, such as obtaining request frames.
537 *
538 * NOTES: The SCSI protocol driver currently calls this routine thrice
539 * in order to register separate callbacks; one for "normal" SCSI IO;
540 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
541 *
542 * Returns a positive integer valued "handle" in the
543 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
544 * Any non-positive return value (including zero!) should be considered
545 * an error by the caller.
546 */
547int
548mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
549{
550 int i;
551
552 last_drv_idx = -1;
553
554 /*
555 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
556 * (slot/handle 0 is reserved!)
557 */
558 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
559 if (MptCallbacks[i] == NULL) {
560 MptCallbacks[i] = cbfunc;
561 MptDriverClass[i] = dclass;
562 MptEvHandlers[i] = NULL;
563 last_drv_idx = i;
564 break;
565 }
566 }
567
568 return last_drv_idx;
569}
570
571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
572/**
573 * mpt_deregister - Deregister a protocol drivers resources.
574 * @cb_idx: previously registered callback handle
575 *
576 * Each protocol-specific driver should call this routine when it's
577 * module is unloaded.
578 */
579void
580mpt_deregister(int cb_idx)
581{
582 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
583 MptCallbacks[cb_idx] = NULL;
584 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
585 MptEvHandlers[cb_idx] = NULL;
586
587 last_drv_idx++;
588 }
589}
590
591/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
592/**
593 * mpt_event_register - Register protocol-specific event callback
594 * handler.
595 * @cb_idx: previously registered (via mpt_register) callback handle
596 * @ev_cbfunc: callback function
597 *
598 * This routine can be called by one or more protocol-specific drivers
599 * if/when they choose to be notified of MPT events.
600 *
601 * Returns 0 for success.
602 */
603int
604mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
605{
606 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
607 return -1;
608
609 MptEvHandlers[cb_idx] = ev_cbfunc;
610 return 0;
611}
612
613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
614/**
615 * mpt_event_deregister - Deregister protocol-specific event callback
616 * handler.
617 * @cb_idx: previously registered callback handle
618 *
619 * Each protocol-specific driver should call this routine
620 * when it does not (or can no longer) handle events,
621 * or when it's module is unloaded.
622 */
623void
624mpt_event_deregister(int cb_idx)
625{
626 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
627 return;
628
629 MptEvHandlers[cb_idx] = NULL;
630}
631
632/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
633/**
634 * mpt_reset_register - Register protocol-specific IOC reset handler.
635 * @cb_idx: previously registered (via mpt_register) callback handle
636 * @reset_func: reset function
637 *
638 * This routine can be called by one or more protocol-specific drivers
639 * if/when they choose to be notified of IOC resets.
640 *
641 * Returns 0 for success.
642 */
643int
644mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
645{
646 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
647 return -1;
648
649 MptResetHandlers[cb_idx] = reset_func;
650 return 0;
651}
652
653/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
654/**
655 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
656 * @cb_idx: previously registered callback handle
657 *
658 * Each protocol-specific driver should call this routine
659 * when it does not (or can no longer) handle IOC reset handling,
660 * or when it's module is unloaded.
661 */
662void
663mpt_reset_deregister(int cb_idx)
664{
665 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
666 return;
667
668 MptResetHandlers[cb_idx] = NULL;
669}
670
671/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
672/**
673 * mpt_device_driver_register - Register device driver hooks
674 */
675int
676mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
677{
678 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600679 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Eric Moored58b2722006-07-11 17:23:23 -0600681 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400682 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
685
686 /* call per pci device probe entry point */
687 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600688 id = ioc->pcidev->driver ?
689 ioc->pcidev->driver->id_table : NULL;
690 if (dd_cbfunc->probe)
691 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 }
693
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400694 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
697/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
698/**
699 * mpt_device_driver_deregister - DeRegister device driver hooks
700 */
701void
702mpt_device_driver_deregister(int cb_idx)
703{
704 struct mpt_pci_driver *dd_cbfunc;
705 MPT_ADAPTER *ioc;
706
707 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
708 return;
709
710 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
711
712 list_for_each_entry(ioc, &ioc_list, list) {
713 if (dd_cbfunc->remove)
714 dd_cbfunc->remove(ioc->pcidev);
715 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 MptDeviceDriverHandlers[cb_idx] = NULL;
718}
719
720
721/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
722/**
723 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
724 * allocated per MPT adapter.
725 * @handle: Handle of registered MPT protocol driver
726 * @ioc: Pointer to MPT adapter structure
727 *
728 * Returns pointer to a MPT request frame or %NULL if none are available
729 * or IOC is not active.
730 */
731MPT_FRAME_HDR*
732mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
733{
734 MPT_FRAME_HDR *mf;
735 unsigned long flags;
736 u16 req_idx; /* Request index */
737
738 /* validate handle and ioc identifier */
739
740#ifdef MFCNT
741 if (!ioc->active)
742 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
743#endif
744
745 /* If interrupts are not attached, do not return a request frame */
746 if (!ioc->active)
747 return NULL;
748
749 spin_lock_irqsave(&ioc->FreeQlock, flags);
750 if (!list_empty(&ioc->FreeQ)) {
751 int req_offset;
752
753 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
754 u.frame.linkage.list);
755 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200756 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
758 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
759 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500760 req_idx = req_offset / ioc->req_sz;
761 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
763 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
764#ifdef MFCNT
765 ioc->mfcnt++;
766#endif
767 }
768 else
769 mf = NULL;
770 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
771
772#ifdef MFCNT
773 if (mf == NULL)
774 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
775 mfcounter++;
776 if (mfcounter == PRINT_MF_COUNT)
777 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
778#endif
779
780 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
781 ioc->name, handle, ioc->id, mf));
782 return mf;
783}
784
785/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
786/**
787 * mpt_put_msg_frame - Send a protocol specific MPT request frame
788 * to a IOC.
789 * @handle: Handle of registered MPT protocol driver
790 * @ioc: Pointer to MPT adapter structure
791 * @mf: Pointer to MPT request frame
792 *
793 * This routine posts a MPT request frame to the request post FIFO of a
794 * specific MPT adapter.
795 */
796void
797mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
798{
799 u32 mf_dma_addr;
800 int req_offset;
801 u16 req_idx; /* Request index */
802
803 /* ensure values are reset properly! */
804 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
805 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
806 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500807 req_idx = req_offset / ioc->req_sz;
808 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
810
811#ifdef MPT_DEBUG_MSG_FRAME
812 {
813 u32 *m = mf->u.frame.hwhdr.__hdr;
814 int ii, n;
815
816 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
817 ioc->name, m);
818 n = ioc->req_sz/4 - 1;
819 while (m[n] == 0)
820 n--;
821 for (ii=0; ii<=n; ii++) {
822 if (ii && ((ii%8)==0))
823 printk("\n" KERN_INFO " ");
824 printk(" %08x", le32_to_cpu(m[ii]));
825 }
826 printk("\n");
827 }
828#endif
829
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200830 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 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]));
832 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
833}
834
835/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
836/**
837 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
838 * @handle: Handle of registered MPT protocol driver
839 * @ioc: Pointer to MPT adapter structure
840 * @mf: Pointer to MPT request frame
841 *
842 * This routine places a MPT request frame back on the MPT adapter's
843 * FreeQ.
844 */
845void
846mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
847{
848 unsigned long flags;
849
850 /* Put Request back on FreeQ! */
851 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200852 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
854#ifdef MFCNT
855 ioc->mfcnt--;
856#endif
857 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
858}
859
860/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
861/**
862 * mpt_add_sge - Place a simple SGE at address pAddr.
863 * @pAddr: virtual address for SGE
864 * @flagslength: SGE flags and data transfer length
865 * @dma_addr: Physical address
866 *
867 * This routine places a MPT request frame back on the MPT adapter's
868 * FreeQ.
869 */
870void
871mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
872{
873 if (sizeof(dma_addr_t) == sizeof(u64)) {
874 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
875 u32 tmp = dma_addr & 0xFFFFFFFF;
876
877 pSge->FlagsLength = cpu_to_le32(flagslength);
878 pSge->Address.Low = cpu_to_le32(tmp);
879 tmp = (u32) ((u64)dma_addr >> 32);
880 pSge->Address.High = cpu_to_le32(tmp);
881
882 } else {
883 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
884 pSge->FlagsLength = cpu_to_le32(flagslength);
885 pSge->Address = cpu_to_le32(dma_addr);
886 }
887}
888
889/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
890/**
891 * mpt_send_handshake_request - Send MPT request via doorbell
892 * handshake method.
893 * @handle: Handle of registered MPT protocol driver
894 * @ioc: Pointer to MPT adapter structure
895 * @reqBytes: Size of the request in bytes
896 * @req: Pointer to MPT request frame
897 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
898 *
899 * This routine is used exclusively to send MptScsiTaskMgmt
900 * requests since they are required to be sent via doorbell handshake.
901 *
902 * NOTE: It is the callers responsibility to byte-swap fields in the
903 * request which are greater than 1 byte in size.
904 *
905 * Returns 0 for success, non-zero for failure.
906 */
907int
908mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
909{
910 int r = 0;
911 u8 *req_as_bytes;
912 int ii;
913
914 /* State is known to be good upon entering
915 * this function so issue the bus reset
916 * request.
917 */
918
919 /*
920 * Emulate what mpt_put_msg_frame() does /wrt to sanity
921 * setting cb_idx/req_idx. But ONLY if this request
922 * is in proper (pre-alloc'd) request buffer range...
923 */
924 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
925 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
926 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
927 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
928 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
929 }
930
931 /* Make sure there are no doorbells */
932 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 CHIPREG_WRITE32(&ioc->chip->Doorbell,
935 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
936 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
937
938 /* Wait for IOC doorbell int */
939 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
940 return ii;
941 }
942
943 /* Read doorbell and check for active bit */
944 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
945 return -5;
946
947 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200948 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
951
952 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
953 return -2;
954 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200955
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 /* Send request via doorbell handshake */
957 req_as_bytes = (u8 *) req;
958 for (ii = 0; ii < reqBytes/4; ii++) {
959 u32 word;
960
961 word = ((req_as_bytes[(ii*4) + 0] << 0) |
962 (req_as_bytes[(ii*4) + 1] << 8) |
963 (req_as_bytes[(ii*4) + 2] << 16) |
964 (req_as_bytes[(ii*4) + 3] << 24));
965 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
966 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
967 r = -3;
968 break;
969 }
970 }
971
972 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
973 r = 0;
974 else
975 r = -4;
976
977 /* Make sure there are no doorbells */
978 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200979
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 return r;
981}
982
983/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
984/**
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200985 * mpt_host_page_access_control - provides mechanism for the host
986 * driver to control the IOC's Host Page Buffer access.
987 * @ioc: Pointer to MPT adapter structure
988 * @access_control_value: define bits below
989 *
990 * Access Control Value - bits[15:12]
991 * 0h Reserved
992 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
993 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
994 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
995 *
996 * Returns 0 for success, non-zero for failure.
997 */
998
999static int
1000mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1001{
1002 int r = 0;
1003
1004 /* return if in use */
1005 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1006 & MPI_DOORBELL_ACTIVE)
1007 return -1;
1008
1009 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1010
1011 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1012 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1013 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1014 (access_control_value<<12)));
1015
1016 /* Wait for IOC to clear Doorbell Status bit */
1017 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1018 return -2;
1019 }else
1020 return 0;
1021}
1022
1023/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1024/**
1025 * mpt_host_page_alloc - allocate system memory for the fw
1026 * If we already allocated memory in past, then resend the same pointer.
1027 * ioc@: Pointer to pointer to IOC adapter
1028 * ioc_init@: Pointer to ioc init config page
1029 *
1030 * Returns 0 for success, non-zero for failure.
1031 */
1032static int
1033mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1034{
1035 char *psge;
1036 int flags_length;
1037 u32 host_page_buffer_sz=0;
1038
1039 if(!ioc->HostPageBuffer) {
1040
1041 host_page_buffer_sz =
1042 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1043
1044 if(!host_page_buffer_sz)
1045 return 0; /* fw doesn't need any host buffers */
1046
1047 /* spin till we get enough memory */
1048 while(host_page_buffer_sz > 0) {
1049
1050 if((ioc->HostPageBuffer = pci_alloc_consistent(
1051 ioc->pcidev,
1052 host_page_buffer_sz,
1053 &ioc->HostPageBuffer_dma)) != NULL) {
1054
1055 dinitprintk((MYIOC_s_INFO_FMT
1056 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
1057 ioc->name,
1058 ioc->HostPageBuffer,
1059 ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001060 host_page_buffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001061 ioc->alloc_total += host_page_buffer_sz;
1062 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1063 break;
1064 }
1065
1066 host_page_buffer_sz -= (4*1024);
1067 }
1068 }
1069
1070 if(!ioc->HostPageBuffer) {
1071 printk(MYIOC_s_ERR_FMT
1072 "Failed to alloc memory for host_page_buffer!\n",
1073 ioc->name);
1074 return -999;
1075 }
1076
1077 psge = (char *)&ioc_init->HostPageBufferSGE;
1078 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1079 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1080 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1081 MPI_SGE_FLAGS_HOST_TO_IOC |
1082 MPI_SGE_FLAGS_END_OF_BUFFER;
1083 if (sizeof(dma_addr_t) == sizeof(u64)) {
1084 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1085 }
1086 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1087 flags_length |= ioc->HostPageBuffer_sz;
1088 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1089 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1090
1091return 0;
1092}
1093
1094/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1095/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
1097 * the associated MPT adapter structure.
1098 * @iocid: IOC unique identifier (integer)
1099 * @iocpp: Pointer to pointer to IOC adapter
1100 *
1101 * Returns iocid and sets iocpp.
1102 */
1103int
1104mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1105{
1106 MPT_ADAPTER *ioc;
1107
1108 list_for_each_entry(ioc,&ioc_list,list) {
1109 if (ioc->id == iocid) {
1110 *iocpp =ioc;
1111 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001114
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 *iocpp = NULL;
1116 return -1;
1117}
1118
1119/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1120/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001121 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 * @pdev: Pointer to pci_dev structure
1123 *
1124 * This routine performs all the steps necessary to bring the IOC of
1125 * a MPT adapter to a OPERATIONAL state. This includes registering
1126 * memory regions, registering the interrupt, and allocating request
1127 * and reply memory pools.
1128 *
1129 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1130 * MPT adapter.
1131 *
1132 * Returns 0 for success, non-zero for failure.
1133 *
1134 * TODO: Add support for polled controllers
1135 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001136int
1137mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
1139 MPT_ADAPTER *ioc;
1140 u8 __iomem *mem;
1141 unsigned long mem_phys;
1142 unsigned long port;
1143 u32 msize;
1144 u32 psize;
1145 int ii;
1146 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 u8 revision;
1148 u8 pcixcmd;
1149 static int mpt_ids = 0;
1150#ifdef CONFIG_PROC_FS
1151 struct proc_dir_entry *dent, *ent;
1152#endif
1153
1154 if (pci_enable_device(pdev))
1155 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001156
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001158
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001159 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 dprintk((KERN_INFO MYNAM
1161 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001162 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1164 return r;
1165 }
1166
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001167 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 dprintk((KERN_INFO MYNAM
1169 ": Using 64 bit consistent mask\n"));
1170 else
1171 dprintk((KERN_INFO MYNAM
1172 ": Not using 64 bit consistent mask\n"));
1173
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001174 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 if (ioc == NULL) {
1176 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1177 return -ENOMEM;
1178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 ioc->alloc_total = sizeof(MPT_ADAPTER);
1180 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1181 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001182
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 ioc->pcidev = pdev;
1184 ioc->diagPending = 0;
1185 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001186 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
1188 /* Initialize the event logging.
1189 */
1190 ioc->eventTypes = 0; /* None */
1191 ioc->eventContext = 0;
1192 ioc->eventLogSize = 0;
1193 ioc->events = NULL;
1194
1195#ifdef MFCNT
1196 ioc->mfcnt = 0;
1197#endif
1198
1199 ioc->cached_fw = NULL;
1200
1201 /* Initilize SCSI Config Data structure
1202 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001203 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
1205 /* Initialize the running configQ head.
1206 */
1207 INIT_LIST_HEAD(&ioc->configQ);
1208
Michael Reed05e8ec12006-01-13 14:31:54 -06001209 /* Initialize the fc rport list head.
1210 */
1211 INIT_LIST_HEAD(&ioc->fc_rports);
1212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 /* Find lookup slot. */
1214 INIT_LIST_HEAD(&ioc->list);
1215 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001216
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 mem_phys = msize = 0;
1218 port = psize = 0;
1219 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1220 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001221 if (psize)
1222 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 /* Get I/O space! */
1224 port = pci_resource_start(pdev, ii);
1225 psize = pci_resource_len(pdev,ii);
1226 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001227 if (msize)
1228 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 /* Get memmap */
1230 mem_phys = pci_resource_start(pdev, ii);
1231 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 }
1233 }
1234 ioc->mem_size = msize;
1235
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 mem = NULL;
1237 /* Get logical ptr for PciMem0 space */
1238 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001239 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 if (mem == NULL) {
1241 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1242 kfree(ioc);
1243 return -EINVAL;
1244 }
1245 ioc->memmap = mem;
1246 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1247
1248 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1249 &ioc->facts, &ioc->pfacts[0]));
1250
1251 ioc->mem_phys = mem_phys;
1252 ioc->chip = (SYSIF_REGS __iomem *)mem;
1253
1254 /* Save Port IO values in case we need to do downloadboot */
1255 {
1256 u8 *pmem = (u8*)port;
1257 ioc->pio_mem_phys = port;
1258 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1259 }
1260
1261 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1262 ioc->prod_name = "LSIFC909";
1263 ioc->bus_type = FC;
1264 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001265 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 ioc->prod_name = "LSIFC929";
1267 ioc->bus_type = FC;
1268 }
1269 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1270 ioc->prod_name = "LSIFC919";
1271 ioc->bus_type = FC;
1272 }
1273 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1274 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1275 ioc->bus_type = FC;
1276 if (revision < XL_929) {
1277 ioc->prod_name = "LSIFC929X";
1278 /* 929X Chip Fix. Set Split transactions level
1279 * for PCIX. Set MOST bits to zero.
1280 */
1281 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1282 pcixcmd &= 0x8F;
1283 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1284 } else {
1285 ioc->prod_name = "LSIFC929XL";
1286 /* 929XL Chip Fix. Set MMRBC to 0x08.
1287 */
1288 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1289 pcixcmd |= 0x08;
1290 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1291 }
1292 }
1293 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1294 ioc->prod_name = "LSIFC919X";
1295 ioc->bus_type = FC;
1296 /* 919X Chip Fix. Set Split transactions level
1297 * for PCIX. Set MOST bits to zero.
1298 */
1299 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1300 pcixcmd &= 0x8F;
1301 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1302 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001303 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1304 ioc->prod_name = "LSIFC939X";
1305 ioc->bus_type = FC;
1306 ioc->errata_flag_1064 = 1;
1307 }
1308 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1309 ioc->prod_name = "LSIFC949X";
1310 ioc->bus_type = FC;
1311 ioc->errata_flag_1064 = 1;
1312 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001313 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1314 ioc->prod_name = "LSIFC949E";
1315 ioc->bus_type = FC;
1316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1318 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001319 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 /* 1030 Chip Fix. Disable Split transactions
1321 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1322 */
1323 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1324 if (revision < C0_1030) {
1325 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1326 pcixcmd &= 0x8F;
1327 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1328 }
1329 }
1330 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1331 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001332 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001334 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1335 ioc->prod_name = "LSISAS1064";
1336 ioc->bus_type = SAS;
1337 ioc->errata_flag_1064 = 1;
1338 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001339 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1340 ioc->prod_name = "LSISAS1068";
1341 ioc->bus_type = SAS;
1342 ioc->errata_flag_1064 = 1;
1343 }
1344 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1345 ioc->prod_name = "LSISAS1064E";
1346 ioc->bus_type = SAS;
1347 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001348 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1349 ioc->prod_name = "LSISAS1068E";
1350 ioc->bus_type = SAS;
1351 }
Eric Moore87cf8982006-06-27 16:09:26 -06001352 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
1353 ioc->prod_name = "LSISAS1078";
1354 ioc->bus_type = SAS;
1355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001357 if (ioc->errata_flag_1064)
1358 pci_disable_io_access(pdev);
1359
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 sprintf(ioc->name, "ioc%d", ioc->id);
1361
1362 spin_lock_init(&ioc->FreeQlock);
1363
1364 /* Disable all! */
1365 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1366 ioc->active = 0;
1367 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1368
1369 /* Set lookup ptr. */
1370 list_add_tail(&ioc->list, &ioc_list);
1371
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001372 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 */
1374 mpt_detect_bound_ports(ioc, pdev);
1375
James Bottomleyc92f2222006-03-01 09:02:49 -06001376 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1377 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 printk(KERN_WARNING MYNAM
1379 ": WARNING - %s did not initialize properly! (%d)\n",
1380 ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001382 if (ioc->alt_ioc)
1383 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 iounmap(mem);
1385 kfree(ioc);
1386 pci_set_drvdata(pdev, NULL);
1387 return r;
1388 }
1389
1390 /* call per device driver probe entry point */
1391 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1392 if(MptDeviceDriverHandlers[ii] &&
1393 MptDeviceDriverHandlers[ii]->probe) {
1394 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1395 }
1396 }
1397
1398#ifdef CONFIG_PROC_FS
1399 /*
1400 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1401 */
1402 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1403 if (dent) {
1404 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1405 if (ent) {
1406 ent->read_proc = procmpt_iocinfo_read;
1407 ent->data = ioc;
1408 }
1409 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1410 if (ent) {
1411 ent->read_proc = procmpt_summary_read;
1412 ent->data = ioc;
1413 }
1414 }
1415#endif
1416
1417 return 0;
1418}
1419
1420/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1421/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001422 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 * @pdev: Pointer to pci_dev structure
1424 *
1425 */
1426
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001427void
1428mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429{
1430 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1431 char pname[32];
1432 int ii;
1433
1434 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1435 remove_proc_entry(pname, NULL);
1436 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1437 remove_proc_entry(pname, NULL);
1438 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1439 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 /* call per device driver remove entry point */
1442 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1443 if(MptDeviceDriverHandlers[ii] &&
1444 MptDeviceDriverHandlers[ii]->remove) {
1445 MptDeviceDriverHandlers[ii]->remove(pdev);
1446 }
1447 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001448
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 /* Disable interrupts! */
1450 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1451
1452 ioc->active = 0;
1453 synchronize_irq(pdev->irq);
1454
1455 /* Clear any lingering interrupt */
1456 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1457
1458 CHIPREG_READ32(&ioc->chip->IntStatus);
1459
1460 mpt_adapter_dispose(ioc);
1461
1462 pci_set_drvdata(pdev, NULL);
1463}
1464
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465/**************************************************************************
1466 * Power Management
1467 */
1468#ifdef CONFIG_PM
1469/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1470/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001471 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 *
1473 *
1474 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001475int
1476mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477{
1478 u32 device_state;
1479 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480
Pavel Machek2a569572005-07-07 17:56:40 -07001481 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
1483 printk(MYIOC_s_INFO_FMT
1484 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1485 ioc->name, pdev, pci_name(pdev), device_state);
1486
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 pci_save_state(pdev);
1488
1489 /* put ioc into READY_STATE */
1490 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1491 printk(MYIOC_s_ERR_FMT
1492 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1493 }
1494
1495 /* disable interrupts */
1496 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1497 ioc->active = 0;
1498
1499 /* Clear any lingering interrupt */
1500 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1501
1502 pci_disable_device(pdev);
1503 pci_set_power_state(pdev, device_state);
1504
1505 return 0;
1506}
1507
1508/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1509/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001510 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 *
1512 *
1513 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001514int
1515mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
1517 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1518 u32 device_state = pdev->current_state;
1519 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001520
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 printk(MYIOC_s_INFO_FMT
1522 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1523 ioc->name, pdev, pci_name(pdev), device_state);
1524
1525 pci_set_power_state(pdev, 0);
1526 pci_restore_state(pdev);
1527 pci_enable_device(pdev);
1528
1529 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001530 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 ioc->active = 1;
1532
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 printk(MYIOC_s_INFO_FMT
1534 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1535 ioc->name,
1536 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1537 CHIPREG_READ32(&ioc->chip->Doorbell));
1538
1539 /* bring ioc to operational state */
1540 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1541 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1542 printk(MYIOC_s_INFO_FMT
1543 "pci-resume: Cannot recover, error:[%x]\n",
1544 ioc->name, recovery_state);
1545 } else {
1546 printk(MYIOC_s_INFO_FMT
1547 "pci-resume: success\n", ioc->name);
1548 }
1549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 return 0;
1551}
1552#endif
1553
James Bottomley4ff42a62006-05-17 18:06:52 -05001554static int
1555mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1556{
1557 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1558 ioc->bus_type != SPI) ||
1559 (MptDriverClass[index] == MPTFC_DRIVER &&
1560 ioc->bus_type != FC) ||
1561 (MptDriverClass[index] == MPTSAS_DRIVER &&
1562 ioc->bus_type != SAS))
1563 /* make sure we only call the relevant reset handler
1564 * for the bus */
1565 return 0;
1566 return (MptResetHandlers[index])(ioc, reset_phase);
1567}
1568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1570/*
1571 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1572 * @ioc: Pointer to MPT adapter structure
1573 * @reason: Event word / reason
1574 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1575 *
1576 * This routine performs all the steps necessary to bring the IOC
1577 * to a OPERATIONAL state.
1578 *
1579 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1580 * MPT adapter.
1581 *
1582 * Returns:
1583 * 0 for success
1584 * -1 if failed to get board READY
1585 * -2 if READY but IOCFacts Failed
1586 * -3 if READY but PrimeIOCFifos Failed
1587 * -4 if READY but IOCInit Failed
1588 */
1589static int
1590mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1591{
1592 int hard_reset_done = 0;
1593 int alt_ioc_ready = 0;
1594 int hard;
1595 int rc=0;
1596 int ii;
1597 int handlers;
1598 int ret = 0;
1599 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001600 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1603 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1604
1605 /* Disable reply interrupts (also blocks FreeQ) */
1606 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1607 ioc->active = 0;
1608
1609 if (ioc->alt_ioc) {
1610 if (ioc->alt_ioc->active)
1611 reset_alt_ioc_active = 1;
1612
1613 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1614 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1615 ioc->alt_ioc->active = 0;
1616 }
1617
1618 hard = 1;
1619 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1620 hard = 0;
1621
1622 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1623 if (hard_reset_done == -4) {
1624 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1625 ioc->name);
1626
1627 if (reset_alt_ioc_active && ioc->alt_ioc) {
1628 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1629 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1630 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001631 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 ioc->alt_ioc->active = 1;
1633 }
1634
1635 } else {
1636 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1637 ioc->name);
1638 }
1639 return -1;
1640 }
1641
1642 /* hard_reset_done = 0 if a soft reset was performed
1643 * and 1 if a hard reset was performed.
1644 */
1645 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1646 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1647 alt_ioc_ready = 1;
1648 else
1649 printk(KERN_WARNING MYNAM
1650 ": alt-%s: Not ready WARNING!\n",
1651 ioc->alt_ioc->name);
1652 }
1653
1654 for (ii=0; ii<5; ii++) {
1655 /* Get IOC facts! Allow 5 retries */
1656 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1657 break;
1658 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001659
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
1661 if (ii == 5) {
1662 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1663 ret = -2;
1664 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1665 MptDisplayIocCapabilities(ioc);
1666 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001667
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 if (alt_ioc_ready) {
1669 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1670 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1671 /* Retry - alt IOC was initialized once
1672 */
1673 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1674 }
1675 if (rc) {
1676 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1677 alt_ioc_ready = 0;
1678 reset_alt_ioc_active = 0;
1679 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1680 MptDisplayIocCapabilities(ioc->alt_ioc);
1681 }
1682 }
1683
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001684 /*
1685 * Device is reset now. It must have de-asserted the interrupt line
1686 * (if it was asserted) and it should be safe to register for the
1687 * interrupt now.
1688 */
1689 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1690 ioc->pci_irq = -1;
1691 if (ioc->pcidev->irq) {
1692 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1693 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1694 ioc->name);
1695 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001696 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001697 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001698 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1699 "interrupt %d!\n", ioc->name,
1700 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001701 if (mpt_msi_enable)
1702 pci_disable_msi(ioc->pcidev);
1703 return -EBUSY;
1704 }
1705 irq_allocated = 1;
1706 ioc->pci_irq = ioc->pcidev->irq;
1707 pci_set_master(ioc->pcidev); /* ?? */
1708 pci_set_drvdata(ioc->pcidev, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001709 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1710 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001711 }
1712 }
1713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 /* Prime reply & request queues!
1715 * (mucho alloc's) Must be done prior to
1716 * init as upper addresses are needed for init.
1717 * If fails, continue with alt-ioc processing
1718 */
1719 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1720 ret = -3;
1721
1722 /* May need to check/upload firmware & data here!
1723 * If fails, continue with alt-ioc processing
1724 */
1725 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1726 ret = -4;
1727// NEW!
1728 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1729 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1730 ioc->alt_ioc->name, rc);
1731 alt_ioc_ready = 0;
1732 reset_alt_ioc_active = 0;
1733 }
1734
1735 if (alt_ioc_ready) {
1736 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1737 alt_ioc_ready = 0;
1738 reset_alt_ioc_active = 0;
1739 printk(KERN_WARNING MYNAM
1740 ": alt-%s: (%d) init failure WARNING!\n",
1741 ioc->alt_ioc->name, rc);
1742 }
1743 }
1744
1745 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1746 if (ioc->upload_fw) {
1747 ddlprintk((MYIOC_s_INFO_FMT
1748 "firmware upload required!\n", ioc->name));
1749
1750 /* Controller is not operational, cannot do upload
1751 */
1752 if (ret == 0) {
1753 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001754 if (rc == 0) {
1755 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1756 /*
1757 * Maintain only one pointer to FW memory
1758 * so there will not be two attempt to
1759 * downloadboot onboard dual function
1760 * chips (mpt_adapter_disable,
1761 * mpt_diag_reset)
1762 */
1763 ioc->cached_fw = NULL;
1764 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1765 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1766 }
1767 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001769 ret = -5;
1770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 }
1772 }
1773 }
1774
1775 if (ret == 0) {
1776 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001777 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 ioc->active = 1;
1779 }
1780
1781 if (reset_alt_ioc_active && ioc->alt_ioc) {
1782 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001783 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001785 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 ioc->alt_ioc->active = 1;
1787 }
1788
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001789 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 * and EventAck handling.
1791 */
1792 if ((ret == 0) && (!ioc->facts.EventState))
1793 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1794
1795 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1796 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1797
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001798 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1800 * recursive scenario; GetLanConfigPages times out, timer expired
1801 * routine calls HardResetHandler, which calls into here again,
1802 * and we try GetLanConfigPages again...
1803 */
1804 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001805 if (ioc->bus_type == SAS) {
1806
1807 /* clear persistency table */
1808 if(ioc->facts.IOCExceptions &
1809 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1810 ret = mptbase_sas_persist_operation(ioc,
1811 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1812 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001813 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001814 }
1815
1816 /* Find IM volumes
1817 */
1818 mpt_findImVolumes(ioc);
1819
1820 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1822 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1823 /*
1824 * Pre-fetch the ports LAN MAC address!
1825 * (LANPage1_t stuff)
1826 */
1827 (void) GetLanConfigPages(ioc);
1828#ifdef MPT_DEBUG
1829 {
1830 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1831 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1832 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1833 }
1834#endif
1835 }
1836 } else {
1837 /* Get NVRAM and adapter maximums from SPP 0 and 2
1838 */
1839 mpt_GetScsiPortSettings(ioc, 0);
1840
1841 /* Get version and length of SDP 1
1842 */
1843 mpt_readScsiDevicePageHeaders(ioc, 0);
1844
1845 /* Find IM volumes
1846 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001847 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 mpt_findImVolumes(ioc);
1849
1850 /* Check, and possibly reset, the coalescing value
1851 */
1852 mpt_read_ioc_pg_1(ioc);
1853
1854 mpt_read_ioc_pg_4(ioc);
1855 }
1856
1857 GetIoUnitPage2(ioc);
1858 }
1859
1860 /*
1861 * Call each currently registered protocol IOC reset handler
1862 * with post-reset indication.
1863 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1864 * MptResetHandlers[] registered yet.
1865 */
1866 if (hard_reset_done) {
1867 rc = handlers = 0;
1868 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1869 if ((ret == 0) && MptResetHandlers[ii]) {
1870 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1871 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001872 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 handlers++;
1874 }
1875
1876 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001877 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001879 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 handlers++;
1881 }
1882 }
1883 /* FIXME? Examine results here? */
1884 }
1885
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001886out:
1887 if ((ret != 0) && irq_allocated) {
1888 free_irq(ioc->pci_irq, ioc);
1889 if (mpt_msi_enable)
1890 pci_disable_msi(ioc->pcidev);
1891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 return ret;
1893}
1894
1895/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1896/*
1897 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1898 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1899 * 929X, 1030 or 1035.
1900 * @ioc: Pointer to MPT adapter structure
1901 * @pdev: Pointer to (struct pci_dev) structure
1902 *
1903 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1904 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1905 */
1906static void
1907mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1908{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001909 struct pci_dev *peer=NULL;
1910 unsigned int slot = PCI_SLOT(pdev->devfn);
1911 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 MPT_ADAPTER *ioc_srch;
1913
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001914 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1915 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001916 ioc->name, pci_name(pdev), pdev->bus->number,
1917 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001918
1919 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1920 if (!peer) {
1921 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1922 if (!peer)
1923 return;
1924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
1926 list_for_each_entry(ioc_srch, &ioc_list, list) {
1927 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001928 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 /* Paranoia checks */
1930 if (ioc->alt_ioc != NULL) {
1931 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001932 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 break;
1934 } else if (ioc_srch->alt_ioc != NULL) {
1935 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001936 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 break;
1938 }
1939 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001940 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 ioc_srch->alt_ioc = ioc;
1942 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 }
1944 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001945 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946}
1947
1948/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1949/*
1950 * mpt_adapter_disable - Disable misbehaving MPT adapter.
1951 * @this: Pointer to MPT adapter structure
1952 */
1953static void
1954mpt_adapter_disable(MPT_ADAPTER *ioc)
1955{
1956 int sz;
1957 int ret;
1958
1959 if (ioc->cached_fw != NULL) {
1960 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001961 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 printk(KERN_WARNING MYNAM
1963 ": firmware downloadboot failure (%d)!\n", ret);
1964 }
1965 }
1966
1967 /* Disable adapter interrupts! */
1968 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1969 ioc->active = 0;
1970 /* Clear any lingering interrupt */
1971 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1972
1973 if (ioc->alloc != NULL) {
1974 sz = ioc->alloc_sz;
1975 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1976 ioc->name, ioc->alloc, ioc->alloc_sz));
1977 pci_free_consistent(ioc->pcidev, sz,
1978 ioc->alloc, ioc->alloc_dma);
1979 ioc->reply_frames = NULL;
1980 ioc->req_frames = NULL;
1981 ioc->alloc = NULL;
1982 ioc->alloc_total -= sz;
1983 }
1984
1985 if (ioc->sense_buf_pool != NULL) {
1986 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
1987 pci_free_consistent(ioc->pcidev, sz,
1988 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
1989 ioc->sense_buf_pool = NULL;
1990 ioc->alloc_total -= sz;
1991 }
1992
1993 if (ioc->events != NULL){
1994 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
1995 kfree(ioc->events);
1996 ioc->events = NULL;
1997 ioc->alloc_total -= sz;
1998 }
1999
2000 if (ioc->cached_fw != NULL) {
2001 sz = ioc->facts.FWImageSize;
2002 pci_free_consistent(ioc->pcidev, sz,
2003 ioc->cached_fw, ioc->cached_fw_dma);
2004 ioc->cached_fw = NULL;
2005 ioc->alloc_total -= sz;
2006 }
2007
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002008 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002009 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002010 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002011 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
2013 if (ioc->spi_data.pIocPg4 != NULL) {
2014 sz = ioc->spi_data.IocPg4Sz;
2015 pci_free_consistent(ioc->pcidev, sz,
2016 ioc->spi_data.pIocPg4,
2017 ioc->spi_data.IocPg4_dma);
2018 ioc->spi_data.pIocPg4 = NULL;
2019 ioc->alloc_total -= sz;
2020 }
2021
2022 if (ioc->ReqToChain != NULL) {
2023 kfree(ioc->ReqToChain);
2024 kfree(ioc->RequestNB);
2025 ioc->ReqToChain = NULL;
2026 }
2027
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002028 kfree(ioc->ChainToChain);
2029 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002030
2031 if (ioc->HostPageBuffer != NULL) {
2032 if((ret = mpt_host_page_access_control(ioc,
2033 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2034 printk(KERN_ERR MYNAM
2035 ": %s: host page buffers free failed (%d)!\n",
2036 __FUNCTION__, ret);
2037 }
2038 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2039 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2040 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2041 ioc->HostPageBuffer,
2042 ioc->HostPageBuffer_dma);
2043 ioc->HostPageBuffer = NULL;
2044 ioc->HostPageBuffer_sz = 0;
2045 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047}
2048
2049/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2050/*
2051 * mpt_adapter_dispose - Free all resources associated with a MPT
2052 * adapter.
2053 * @ioc: Pointer to MPT adapter structure
2054 *
2055 * This routine unregisters h/w resources and frees all alloc'd memory
2056 * associated with a MPT adapter structure.
2057 */
2058static void
2059mpt_adapter_dispose(MPT_ADAPTER *ioc)
2060{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002061 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002063 if (ioc == NULL)
2064 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002066 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002068 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002070 if (ioc->pci_irq != -1) {
2071 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002072 if (mpt_msi_enable)
2073 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002074 ioc->pci_irq = -1;
2075 }
2076
2077 if (ioc->memmap != NULL) {
2078 iounmap(ioc->memmap);
2079 ioc->memmap = NULL;
2080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002083 if (ioc->mtrr_reg > 0) {
2084 mtrr_del(ioc->mtrr_reg, 0, 0);
2085 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087#endif
2088
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002089 /* Zap the adapter lookup ptr! */
2090 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002092 sz_last = ioc->alloc_total;
2093 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2094 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002095
2096 if (ioc->alt_ioc)
2097 ioc->alt_ioc->alt_ioc = NULL;
2098
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002099 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100}
2101
2102/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2103/*
2104 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2105 * @ioc: Pointer to MPT adapter structure
2106 */
2107static void
2108MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2109{
2110 int i = 0;
2111
2112 printk(KERN_INFO "%s: ", ioc->name);
2113 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2114 printk("%s: ", ioc->prod_name+3);
2115 printk("Capabilities={");
2116
2117 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2118 printk("Initiator");
2119 i++;
2120 }
2121
2122 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2123 printk("%sTarget", i ? "," : "");
2124 i++;
2125 }
2126
2127 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2128 printk("%sLAN", i ? "," : "");
2129 i++;
2130 }
2131
2132#if 0
2133 /*
2134 * This would probably evoke more questions than it's worth
2135 */
2136 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2137 printk("%sLogBusAddr", i ? "," : "");
2138 i++;
2139 }
2140#endif
2141
2142 printk("}\n");
2143}
2144
2145/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2146/*
2147 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2148 * @ioc: Pointer to MPT_ADAPTER structure
2149 * @force: Force hard KickStart of IOC
2150 * @sleepFlag: Specifies whether the process can sleep
2151 *
2152 * Returns:
2153 * 1 - DIAG reset and READY
2154 * 0 - READY initially OR soft reset and READY
2155 * -1 - Any failure on KickStart
2156 * -2 - Msg Unit Reset Failed
2157 * -3 - IO Unit Reset Failed
2158 * -4 - IOC owned by a PEER
2159 */
2160static int
2161MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2162{
2163 u32 ioc_state;
2164 int statefault = 0;
2165 int cntdn;
2166 int hard_reset_done = 0;
2167 int r;
2168 int ii;
2169 int whoinit;
2170
2171 /* Get current [raw] IOC state */
2172 ioc_state = mpt_GetIocState(ioc, 0);
2173 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2174
2175 /*
2176 * Check to see if IOC got left/stuck in doorbell handshake
2177 * grip of death. If so, hard reset the IOC.
2178 */
2179 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2180 statefault = 1;
2181 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2182 ioc->name);
2183 }
2184
2185 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002186 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 return 0;
2188
2189 /*
2190 * Check to see if IOC is in FAULT state.
2191 */
2192 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2193 statefault = 2;
2194 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2195 ioc->name);
2196 printk(KERN_WARNING " FAULT code = %04xh\n",
2197 ioc_state & MPI_DOORBELL_DATA_MASK);
2198 }
2199
2200 /*
2201 * Hmmm... Did it get left operational?
2202 */
2203 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002204 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 ioc->name));
2206
2207 /* Check WhoInit.
2208 * If PCI Peer, exit.
2209 * Else, if no fault conditions are present, issue a MessageUnitReset
2210 * Else, fall through to KickStart case
2211 */
2212 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002213 dinitprintk((KERN_INFO MYNAM
2214 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 whoinit, statefault, force));
2216 if (whoinit == MPI_WHOINIT_PCI_PEER)
2217 return -4;
2218 else {
2219 if ((statefault == 0 ) && (force == 0)) {
2220 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2221 return 0;
2222 }
2223 statefault = 3;
2224 }
2225 }
2226
2227 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2228 if (hard_reset_done < 0)
2229 return -1;
2230
2231 /*
2232 * Loop here waiting for IOC to come READY.
2233 */
2234 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002235 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
2237 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2238 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2239 /*
2240 * BIOS or previous driver load left IOC in OP state.
2241 * Reset messaging FIFOs.
2242 */
2243 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2244 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2245 return -2;
2246 }
2247 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2248 /*
2249 * Something is wrong. Try to get IOC back
2250 * to a known state.
2251 */
2252 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2253 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2254 return -3;
2255 }
2256 }
2257
2258 ii++; cntdn--;
2259 if (!cntdn) {
2260 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2261 ioc->name, (int)((ii+5)/HZ));
2262 return -ETIME;
2263 }
2264
2265 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002266 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 } else {
2268 mdelay (1); /* 1 msec delay */
2269 }
2270
2271 }
2272
2273 if (statefault < 3) {
2274 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2275 ioc->name,
2276 statefault==1 ? "stuck handshake" : "IOC FAULT");
2277 }
2278
2279 return hard_reset_done;
2280}
2281
2282/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2283/*
2284 * mpt_GetIocState - Get the current state of a MPT adapter.
2285 * @ioc: Pointer to MPT_ADAPTER structure
2286 * @cooked: Request raw or cooked IOC state
2287 *
2288 * Returns all IOC Doorbell register bits if cooked==0, else just the
2289 * Doorbell bits in MPI_IOC_STATE_MASK.
2290 */
2291u32
2292mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2293{
2294 u32 s, sc;
2295
2296 /* Get! */
2297 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2298// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2299 sc = s & MPI_IOC_STATE_MASK;
2300
2301 /* Save! */
2302 ioc->last_state = sc;
2303
2304 return cooked ? sc : s;
2305}
2306
2307/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2308/*
2309 * GetIocFacts - Send IOCFacts request to MPT adapter.
2310 * @ioc: Pointer to MPT_ADAPTER structure
2311 * @sleepFlag: Specifies whether the process can sleep
2312 * @reason: If recovery, only update facts.
2313 *
2314 * Returns 0 for success, non-zero for failure.
2315 */
2316static int
2317GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2318{
2319 IOCFacts_t get_facts;
2320 IOCFactsReply_t *facts;
2321 int r;
2322 int req_sz;
2323 int reply_sz;
2324 int sz;
2325 u32 status, vv;
2326 u8 shiftFactor=1;
2327
2328 /* IOC *must* NOT be in RESET state! */
2329 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2330 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2331 ioc->name,
2332 ioc->last_state );
2333 return -44;
2334 }
2335
2336 facts = &ioc->facts;
2337
2338 /* Destination (reply area)... */
2339 reply_sz = sizeof(*facts);
2340 memset(facts, 0, reply_sz);
2341
2342 /* Request area (get_facts on the stack right now!) */
2343 req_sz = sizeof(get_facts);
2344 memset(&get_facts, 0, req_sz);
2345
2346 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2347 /* Assert: All other get_facts fields are zero! */
2348
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002349 dinitprintk((MYIOC_s_INFO_FMT
2350 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 ioc->name, req_sz, reply_sz));
2352
2353 /* No non-zero fields in the get_facts request are greater than
2354 * 1 byte in size, so we can just fire it off as is.
2355 */
2356 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2357 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2358 if (r != 0)
2359 return r;
2360
2361 /*
2362 * Now byte swap (GRRR) the necessary fields before any further
2363 * inspection of reply contents.
2364 *
2365 * But need to do some sanity checks on MsgLength (byte) field
2366 * to make sure we don't zero IOC's req_sz!
2367 */
2368 /* Did we get a valid reply? */
2369 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2370 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2371 /*
2372 * If not been here, done that, save off first WhoInit value
2373 */
2374 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2375 ioc->FirstWhoInit = facts->WhoInit;
2376 }
2377
2378 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2379 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2380 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2381 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2382 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002383 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 /* CHECKME! IOCStatus, IOCLogInfo */
2385
2386 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2387 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2388
2389 /*
2390 * FC f/w version changed between 1.1 and 1.2
2391 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2392 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2393 */
2394 if (facts->MsgVersion < 0x0102) {
2395 /*
2396 * Handle old FC f/w style, convert to new...
2397 */
2398 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2399 facts->FWVersion.Word =
2400 ((oldv<<12) & 0xFF000000) |
2401 ((oldv<<8) & 0x000FFF00);
2402 } else
2403 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2404
2405 facts->ProductID = le16_to_cpu(facts->ProductID);
2406 facts->CurrentHostMfaHighAddr =
2407 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2408 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2409 facts->CurrentSenseBufferHighAddr =
2410 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2411 facts->CurReplyFrameSize =
2412 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002413 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
2415 /*
2416 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2417 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2418 * to 14 in MPI-1.01.0x.
2419 */
2420 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2421 facts->MsgVersion > 0x0100) {
2422 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2423 }
2424
2425 sz = facts->FWImageSize;
2426 if ( sz & 0x01 )
2427 sz += 1;
2428 if ( sz & 0x02 )
2429 sz += 2;
2430 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002431
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 if (!facts->RequestFrameSize) {
2433 /* Something is wrong! */
2434 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2435 ioc->name);
2436 return -55;
2437 }
2438
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002439 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 vv = ((63 / (sz * 4)) + 1) & 0x03;
2441 ioc->NB_for_64_byte_frame = vv;
2442 while ( sz )
2443 {
2444 shiftFactor++;
2445 sz = sz >> 1;
2446 }
2447 ioc->NBShiftFactor = shiftFactor;
2448 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2449 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002450
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2452 /*
2453 * Set values for this IOC's request & reply frame sizes,
2454 * and request & reply queue depths...
2455 */
2456 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2457 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2458 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2459 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2460
2461 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2462 ioc->name, ioc->reply_sz, ioc->reply_depth));
2463 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2464 ioc->name, ioc->req_sz, ioc->req_depth));
2465
2466 /* Get port facts! */
2467 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2468 return r;
2469 }
2470 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002471 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2473 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2474 RequestFrameSize)/sizeof(u32)));
2475 return -66;
2476 }
2477
2478 return 0;
2479}
2480
2481/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2482/*
2483 * GetPortFacts - Send PortFacts request to MPT adapter.
2484 * @ioc: Pointer to MPT_ADAPTER structure
2485 * @portnum: Port number
2486 * @sleepFlag: Specifies whether the process can sleep
2487 *
2488 * Returns 0 for success, non-zero for failure.
2489 */
2490static int
2491GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2492{
2493 PortFacts_t get_pfacts;
2494 PortFactsReply_t *pfacts;
2495 int ii;
2496 int req_sz;
2497 int reply_sz;
2498
2499 /* IOC *must* NOT be in RESET state! */
2500 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2501 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2502 ioc->name,
2503 ioc->last_state );
2504 return -4;
2505 }
2506
2507 pfacts = &ioc->pfacts[portnum];
2508
2509 /* Destination (reply area)... */
2510 reply_sz = sizeof(*pfacts);
2511 memset(pfacts, 0, reply_sz);
2512
2513 /* Request area (get_pfacts on the stack right now!) */
2514 req_sz = sizeof(get_pfacts);
2515 memset(&get_pfacts, 0, req_sz);
2516
2517 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2518 get_pfacts.PortNumber = portnum;
2519 /* Assert: All other get_pfacts fields are zero! */
2520
2521 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2522 ioc->name, portnum));
2523
2524 /* No non-zero fields in the get_pfacts request are greater than
2525 * 1 byte in size, so we can just fire it off as is.
2526 */
2527 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2528 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2529 if (ii != 0)
2530 return ii;
2531
2532 /* Did we get a valid reply? */
2533
2534 /* Now byte swap the necessary fields in the response. */
2535 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2536 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2537 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2538 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2539 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2540 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2541 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2542 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2543 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2544
2545 return 0;
2546}
2547
2548/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2549/*
2550 * SendIocInit - Send IOCInit request to MPT adapter.
2551 * @ioc: Pointer to MPT_ADAPTER structure
2552 * @sleepFlag: Specifies whether the process can sleep
2553 *
2554 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2555 *
2556 * Returns 0 for success, non-zero for failure.
2557 */
2558static int
2559SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2560{
2561 IOCInit_t ioc_init;
2562 MPIDefaultReply_t init_reply;
2563 u32 state;
2564 int r;
2565 int count;
2566 int cntdn;
2567
2568 memset(&ioc_init, 0, sizeof(ioc_init));
2569 memset(&init_reply, 0, sizeof(init_reply));
2570
2571 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2572 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2573
2574 /* If we are in a recovery mode and we uploaded the FW image,
2575 * then this pointer is not NULL. Skip the upload a second time.
2576 * Set this flag if cached_fw set for either IOC.
2577 */
2578 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2579 ioc->upload_fw = 1;
2580 else
2581 ioc->upload_fw = 0;
2582 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2583 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2584
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002585 if(ioc->bus_type == SAS)
2586 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2587 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2589 else
2590 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002592 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2593 ioc->name, ioc->facts.MsgVersion));
2594 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2595 // set MsgVersion and HeaderVersion host driver was built with
2596 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2597 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002599 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2600 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2601 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2602 return -99;
2603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2605
2606 if (sizeof(dma_addr_t) == sizeof(u64)) {
2607 /* Save the upper 32-bits of the request
2608 * (reply) and sense buffers.
2609 */
2610 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2611 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2612 } else {
2613 /* Force 32-bit addressing */
2614 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2615 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2616 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002617
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2619 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002620 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2621 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
2623 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2624 ioc->name, &ioc_init));
2625
2626 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2627 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002628 if (r != 0) {
2629 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
2633 /* No need to byte swap the multibyte fields in the reply
2634 * since we don't even look at it's contents.
2635 */
2636
2637 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2638 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002639
2640 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2641 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
2645 /* YIKES! SUPER IMPORTANT!!!
2646 * Poll IocState until _OPERATIONAL while IOC is doing
2647 * LoopInit and TargetDiscovery!
2648 */
2649 count = 0;
2650 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2651 state = mpt_GetIocState(ioc, 1);
2652 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2653 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002654 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 } else {
2656 mdelay(1);
2657 }
2658
2659 if (!cntdn) {
2660 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2661 ioc->name, (int)((count+5)/HZ));
2662 return -9;
2663 }
2664
2665 state = mpt_GetIocState(ioc, 1);
2666 count++;
2667 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002668 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 ioc->name, count));
2670
2671 return r;
2672}
2673
2674/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2675/*
2676 * SendPortEnable - Send PortEnable request to MPT adapter port.
2677 * @ioc: Pointer to MPT_ADAPTER structure
2678 * @portnum: Port number to enable
2679 * @sleepFlag: Specifies whether the process can sleep
2680 *
2681 * Send PortEnable to bring IOC to OPERATIONAL state.
2682 *
2683 * Returns 0 for success, non-zero for failure.
2684 */
2685static int
2686SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2687{
2688 PortEnable_t port_enable;
2689 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002690 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 int req_sz;
2692 int reply_sz;
2693
2694 /* Destination... */
2695 reply_sz = sizeof(MPIDefaultReply_t);
2696 memset(&reply_buf, 0, reply_sz);
2697
2698 req_sz = sizeof(PortEnable_t);
2699 memset(&port_enable, 0, req_sz);
2700
2701 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2702 port_enable.PortNumber = portnum;
2703/* port_enable.ChainOffset = 0; */
2704/* port_enable.MsgFlags = 0; */
2705/* port_enable.MsgContext = 0; */
2706
2707 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2708 ioc->name, portnum, &port_enable));
2709
2710 /* RAID FW may take a long time to enable
2711 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002712 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2713 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2714 (ioc->bus_type == SAS)) {
2715 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2716 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2717 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002718 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002719 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2720 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2721 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002723 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724}
2725
2726/*
2727 * ioc: Pointer to MPT_ADAPTER structure
2728 * size - total FW bytes
2729 */
2730void
2731mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2732{
2733 if (ioc->cached_fw)
2734 return; /* use already allocated memory */
2735 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2736 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2737 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2738 } else {
2739 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2740 ioc->alloc_total += size;
2741 }
2742}
2743/*
2744 * If alt_img is NULL, delete from ioc structure.
2745 * Else, delete a secondary image in same format.
2746 */
2747void
2748mpt_free_fw_memory(MPT_ADAPTER *ioc)
2749{
2750 int sz;
2751
2752 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002753 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2755 pci_free_consistent(ioc->pcidev, sz,
2756 ioc->cached_fw, ioc->cached_fw_dma);
2757 ioc->cached_fw = NULL;
2758
2759 return;
2760}
2761
2762
2763/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2764/*
2765 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2766 * @ioc: Pointer to MPT_ADAPTER structure
2767 * @sleepFlag: Specifies whether the process can sleep
2768 *
2769 * Returns 0 for success, >0 for handshake failure
2770 * <0 for fw upload failure.
2771 *
2772 * Remark: If bound IOC and a successful FWUpload was performed
2773 * on the bound IOC, the second image is discarded
2774 * and memory is free'd. Both channels must upload to prevent
2775 * IOC from running in degraded mode.
2776 */
2777static int
2778mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2779{
2780 u8 request[ioc->req_sz];
2781 u8 reply[sizeof(FWUploadReply_t)];
2782 FWUpload_t *prequest;
2783 FWUploadReply_t *preply;
2784 FWUploadTCSGE_t *ptcsge;
2785 int sgeoffset;
2786 u32 flagsLength;
2787 int ii, sz, reply_sz;
2788 int cmdStatus;
2789
2790 /* If the image size is 0, we are done.
2791 */
2792 if ((sz = ioc->facts.FWImageSize) == 0)
2793 return 0;
2794
2795 mpt_alloc_fw_memory(ioc, sz);
2796
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002797 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002799
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 if (ioc->cached_fw == NULL) {
2801 /* Major Failure.
2802 */
2803 return -ENOMEM;
2804 }
2805
2806 prequest = (FWUpload_t *)&request;
2807 preply = (FWUploadReply_t *)&reply;
2808
2809 /* Destination... */
2810 memset(prequest, 0, ioc->req_sz);
2811
2812 reply_sz = sizeof(reply);
2813 memset(preply, 0, reply_sz);
2814
2815 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2816 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2817
2818 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2819 ptcsge->DetailsLength = 12;
2820 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2821 ptcsge->ImageSize = cpu_to_le32(sz);
2822
2823 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2824
2825 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2826 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2827
2828 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002829 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 prequest, sgeoffset));
2831 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2832
2833 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2834 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2835
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002836 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837
2838 cmdStatus = -EFAULT;
2839 if (ii == 0) {
2840 /* Handshake transfer was complete and successful.
2841 * Check the Reply Frame.
2842 */
2843 int status, transfer_sz;
2844 status = le16_to_cpu(preply->IOCStatus);
2845 if (status == MPI_IOCSTATUS_SUCCESS) {
2846 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2847 if (transfer_sz == sz)
2848 cmdStatus = 0;
2849 }
2850 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002851 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 ioc->name, cmdStatus));
2853
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002854
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 if (cmdStatus) {
2856
2857 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2858 ioc->name));
2859 mpt_free_fw_memory(ioc);
2860 }
2861
2862 return cmdStatus;
2863}
2864
2865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2866/*
2867 * mpt_downloadboot - DownloadBoot code
2868 * @ioc: Pointer to MPT_ADAPTER structure
2869 * @flag: Specify which part of IOC memory is to be uploaded.
2870 * @sleepFlag: Specifies whether the process can sleep
2871 *
2872 * FwDownloadBoot requires Programmed IO access.
2873 *
2874 * Returns 0 for success
2875 * -1 FW Image size is 0
2876 * -2 No valid cached_fw Pointer
2877 * <0 for fw upload failure.
2878 */
2879static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002880mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 MpiExtImageHeader_t *pExtImage;
2883 u32 fwSize;
2884 u32 diag0val;
2885 int count;
2886 u32 *ptrFw;
2887 u32 diagRwData;
2888 u32 nextImage;
2889 u32 load_addr;
2890 u32 ioc_state=0;
2891
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002892 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2893 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002894
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2896 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2897 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2898 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2899 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2900 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2901
2902 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2903
2904 /* wait 1 msec */
2905 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002906 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 } else {
2908 mdelay (1);
2909 }
2910
2911 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2912 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2913
2914 for (count = 0; count < 30; count ++) {
2915 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2916 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2917 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2918 ioc->name, count));
2919 break;
2920 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002921 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002923 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002925 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 }
2927 }
2928
2929 if ( count == 30 ) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002930 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2931 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 ioc->name, diag0val));
2933 return -3;
2934 }
2935
2936 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2937 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2938 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2939 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2940 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2941 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2942
2943 /* Set the DiagRwEn and Disable ARM bits */
2944 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2945
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 fwSize = (pFwHeader->ImageSize + 3)/4;
2947 ptrFw = (u32 *) pFwHeader;
2948
2949 /* Write the LoadStartAddress to the DiagRw Address Register
2950 * using Programmed IO
2951 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002952 if (ioc->errata_flag_1064)
2953 pci_enable_io_access(ioc->pcidev);
2954
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2956 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2957 ioc->name, pFwHeader->LoadStartAddress));
2958
2959 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2960 ioc->name, fwSize*4, ptrFw));
2961 while (fwSize--) {
2962 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2963 }
2964
2965 nextImage = pFwHeader->NextImageHeaderOffset;
2966 while (nextImage) {
2967 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
2968
2969 load_addr = pExtImage->LoadStartAddress;
2970
2971 fwSize = (pExtImage->ImageSize + 3) >> 2;
2972 ptrFw = (u32 *)pExtImage;
2973
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002974 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
2975 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
2977
2978 while (fwSize--) {
2979 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2980 }
2981 nextImage = pExtImage->NextImageHeaderOffset;
2982 }
2983
2984 /* Write the IopResetVectorRegAddr */
2985 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
2986 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
2987
2988 /* Write the IopResetVectorValue */
2989 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
2990 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
2991
2992 /* Clear the internal flash bad bit - autoincrementing register,
2993 * so must do two writes.
2994 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002995 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002996 /*
2997 * 1030 and 1035 H/W errata, workaround to access
2998 * the ClearFlashBadSignatureBit
2999 */
3000 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3001 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3002 diagRwData |= 0x40000000;
3003 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3004 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3005
3006 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3007 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3008 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3009 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3010
3011 /* wait 1 msec */
3012 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003013 msleep (1);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003014 } else {
3015 mdelay (1);
3016 }
3017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003019 if (ioc->errata_flag_1064)
3020 pci_disable_io_access(ioc->pcidev);
3021
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003023 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3024 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003026 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3028 ioc->name, diag0val));
3029 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3030
3031 /* Write 0xFF to reset the sequencer */
3032 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3033
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003034 if (ioc->bus_type == SAS) {
3035 ioc_state = mpt_GetIocState(ioc, 0);
3036 if ( (GetIocFacts(ioc, sleepFlag,
3037 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3038 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3039 ioc->name, ioc_state));
3040 return -EFAULT;
3041 }
3042 }
3043
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 for (count=0; count<HZ*20; count++) {
3045 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3046 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3047 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003048 if (ioc->bus_type == SAS) {
3049 return 0;
3050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3052 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3053 ioc->name));
3054 return -EFAULT;
3055 }
3056 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3057 ioc->name));
3058 return 0;
3059 }
3060 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003061 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 } else {
3063 mdelay (10);
3064 }
3065 }
3066 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3067 ioc->name, ioc_state));
3068 return -EFAULT;
3069}
3070
3071/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3072/*
3073 * KickStart - Perform hard reset of MPT adapter.
3074 * @ioc: Pointer to MPT_ADAPTER structure
3075 * @force: Force hard reset
3076 * @sleepFlag: Specifies whether the process can sleep
3077 *
3078 * This routine places MPT adapter in diagnostic mode via the
3079 * WriteSequence register, and then performs a hard reset of adapter
3080 * via the Diagnostic register.
3081 *
3082 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3083 * or NO_SLEEP (interrupt thread, use mdelay)
3084 * force - 1 if doorbell active, board fault state
3085 * board operational, IOC_RECOVERY or
3086 * IOC_BRINGUP and there is an alt_ioc.
3087 * 0 else
3088 *
3089 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003090 * 1 - hard reset, READY
3091 * 0 - no reset due to History bit, READY
3092 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 * OR reset but failed to come READY
3094 * -2 - no reset, could not enter DIAG mode
3095 * -3 - reset but bad FW bit
3096 */
3097static int
3098KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3099{
3100 int hard_reset_done = 0;
3101 u32 ioc_state=0;
3102 int cnt,cntdn;
3103
3104 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003105 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 /* Always issue a Msg Unit Reset first. This will clear some
3107 * SCSI bus hang conditions.
3108 */
3109 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3110
3111 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003112 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 } else {
3114 mdelay (1000);
3115 }
3116 }
3117
3118 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3119 if (hard_reset_done < 0)
3120 return hard_reset_done;
3121
3122 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3123 ioc->name));
3124
3125 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3126 for (cnt=0; cnt<cntdn; cnt++) {
3127 ioc_state = mpt_GetIocState(ioc, 1);
3128 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3129 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3130 ioc->name, cnt));
3131 return hard_reset_done;
3132 }
3133 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003134 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 } else {
3136 mdelay (10);
3137 }
3138 }
3139
3140 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3141 ioc->name, ioc_state);
3142 return -1;
3143}
3144
3145/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3146/*
3147 * mpt_diag_reset - Perform hard reset of the adapter.
3148 * @ioc: Pointer to MPT_ADAPTER structure
3149 * @ignore: Set if to honor and clear to ignore
3150 * the reset history bit
3151 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3152 * else set to NO_SLEEP (use mdelay instead)
3153 *
3154 * This routine places the adapter in diagnostic mode via the
3155 * WriteSequence register and then performs a hard reset of adapter
3156 * via the Diagnostic register. Adapter should be in ready state
3157 * upon successful completion.
3158 *
3159 * Returns: 1 hard reset successful
3160 * 0 no reset performed because reset history bit set
3161 * -2 enabling diagnostic mode failed
3162 * -3 diagnostic reset failed
3163 */
3164static int
3165mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3166{
3167 u32 diag0val;
3168 u32 doorbell;
3169 int hard_reset_done = 0;
3170 int count = 0;
3171#ifdef MPT_DEBUG
3172 u32 diag1val = 0;
3173#endif
3174
Eric Moore87cf8982006-06-27 16:09:26 -06003175 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
3176 drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
3177 "address=%p\n", ioc->name, __FUNCTION__,
3178 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3179 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3180 if (sleepFlag == CAN_SLEEP)
3181 msleep(1);
3182 else
3183 mdelay(1);
3184
3185 for (count = 0; count < 60; count ++) {
3186 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3187 doorbell &= MPI_IOC_STATE_MASK;
3188
3189 drsprintk((MYIOC_s_INFO_FMT
3190 "looking for READY STATE: doorbell=%x"
3191 " count=%d\n",
3192 ioc->name, doorbell, count));
3193 if (doorbell == MPI_IOC_STATE_READY) {
3194 return 0;
3195 }
3196
3197 /* wait 1 sec */
3198 if (sleepFlag == CAN_SLEEP)
3199 msleep(1000);
3200 else
3201 mdelay(1000);
3202 }
3203 return -1;
3204 }
3205
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 /* Clear any existing interrupts */
3207 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3208
3209 /* Use "Diagnostic reset" method! (only thing available!) */
3210 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3211
3212#ifdef MPT_DEBUG
3213 if (ioc->alt_ioc)
3214 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3215 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3216 ioc->name, diag0val, diag1val));
3217#endif
3218
3219 /* Do the reset if we are told to ignore the reset history
3220 * or if the reset history is 0
3221 */
3222 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3223 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3224 /* Write magic sequence to WriteSequence register
3225 * Loop until in diagnostic mode
3226 */
3227 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3228 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3229 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3230 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3231 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3232 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3233
3234 /* wait 100 msec */
3235 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003236 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 } else {
3238 mdelay (100);
3239 }
3240
3241 count++;
3242 if (count > 20) {
3243 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3244 ioc->name, diag0val);
3245 return -2;
3246
3247 }
3248
3249 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3250
3251 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3252 ioc->name, diag0val));
3253 }
3254
3255#ifdef MPT_DEBUG
3256 if (ioc->alt_ioc)
3257 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3258 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3259 ioc->name, diag0val, diag1val));
3260#endif
3261 /*
3262 * Disable the ARM (Bug fix)
3263 *
3264 */
3265 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003266 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267
3268 /*
3269 * Now hit the reset bit in the Diagnostic register
3270 * (THE BIG HAMMER!) (Clears DRWE bit).
3271 */
3272 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3273 hard_reset_done = 1;
3274 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3275 ioc->name));
3276
3277 /*
3278 * Call each currently registered protocol IOC reset handler
3279 * with pre-reset indication.
3280 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3281 * MptResetHandlers[] registered yet.
3282 */
3283 {
3284 int ii;
3285 int r = 0;
3286
3287 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3288 if (MptResetHandlers[ii]) {
3289 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3290 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003291 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 if (ioc->alt_ioc) {
3293 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3294 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003295 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 }
3297 }
3298 }
3299 /* FIXME? Examine results here? */
3300 }
3301
3302 if (ioc->cached_fw) {
3303 /* If the DownloadBoot operation fails, the
3304 * IOC will be left unusable. This is a fatal error
3305 * case. _diag_reset will return < 0
3306 */
3307 for (count = 0; count < 30; count ++) {
3308 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3309 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3310 break;
3311 }
3312
3313 /* wait 1 sec */
3314 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003315 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 } else {
3317 mdelay (1000);
3318 }
3319 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003320 if ((count = mpt_downloadboot(ioc,
3321 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 printk(KERN_WARNING MYNAM
3323 ": firmware downloadboot failure (%d)!\n", count);
3324 }
3325
3326 } else {
3327 /* Wait for FW to reload and for board
3328 * to go to the READY state.
3329 * Maximum wait is 60 seconds.
3330 * If fail, no error will check again
3331 * with calling program.
3332 */
3333 for (count = 0; count < 60; count ++) {
3334 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3335 doorbell &= MPI_IOC_STATE_MASK;
3336
3337 if (doorbell == MPI_IOC_STATE_READY) {
3338 break;
3339 }
3340
3341 /* wait 1 sec */
3342 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003343 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 } else {
3345 mdelay (1000);
3346 }
3347 }
3348 }
3349 }
3350
3351 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3352#ifdef MPT_DEBUG
3353 if (ioc->alt_ioc)
3354 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3355 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3356 ioc->name, diag0val, diag1val));
3357#endif
3358
3359 /* Clear RESET_HISTORY bit! Place board in the
3360 * diagnostic mode to update the diag register.
3361 */
3362 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3363 count = 0;
3364 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3365 /* Write magic sequence to WriteSequence register
3366 * Loop until in diagnostic mode
3367 */
3368 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3369 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3370 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3371 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3372 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3373 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3374
3375 /* wait 100 msec */
3376 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003377 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 } else {
3379 mdelay (100);
3380 }
3381
3382 count++;
3383 if (count > 20) {
3384 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3385 ioc->name, diag0val);
3386 break;
3387 }
3388 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3389 }
3390 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3391 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3392 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3393 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3394 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3395 ioc->name);
3396 }
3397
3398 /* Disable Diagnostic Mode
3399 */
3400 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3401
3402 /* Check FW reload status flags.
3403 */
3404 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3405 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3406 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3407 ioc->name, diag0val);
3408 return -3;
3409 }
3410
3411#ifdef MPT_DEBUG
3412 if (ioc->alt_ioc)
3413 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3414 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3415 ioc->name, diag0val, diag1val));
3416#endif
3417
3418 /*
3419 * Reset flag that says we've enabled event notification
3420 */
3421 ioc->facts.EventState = 0;
3422
3423 if (ioc->alt_ioc)
3424 ioc->alt_ioc->facts.EventState = 0;
3425
3426 return hard_reset_done;
3427}
3428
3429/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3430/*
3431 * SendIocReset - Send IOCReset request to MPT adapter.
3432 * @ioc: Pointer to MPT_ADAPTER structure
3433 * @reset_type: reset type, expected values are
3434 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3435 *
3436 * Send IOCReset request to the MPT adapter.
3437 *
3438 * Returns 0 for success, non-zero for failure.
3439 */
3440static int
3441SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3442{
3443 int r;
3444 u32 state;
3445 int cntdn, count;
3446
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003447 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 ioc->name, reset_type));
3449 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3450 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3451 return r;
3452
3453 /* FW ACK'd request, wait for READY state
3454 */
3455 count = 0;
3456 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3457
3458 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3459 cntdn--;
3460 count++;
3461 if (!cntdn) {
3462 if (sleepFlag != CAN_SLEEP)
3463 count *= 10;
3464
3465 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3466 ioc->name, (int)((count+5)/HZ));
3467 return -ETIME;
3468 }
3469
3470 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003471 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 } else {
3473 mdelay (1); /* 1 msec delay */
3474 }
3475 }
3476
3477 /* TODO!
3478 * Cleanup all event stuff for this IOC; re-issue EventNotification
3479 * request if needed.
3480 */
3481 if (ioc->facts.Function)
3482 ioc->facts.EventState = 0;
3483
3484 return 0;
3485}
3486
3487/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3488/*
3489 * initChainBuffers - Allocate memory for and initialize
3490 * chain buffers, chain buffer control arrays and spinlock.
3491 * @hd: Pointer to MPT_SCSI_HOST structure
3492 * @init: If set, initialize the spin lock.
3493 */
3494static int
3495initChainBuffers(MPT_ADAPTER *ioc)
3496{
3497 u8 *mem;
3498 int sz, ii, num_chain;
3499 int scale, num_sge, numSGE;
3500
3501 /* ReqToChain size must equal the req_depth
3502 * index = req_idx
3503 */
3504 if (ioc->ReqToChain == NULL) {
3505 sz = ioc->req_depth * sizeof(int);
3506 mem = kmalloc(sz, GFP_ATOMIC);
3507 if (mem == NULL)
3508 return -1;
3509
3510 ioc->ReqToChain = (int *) mem;
3511 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3512 ioc->name, mem, sz));
3513 mem = kmalloc(sz, GFP_ATOMIC);
3514 if (mem == NULL)
3515 return -1;
3516
3517 ioc->RequestNB = (int *) mem;
3518 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3519 ioc->name, mem, sz));
3520 }
3521 for (ii = 0; ii < ioc->req_depth; ii++) {
3522 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3523 }
3524
3525 /* ChainToChain size must equal the total number
3526 * of chain buffers to be allocated.
3527 * index = chain_idx
3528 *
3529 * Calculate the number of chain buffers needed(plus 1) per I/O
3530 * then multiply the the maximum number of simultaneous cmds
3531 *
3532 * num_sge = num sge in request frame + last chain buffer
3533 * scale = num sge per chain buffer if no chain element
3534 */
3535 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3536 if (sizeof(dma_addr_t) == sizeof(u64))
3537 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3538 else
3539 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3540
3541 if (sizeof(dma_addr_t) == sizeof(u64)) {
3542 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3543 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3544 } else {
3545 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3546 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3547 }
3548 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3549 ioc->name, num_sge, numSGE));
3550
3551 if ( numSGE > MPT_SCSI_SG_DEPTH )
3552 numSGE = MPT_SCSI_SG_DEPTH;
3553
3554 num_chain = 1;
3555 while (numSGE - num_sge > 0) {
3556 num_chain++;
3557 num_sge += (scale - 1);
3558 }
3559 num_chain++;
3560
3561 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3562 ioc->name, numSGE, num_sge, num_chain));
3563
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003564 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 num_chain *= MPT_SCSI_CAN_QUEUE;
3566 else
3567 num_chain *= MPT_FC_CAN_QUEUE;
3568
3569 ioc->num_chain = num_chain;
3570
3571 sz = num_chain * sizeof(int);
3572 if (ioc->ChainToChain == NULL) {
3573 mem = kmalloc(sz, GFP_ATOMIC);
3574 if (mem == NULL)
3575 return -1;
3576
3577 ioc->ChainToChain = (int *) mem;
3578 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3579 ioc->name, mem, sz));
3580 } else {
3581 mem = (u8 *) ioc->ChainToChain;
3582 }
3583 memset(mem, 0xFF, sz);
3584 return num_chain;
3585}
3586
3587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3588/*
3589 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3590 * @ioc: Pointer to MPT_ADAPTER structure
3591 *
3592 * This routine allocates memory for the MPT reply and request frame
3593 * pools (if necessary), and primes the IOC reply FIFO with
3594 * reply frames.
3595 *
3596 * Returns 0 for success, non-zero for failure.
3597 */
3598static int
3599PrimeIocFifos(MPT_ADAPTER *ioc)
3600{
3601 MPT_FRAME_HDR *mf;
3602 unsigned long flags;
3603 dma_addr_t alloc_dma;
3604 u8 *mem;
3605 int i, reply_sz, sz, total_size, num_chain;
3606
3607 /* Prime reply FIFO... */
3608
3609 if (ioc->reply_frames == NULL) {
3610 if ( (num_chain = initChainBuffers(ioc)) < 0)
3611 return -1;
3612
3613 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3614 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3615 ioc->name, ioc->reply_sz, ioc->reply_depth));
3616 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3617 ioc->name, reply_sz, reply_sz));
3618
3619 sz = (ioc->req_sz * ioc->req_depth);
3620 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3621 ioc->name, ioc->req_sz, ioc->req_depth));
3622 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3623 ioc->name, sz, sz));
3624 total_size += sz;
3625
3626 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3627 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3628 ioc->name, ioc->req_sz, num_chain));
3629 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3630 ioc->name, sz, sz, num_chain));
3631
3632 total_size += sz;
3633 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3634 if (mem == NULL) {
3635 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3636 ioc->name);
3637 goto out_fail;
3638 }
3639
3640 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3641 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3642
3643 memset(mem, 0, total_size);
3644 ioc->alloc_total += total_size;
3645 ioc->alloc = mem;
3646 ioc->alloc_dma = alloc_dma;
3647 ioc->alloc_sz = total_size;
3648 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3649 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3650
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003651 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3652 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3653
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 alloc_dma += reply_sz;
3655 mem += reply_sz;
3656
3657 /* Request FIFO - WE manage this! */
3658
3659 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3660 ioc->req_frames_dma = alloc_dma;
3661
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003662 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 ioc->name, mem, (void *)(ulong)alloc_dma));
3664
3665 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3666
3667#if defined(CONFIG_MTRR) && 0
3668 /*
3669 * Enable Write Combining MTRR for IOC's memory region.
3670 * (at least as much as we can; "size and base must be
3671 * multiples of 4 kiB"
3672 */
3673 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3674 sz,
3675 MTRR_TYPE_WRCOMB, 1);
3676 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3677 ioc->name, ioc->req_frames_dma, sz));
3678#endif
3679
3680 for (i = 0; i < ioc->req_depth; i++) {
3681 alloc_dma += ioc->req_sz;
3682 mem += ioc->req_sz;
3683 }
3684
3685 ioc->ChainBuffer = mem;
3686 ioc->ChainBufferDMA = alloc_dma;
3687
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003688 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3690
3691 /* Initialize the free chain Q.
3692 */
3693
3694 INIT_LIST_HEAD(&ioc->FreeChainQ);
3695
3696 /* Post the chain buffers to the FreeChainQ.
3697 */
3698 mem = (u8 *)ioc->ChainBuffer;
3699 for (i=0; i < num_chain; i++) {
3700 mf = (MPT_FRAME_HDR *) mem;
3701 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3702 mem += ioc->req_sz;
3703 }
3704
3705 /* Initialize Request frames linked list
3706 */
3707 alloc_dma = ioc->req_frames_dma;
3708 mem = (u8 *) ioc->req_frames;
3709
3710 spin_lock_irqsave(&ioc->FreeQlock, flags);
3711 INIT_LIST_HEAD(&ioc->FreeQ);
3712 for (i = 0; i < ioc->req_depth; i++) {
3713 mf = (MPT_FRAME_HDR *) mem;
3714
3715 /* Queue REQUESTs *internally*! */
3716 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3717
3718 mem += ioc->req_sz;
3719 }
3720 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3721
3722 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3723 ioc->sense_buf_pool =
3724 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3725 if (ioc->sense_buf_pool == NULL) {
3726 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3727 ioc->name);
3728 goto out_fail;
3729 }
3730
3731 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3732 ioc->alloc_total += sz;
3733 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3734 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3735
3736 }
3737
3738 /* Post Reply frames to FIFO
3739 */
3740 alloc_dma = ioc->alloc_dma;
3741 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3742 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3743
3744 for (i = 0; i < ioc->reply_depth; i++) {
3745 /* Write each address to the IOC! */
3746 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3747 alloc_dma += ioc->reply_sz;
3748 }
3749
3750 return 0;
3751
3752out_fail:
3753 if (ioc->alloc != NULL) {
3754 sz = ioc->alloc_sz;
3755 pci_free_consistent(ioc->pcidev,
3756 sz,
3757 ioc->alloc, ioc->alloc_dma);
3758 ioc->reply_frames = NULL;
3759 ioc->req_frames = NULL;
3760 ioc->alloc_total -= sz;
3761 }
3762 if (ioc->sense_buf_pool != NULL) {
3763 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3764 pci_free_consistent(ioc->pcidev,
3765 sz,
3766 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3767 ioc->sense_buf_pool = NULL;
3768 }
3769 return -1;
3770}
3771
3772/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3773/**
3774 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3775 * from IOC via doorbell handshake method.
3776 * @ioc: Pointer to MPT_ADAPTER structure
3777 * @reqBytes: Size of the request in bytes
3778 * @req: Pointer to MPT request frame
3779 * @replyBytes: Expected size of the reply in bytes
3780 * @u16reply: Pointer to area where reply should be written
3781 * @maxwait: Max wait time for a reply (in seconds)
3782 * @sleepFlag: Specifies whether the process can sleep
3783 *
3784 * NOTES: It is the callers responsibility to byte-swap fields in the
3785 * request which are greater than 1 byte in size. It is also the
3786 * callers responsibility to byte-swap response fields which are
3787 * greater than 1 byte in size.
3788 *
3789 * Returns 0 for success, non-zero for failure.
3790 */
3791static int
3792mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003793 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794{
3795 MPIDefaultReply_t *mptReply;
3796 int failcnt = 0;
3797 int t;
3798
3799 /*
3800 * Get ready to cache a handshake reply
3801 */
3802 ioc->hs_reply_idx = 0;
3803 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3804 mptReply->MsgLength = 0;
3805
3806 /*
3807 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3808 * then tell IOC that we want to handshake a request of N words.
3809 * (WRITE u32val to Doorbell reg).
3810 */
3811 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3812 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3813 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3814 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3815
3816 /*
3817 * Wait for IOC's doorbell handshake int
3818 */
3819 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3820 failcnt++;
3821
3822 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3823 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3824
3825 /* Read doorbell and check for active bit */
3826 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3827 return -1;
3828
3829 /*
3830 * Clear doorbell int (WRITE 0 to IntStatus reg),
3831 * then wait for IOC to ACKnowledge that it's ready for
3832 * our handshake request.
3833 */
3834 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3835 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3836 failcnt++;
3837
3838 if (!failcnt) {
3839 int ii;
3840 u8 *req_as_bytes = (u8 *) req;
3841
3842 /*
3843 * Stuff request words via doorbell handshake,
3844 * with ACK from IOC for each.
3845 */
3846 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3847 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3848 (req_as_bytes[(ii*4) + 1] << 8) |
3849 (req_as_bytes[(ii*4) + 2] << 16) |
3850 (req_as_bytes[(ii*4) + 3] << 24));
3851
3852 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3853 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3854 failcnt++;
3855 }
3856
3857 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3858 DBG_DUMP_REQUEST_FRAME_HDR(req)
3859
3860 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3861 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3862
3863 /*
3864 * Wait for completion of doorbell handshake reply from the IOC
3865 */
3866 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3867 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003868
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3870 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3871
3872 /*
3873 * Copy out the cached reply...
3874 */
3875 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3876 u16reply[ii] = ioc->hs_reply[ii];
3877 } else {
3878 return -99;
3879 }
3880
3881 return -failcnt;
3882}
3883
3884/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3885/*
3886 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3887 * in it's IntStatus register.
3888 * @ioc: Pointer to MPT_ADAPTER structure
3889 * @howlong: How long to wait (in seconds)
3890 * @sleepFlag: Specifies whether the process can sleep
3891 *
3892 * This routine waits (up to ~2 seconds max) for IOC doorbell
3893 * handshake ACKnowledge.
3894 *
3895 * Returns a negative value on failure, else wait loop count.
3896 */
3897static int
3898WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3899{
3900 int cntdn;
3901 int count = 0;
3902 u32 intstat=0;
3903
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003904 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905
3906 if (sleepFlag == CAN_SLEEP) {
3907 while (--cntdn) {
3908 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3909 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3910 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05003911 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 count++;
3913 }
3914 } else {
3915 while (--cntdn) {
3916 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3917 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3918 break;
3919 mdelay (1);
3920 count++;
3921 }
3922 }
3923
3924 if (cntdn) {
3925 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3926 ioc->name, count));
3927 return count;
3928 }
3929
3930 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3931 ioc->name, count, intstat);
3932 return -1;
3933}
3934
3935/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3936/*
3937 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3938 * in it's IntStatus register.
3939 * @ioc: Pointer to MPT_ADAPTER structure
3940 * @howlong: How long to wait (in seconds)
3941 * @sleepFlag: Specifies whether the process can sleep
3942 *
3943 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3944 *
3945 * Returns a negative value on failure, else wait loop count.
3946 */
3947static int
3948WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3949{
3950 int cntdn;
3951 int count = 0;
3952 u32 intstat=0;
3953
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003954 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 if (sleepFlag == CAN_SLEEP) {
3956 while (--cntdn) {
3957 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3958 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3959 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05003960 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 count++;
3962 }
3963 } else {
3964 while (--cntdn) {
3965 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3966 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3967 break;
3968 mdelay(1);
3969 count++;
3970 }
3971 }
3972
3973 if (cntdn) {
3974 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3975 ioc->name, count, howlong));
3976 return count;
3977 }
3978
3979 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3980 ioc->name, count, intstat);
3981 return -1;
3982}
3983
3984/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3985/*
3986 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3987 * @ioc: Pointer to MPT_ADAPTER structure
3988 * @howlong: How long to wait (in seconds)
3989 * @sleepFlag: Specifies whether the process can sleep
3990 *
3991 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3992 * Reply is cached to IOC private area large enough to hold a maximum
3993 * of 128 bytes of reply data.
3994 *
3995 * Returns a negative value on failure, else size of reply in WORDS.
3996 */
3997static int
3998WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3999{
4000 int u16cnt = 0;
4001 int failcnt = 0;
4002 int t;
4003 u16 *hs_reply = ioc->hs_reply;
4004 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4005 u16 hword;
4006
4007 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4008
4009 /*
4010 * Get first two u16's so we can look at IOC's intended reply MsgLength
4011 */
4012 u16cnt=0;
4013 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4014 failcnt++;
4015 } else {
4016 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4017 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4018 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4019 failcnt++;
4020 else {
4021 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4022 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4023 }
4024 }
4025
4026 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004027 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4029
4030 /*
4031 * If no error (and IOC said MsgLength is > 0), piece together
4032 * reply 16 bits at a time.
4033 */
4034 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4035 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4036 failcnt++;
4037 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4038 /* don't overflow our IOC hs_reply[] buffer! */
4039 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4040 hs_reply[u16cnt] = hword;
4041 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4042 }
4043
4044 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4045 failcnt++;
4046 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4047
4048 if (failcnt) {
4049 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4050 ioc->name);
4051 return -failcnt;
4052 }
4053#if 0
4054 else if (u16cnt != (2 * mptReply->MsgLength)) {
4055 return -101;
4056 }
4057 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4058 return -102;
4059 }
4060#endif
4061
4062 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4063 DBG_DUMP_REPLY_FRAME(mptReply)
4064
4065 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4066 ioc->name, t, u16cnt/2));
4067 return u16cnt/2;
4068}
4069
4070/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4071/*
4072 * GetLanConfigPages - Fetch LANConfig pages.
4073 * @ioc: Pointer to MPT_ADAPTER structure
4074 *
4075 * Return: 0 for success
4076 * -ENOMEM if no memory available
4077 * -EPERM if not allowed due to ISR context
4078 * -EAGAIN if no msg frames currently available
4079 * -EFAULT for non-successful reply or no reply (timeout)
4080 */
4081static int
4082GetLanConfigPages(MPT_ADAPTER *ioc)
4083{
4084 ConfigPageHeader_t hdr;
4085 CONFIGPARMS cfg;
4086 LANPage0_t *ppage0_alloc;
4087 dma_addr_t page0_dma;
4088 LANPage1_t *ppage1_alloc;
4089 dma_addr_t page1_dma;
4090 int rc = 0;
4091 int data_sz;
4092 int copy_sz;
4093
4094 /* Get LAN Page 0 header */
4095 hdr.PageVersion = 0;
4096 hdr.PageLength = 0;
4097 hdr.PageNumber = 0;
4098 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004099 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 cfg.physAddr = -1;
4101 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4102 cfg.dir = 0;
4103 cfg.pageAddr = 0;
4104 cfg.timeout = 0;
4105
4106 if ((rc = mpt_config(ioc, &cfg)) != 0)
4107 return rc;
4108
4109 if (hdr.PageLength > 0) {
4110 data_sz = hdr.PageLength * 4;
4111 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4112 rc = -ENOMEM;
4113 if (ppage0_alloc) {
4114 memset((u8 *)ppage0_alloc, 0, data_sz);
4115 cfg.physAddr = page0_dma;
4116 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4117
4118 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4119 /* save the data */
4120 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4121 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4122
4123 }
4124
4125 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4126
4127 /* FIXME!
4128 * Normalize endianness of structure data,
4129 * by byte-swapping all > 1 byte fields!
4130 */
4131
4132 }
4133
4134 if (rc)
4135 return rc;
4136 }
4137
4138 /* Get LAN Page 1 header */
4139 hdr.PageVersion = 0;
4140 hdr.PageLength = 0;
4141 hdr.PageNumber = 1;
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
4149 if ((rc = mpt_config(ioc, &cfg)) != 0)
4150 return rc;
4151
4152 if (hdr.PageLength == 0)
4153 return 0;
4154
4155 data_sz = hdr.PageLength * 4;
4156 rc = -ENOMEM;
4157 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4158 if (ppage1_alloc) {
4159 memset((u8 *)ppage1_alloc, 0, data_sz);
4160 cfg.physAddr = page1_dma;
4161 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4162
4163 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4164 /* save the data */
4165 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4166 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4167 }
4168
4169 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4170
4171 /* FIXME!
4172 * Normalize endianness of structure data,
4173 * by byte-swapping all > 1 byte fields!
4174 */
4175
4176 }
4177
4178 return rc;
4179}
4180
4181/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4182/*
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004183 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4184 * @ioc: Pointer to MPT_ADAPTER structure
4185 * @sas_address: 64bit SAS Address for operation.
4186 * @target_id: specified target for operation
4187 * @bus: specified bus for operation
4188 * @persist_opcode: see below
4189 *
4190 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4191 * devices not currently present.
4192 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4193 *
4194 * NOTE: Don't use not this function during interrupt time.
4195 *
4196 * Returns: 0 for success, non-zero error
4197 */
4198
4199/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4200int
4201mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4202{
4203 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4204 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4205 MPT_FRAME_HDR *mf = NULL;
4206 MPIHeader_t *mpi_hdr;
4207
4208
4209 /* insure garbage is not sent to fw */
4210 switch(persist_opcode) {
4211
4212 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4213 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4214 break;
4215
4216 default:
4217 return -1;
4218 break;
4219 }
4220
4221 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4222
4223 /* Get a MF for this command.
4224 */
4225 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4226 printk("%s: no msg frames!\n",__FUNCTION__);
4227 return -1;
4228 }
4229
4230 mpi_hdr = (MPIHeader_t *) mf;
4231 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4232 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4233 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4234 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4235 sasIoUnitCntrReq->Operation = persist_opcode;
4236
4237 init_timer(&ioc->persist_timer);
4238 ioc->persist_timer.data = (unsigned long) ioc;
4239 ioc->persist_timer.function = mpt_timer_expired;
4240 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4241 ioc->persist_wait_done=0;
4242 add_timer(&ioc->persist_timer);
4243 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4244 wait_event(mpt_waitq, ioc->persist_wait_done);
4245
4246 sasIoUnitCntrReply =
4247 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4248 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4249 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4250 __FUNCTION__,
4251 sasIoUnitCntrReply->IOCStatus,
4252 sasIoUnitCntrReply->IOCLogInfo);
4253 return -1;
4254 }
4255
4256 printk("%s: success\n",__FUNCTION__);
4257 return 0;
4258}
4259
4260/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004261
4262static void
4263mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4264 MpiEventDataRaid_t * pRaidEventData)
4265{
4266 int volume;
4267 int reason;
4268 int disk;
4269 int status;
4270 int flags;
4271 int state;
4272
4273 volume = pRaidEventData->VolumeID;
4274 reason = pRaidEventData->ReasonCode;
4275 disk = pRaidEventData->PhysDiskNum;
4276 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4277 flags = (status >> 0) & 0xff;
4278 state = (status >> 8) & 0xff;
4279
4280 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4281 return;
4282 }
4283
4284 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4285 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4286 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4287 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4288 ioc->name, disk);
4289 } else {
4290 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4291 ioc->name, volume);
4292 }
4293
4294 switch(reason) {
4295 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4296 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4297 ioc->name);
4298 break;
4299
4300 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4301
4302 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4303 ioc->name);
4304 break;
4305
4306 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4307 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4308 ioc->name);
4309 break;
4310
4311 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4312 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4313 ioc->name,
4314 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4315 ? "optimal"
4316 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4317 ? "degraded"
4318 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4319 ? "failed"
4320 : "state unknown",
4321 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4322 ? ", enabled" : "",
4323 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4324 ? ", quiesced" : "",
4325 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4326 ? ", resync in progress" : "" );
4327 break;
4328
4329 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4330 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4331 ioc->name, disk);
4332 break;
4333
4334 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4335 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4336 ioc->name);
4337 break;
4338
4339 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4340 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4341 ioc->name);
4342 break;
4343
4344 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4345 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4346 ioc->name);
4347 break;
4348
4349 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4350 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4351 ioc->name,
4352 state == MPI_PHYSDISK0_STATUS_ONLINE
4353 ? "online"
4354 : state == MPI_PHYSDISK0_STATUS_MISSING
4355 ? "missing"
4356 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4357 ? "not compatible"
4358 : state == MPI_PHYSDISK0_STATUS_FAILED
4359 ? "failed"
4360 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4361 ? "initializing"
4362 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4363 ? "offline requested"
4364 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4365 ? "failed requested"
4366 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4367 ? "offline"
4368 : "state unknown",
4369 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4370 ? ", out of sync" : "",
4371 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4372 ? ", quiesced" : "" );
4373 break;
4374
4375 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4376 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4377 ioc->name, disk);
4378 break;
4379
4380 case MPI_EVENT_RAID_RC_SMART_DATA:
4381 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4382 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4383 break;
4384
4385 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4386 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4387 ioc->name, disk);
4388 break;
4389 }
4390}
4391
4392/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004393/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4395 * @ioc: Pointer to MPT_ADAPTER structure
4396 *
4397 * Returns: 0 for success
4398 * -ENOMEM if no memory available
4399 * -EPERM if not allowed due to ISR context
4400 * -EAGAIN if no msg frames currently available
4401 * -EFAULT for non-successful reply or no reply (timeout)
4402 */
4403static int
4404GetIoUnitPage2(MPT_ADAPTER *ioc)
4405{
4406 ConfigPageHeader_t hdr;
4407 CONFIGPARMS cfg;
4408 IOUnitPage2_t *ppage_alloc;
4409 dma_addr_t page_dma;
4410 int data_sz;
4411 int rc;
4412
4413 /* Get the page header */
4414 hdr.PageVersion = 0;
4415 hdr.PageLength = 0;
4416 hdr.PageNumber = 2;
4417 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004418 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 cfg.physAddr = -1;
4420 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4421 cfg.dir = 0;
4422 cfg.pageAddr = 0;
4423 cfg.timeout = 0;
4424
4425 if ((rc = mpt_config(ioc, &cfg)) != 0)
4426 return rc;
4427
4428 if (hdr.PageLength == 0)
4429 return 0;
4430
4431 /* Read the config page */
4432 data_sz = hdr.PageLength * 4;
4433 rc = -ENOMEM;
4434 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4435 if (ppage_alloc) {
4436 memset((u8 *)ppage_alloc, 0, data_sz);
4437 cfg.physAddr = page_dma;
4438 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4439
4440 /* If Good, save data */
4441 if ((rc = mpt_config(ioc, &cfg)) == 0)
4442 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4443
4444 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4445 }
4446
4447 return rc;
4448}
4449
4450/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4451/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4452 * @ioc: Pointer to a Adapter Strucutre
4453 * @portnum: IOC port number
4454 *
4455 * Return: -EFAULT if read of config page header fails
4456 * or if no nvram
4457 * If read of SCSI Port Page 0 fails,
4458 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4459 * Adapter settings: async, narrow
4460 * Return 1
4461 * If read of SCSI Port Page 2 fails,
4462 * Adapter settings valid
4463 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4464 * Return 1
4465 * Else
4466 * Both valid
4467 * Return 0
4468 * CHECK - what type of locking mechanisms should be used????
4469 */
4470static int
4471mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4472{
4473 u8 *pbuf;
4474 dma_addr_t buf_dma;
4475 CONFIGPARMS cfg;
4476 ConfigPageHeader_t header;
4477 int ii;
4478 int data, rc = 0;
4479
4480 /* Allocate memory
4481 */
4482 if (!ioc->spi_data.nvram) {
4483 int sz;
4484 u8 *mem;
4485 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4486 mem = kmalloc(sz, GFP_ATOMIC);
4487 if (mem == NULL)
4488 return -EFAULT;
4489
4490 ioc->spi_data.nvram = (int *) mem;
4491
4492 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4493 ioc->name, ioc->spi_data.nvram, sz));
4494 }
4495
4496 /* Invalidate NVRAM information
4497 */
4498 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4499 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4500 }
4501
4502 /* Read SPP0 header, allocate memory, then read page.
4503 */
4504 header.PageVersion = 0;
4505 header.PageLength = 0;
4506 header.PageNumber = 0;
4507 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004508 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 cfg.physAddr = -1;
4510 cfg.pageAddr = portnum;
4511 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4512 cfg.dir = 0;
4513 cfg.timeout = 0; /* use default */
4514 if (mpt_config(ioc, &cfg) != 0)
4515 return -EFAULT;
4516
4517 if (header.PageLength > 0) {
4518 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4519 if (pbuf) {
4520 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4521 cfg.physAddr = buf_dma;
4522 if (mpt_config(ioc, &cfg) != 0) {
4523 ioc->spi_data.maxBusWidth = MPT_NARROW;
4524 ioc->spi_data.maxSyncOffset = 0;
4525 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4526 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4527 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004528 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4529 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 } else {
4531 /* Save the Port Page 0 data
4532 */
4533 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4534 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4535 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4536
4537 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4538 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004539 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 ioc->name, pPP0->Capabilities));
4541 }
4542 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4543 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4544 if (data) {
4545 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4546 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4547 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004548 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4549 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 } else {
4551 ioc->spi_data.maxSyncOffset = 0;
4552 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4553 }
4554
4555 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4556
4557 /* Update the minSyncFactor based on bus type.
4558 */
4559 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4560 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4561
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004562 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004564 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4565 ioc->name, ioc->spi_data.minSyncFactor));
4566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 }
4568 }
4569 if (pbuf) {
4570 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4571 }
4572 }
4573 }
4574
4575 /* SCSI Port Page 2 - Read the header then the page.
4576 */
4577 header.PageVersion = 0;
4578 header.PageLength = 0;
4579 header.PageNumber = 2;
4580 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004581 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 cfg.physAddr = -1;
4583 cfg.pageAddr = portnum;
4584 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4585 cfg.dir = 0;
4586 if (mpt_config(ioc, &cfg) != 0)
4587 return -EFAULT;
4588
4589 if (header.PageLength > 0) {
4590 /* Allocate memory and read SCSI Port Page 2
4591 */
4592 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4593 if (pbuf) {
4594 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4595 cfg.physAddr = buf_dma;
4596 if (mpt_config(ioc, &cfg) != 0) {
4597 /* Nvram data is left with INVALID mark
4598 */
4599 rc = 1;
4600 } else {
4601 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4602 MpiDeviceInfo_t *pdevice = NULL;
4603
Moore, Ericd8e925d2006-01-16 18:53:06 -07004604 /*
4605 * Save "Set to Avoid SCSI Bus Resets" flag
4606 */
4607 ioc->spi_data.bus_reset =
4608 (le32_to_cpu(pPP2->PortFlags) &
4609 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4610 0 : 1 ;
4611
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 /* Save the Port Page 2 data
4613 * (reformat into a 32bit quantity)
4614 */
4615 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4616 ioc->spi_data.PortFlags = data;
4617 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4618 pdevice = &pPP2->DeviceSettings[ii];
4619 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4620 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4621 ioc->spi_data.nvram[ii] = data;
4622 }
4623 }
4624
4625 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4626 }
4627 }
4628
4629 /* Update Adapter limits with those from NVRAM
4630 * Comment: Don't need to do this. Target performance
4631 * parameters will never exceed the adapters limits.
4632 */
4633
4634 return rc;
4635}
4636
4637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4638/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4639 * @ioc: Pointer to a Adapter Strucutre
4640 * @portnum: IOC port number
4641 *
4642 * Return: -EFAULT if read of config page header fails
4643 * or 0 if success.
4644 */
4645static int
4646mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4647{
4648 CONFIGPARMS cfg;
4649 ConfigPageHeader_t header;
4650
4651 /* Read the SCSI Device Page 1 header
4652 */
4653 header.PageVersion = 0;
4654 header.PageLength = 0;
4655 header.PageNumber = 1;
4656 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004657 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 cfg.physAddr = -1;
4659 cfg.pageAddr = portnum;
4660 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4661 cfg.dir = 0;
4662 cfg.timeout = 0;
4663 if (mpt_config(ioc, &cfg) != 0)
4664 return -EFAULT;
4665
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004666 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4667 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668
4669 header.PageVersion = 0;
4670 header.PageLength = 0;
4671 header.PageNumber = 0;
4672 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4673 if (mpt_config(ioc, &cfg) != 0)
4674 return -EFAULT;
4675
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004676 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4677 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678
4679 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4680 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4681
4682 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4683 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4684 return 0;
4685}
4686
4687/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4688/**
4689 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4690 * @ioc: Pointer to a Adapter Strucutre
4691 * @portnum: IOC port number
4692 *
4693 * Return:
4694 * 0 on success
4695 * -EFAULT if read of config page header fails or data pointer not NULL
4696 * -ENOMEM if pci_alloc failed
4697 */
4698int
4699mpt_findImVolumes(MPT_ADAPTER *ioc)
4700{
4701 IOCPage2_t *pIoc2;
4702 u8 *mem;
4703 ConfigPageIoc2RaidVol_t *pIocRv;
4704 dma_addr_t ioc2_dma;
4705 CONFIGPARMS cfg;
4706 ConfigPageHeader_t header;
4707 int jj;
4708 int rc = 0;
4709 int iocpage2sz;
4710 u8 nVols, nPhys;
4711 u8 vid, vbus, vioc;
4712
4713 /* Read IOCP2 header then the page.
4714 */
4715 header.PageVersion = 0;
4716 header.PageLength = 0;
4717 header.PageNumber = 2;
4718 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004719 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 cfg.physAddr = -1;
4721 cfg.pageAddr = 0;
4722 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4723 cfg.dir = 0;
4724 cfg.timeout = 0;
4725 if (mpt_config(ioc, &cfg) != 0)
4726 return -EFAULT;
4727
4728 if (header.PageLength == 0)
4729 return -EFAULT;
4730
4731 iocpage2sz = header.PageLength * 4;
4732 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4733 if (!pIoc2)
4734 return -ENOMEM;
4735
4736 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4737 cfg.physAddr = ioc2_dma;
4738 if (mpt_config(ioc, &cfg) != 0)
4739 goto done_and_free;
4740
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004741 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4743 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004744 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 } else {
4746 goto done_and_free;
4747 }
4748 }
4749 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4750
4751 /* Identify RAID Volume Id's */
4752 nVols = pIoc2->NumActiveVolumes;
4753 if ( nVols == 0) {
4754 /* No RAID Volume.
4755 */
4756 goto done_and_free;
4757 } else {
4758 /* At least 1 RAID Volume
4759 */
4760 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004761 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4763 vid = pIocRv->VolumeID;
4764 vbus = pIocRv->VolumeBus;
4765 vioc = pIocRv->VolumeIOC;
4766
4767 /* find the match
4768 */
4769 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004770 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 } else {
4772 /* Error! Always bus 0
4773 */
4774 }
4775 }
4776 }
4777
4778 /* Identify Hidden Physical Disk Id's */
4779 nPhys = pIoc2->NumActivePhysDisks;
4780 if (nPhys == 0) {
4781 /* No physical disks.
4782 */
4783 } else {
4784 mpt_read_ioc_pg_3(ioc);
4785 }
4786
4787done_and_free:
4788 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4789
4790 return rc;
4791}
4792
Moore, Ericc972c702006-03-14 09:14:06 -07004793static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4795{
4796 IOCPage3_t *pIoc3;
4797 u8 *mem;
4798 CONFIGPARMS cfg;
4799 ConfigPageHeader_t header;
4800 dma_addr_t ioc3_dma;
4801 int iocpage3sz = 0;
4802
4803 /* Free the old page
4804 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004805 kfree(ioc->raid_data.pIocPg3);
4806 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
4808 /* There is at least one physical disk.
4809 * Read and save IOC Page 3
4810 */
4811 header.PageVersion = 0;
4812 header.PageLength = 0;
4813 header.PageNumber = 3;
4814 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004815 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 cfg.physAddr = -1;
4817 cfg.pageAddr = 0;
4818 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4819 cfg.dir = 0;
4820 cfg.timeout = 0;
4821 if (mpt_config(ioc, &cfg) != 0)
4822 return 0;
4823
4824 if (header.PageLength == 0)
4825 return 0;
4826
4827 /* Read Header good, alloc memory
4828 */
4829 iocpage3sz = header.PageLength * 4;
4830 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4831 if (!pIoc3)
4832 return 0;
4833
4834 /* Read the Page and save the data
4835 * into malloc'd memory.
4836 */
4837 cfg.physAddr = ioc3_dma;
4838 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4839 if (mpt_config(ioc, &cfg) == 0) {
4840 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4841 if (mem) {
4842 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004843 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 }
4845 }
4846
4847 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4848
4849 return 0;
4850}
4851
4852static void
4853mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4854{
4855 IOCPage4_t *pIoc4;
4856 CONFIGPARMS cfg;
4857 ConfigPageHeader_t header;
4858 dma_addr_t ioc4_dma;
4859 int iocpage4sz;
4860
4861 /* Read and save IOC Page 4
4862 */
4863 header.PageVersion = 0;
4864 header.PageLength = 0;
4865 header.PageNumber = 4;
4866 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004867 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 cfg.physAddr = -1;
4869 cfg.pageAddr = 0;
4870 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4871 cfg.dir = 0;
4872 cfg.timeout = 0;
4873 if (mpt_config(ioc, &cfg) != 0)
4874 return;
4875
4876 if (header.PageLength == 0)
4877 return;
4878
4879 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4880 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4881 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4882 if (!pIoc4)
4883 return;
4884 } else {
4885 ioc4_dma = ioc->spi_data.IocPg4_dma;
4886 iocpage4sz = ioc->spi_data.IocPg4Sz;
4887 }
4888
4889 /* Read the Page into dma memory.
4890 */
4891 cfg.physAddr = ioc4_dma;
4892 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4893 if (mpt_config(ioc, &cfg) == 0) {
4894 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4895 ioc->spi_data.IocPg4_dma = ioc4_dma;
4896 ioc->spi_data.IocPg4Sz = iocpage4sz;
4897 } else {
4898 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4899 ioc->spi_data.pIocPg4 = NULL;
4900 }
4901}
4902
4903static void
4904mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4905{
4906 IOCPage1_t *pIoc1;
4907 CONFIGPARMS cfg;
4908 ConfigPageHeader_t header;
4909 dma_addr_t ioc1_dma;
4910 int iocpage1sz = 0;
4911 u32 tmp;
4912
4913 /* Check the Coalescing Timeout in IOC Page 1
4914 */
4915 header.PageVersion = 0;
4916 header.PageLength = 0;
4917 header.PageNumber = 1;
4918 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004919 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 cfg.physAddr = -1;
4921 cfg.pageAddr = 0;
4922 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4923 cfg.dir = 0;
4924 cfg.timeout = 0;
4925 if (mpt_config(ioc, &cfg) != 0)
4926 return;
4927
4928 if (header.PageLength == 0)
4929 return;
4930
4931 /* Read Header good, alloc memory
4932 */
4933 iocpage1sz = header.PageLength * 4;
4934 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
4935 if (!pIoc1)
4936 return;
4937
4938 /* Read the Page and check coalescing timeout
4939 */
4940 cfg.physAddr = ioc1_dma;
4941 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4942 if (mpt_config(ioc, &cfg) == 0) {
4943
4944 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
4945 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
4946 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
4947
4948 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
4949 ioc->name, tmp));
4950
4951 if (tmp > MPT_COALESCING_TIMEOUT) {
4952 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
4953
4954 /* Write NVRAM and current
4955 */
4956 cfg.dir = 1;
4957 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4958 if (mpt_config(ioc, &cfg) == 0) {
4959 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
4960 ioc->name, MPT_COALESCING_TIMEOUT));
4961
4962 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
4963 if (mpt_config(ioc, &cfg) == 0) {
4964 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
4965 ioc->name, MPT_COALESCING_TIMEOUT));
4966 } else {
4967 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
4968 ioc->name));
4969 }
4970
4971 } else {
4972 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
4973 ioc->name));
4974 }
4975 }
4976
4977 } else {
4978 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
4979 }
4980 }
4981
4982 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
4983
4984 return;
4985}
4986
4987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4988/*
4989 * SendEventNotification - Send EventNotification (on or off) request
4990 * to MPT adapter.
4991 * @ioc: Pointer to MPT_ADAPTER structure
4992 * @EvSwitch: Event switch flags
4993 */
4994static int
4995SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
4996{
4997 EventNotification_t *evnp;
4998
4999 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5000 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005001 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 ioc->name));
5003 return 0;
5004 }
5005 memset(evnp, 0, sizeof(*evnp));
5006
Moore, Eric3a892be2006-03-14 09:14:03 -07005007 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008
5009 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5010 evnp->ChainOffset = 0;
5011 evnp->MsgFlags = 0;
5012 evnp->Switch = EvSwitch;
5013
5014 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5015
5016 return 0;
5017}
5018
5019/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5020/**
5021 * SendEventAck - Send EventAck request to MPT adapter.
5022 * @ioc: Pointer to MPT_ADAPTER structure
5023 * @evnp: Pointer to original EventNotification request
5024 */
5025static int
5026SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5027{
5028 EventAck_t *pAck;
5029
5030 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Eric Moore4f766dc2006-07-11 17:24:07 -06005031 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
5032 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 return -1;
5034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
Eric Moore4f766dc2006-07-11 17:24:07 -06005036 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037
5038 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5039 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005040 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005042 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 pAck->Event = evnp->Event;
5044 pAck->EventContext = evnp->EventContext;
5045
5046 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5047
5048 return 0;
5049}
5050
5051/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5052/**
5053 * mpt_config - Generic function to issue config message
5054 * @ioc - Pointer to an adapter structure
5055 * @cfg - Pointer to a configuration structure. Struct contains
5056 * action, page address, direction, physical address
5057 * and pointer to a configuration page header
5058 * Page header is updated.
5059 *
5060 * Returns 0 for success
5061 * -EPERM if not allowed due to ISR context
5062 * -EAGAIN if no msg frames currently available
5063 * -EFAULT for non-successful reply or no reply (timeout)
5064 */
5065int
5066mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5067{
5068 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005069 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 MPT_FRAME_HDR *mf;
5071 unsigned long flags;
5072 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005073 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 int in_isr;
5075
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005076 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 * to be in ISR context, because that is fatal!
5078 */
5079 in_isr = in_interrupt();
5080 if (in_isr) {
5081 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5082 ioc->name));
5083 return -EPERM;
5084 }
5085
5086 /* Get and Populate a free Frame
5087 */
5088 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5089 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5090 ioc->name));
5091 return -EAGAIN;
5092 }
5093 pReq = (Config_t *)mf;
5094 pReq->Action = pCfg->action;
5095 pReq->Reserved = 0;
5096 pReq->ChainOffset = 0;
5097 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005098
5099 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 pReq->ExtPageLength = 0;
5101 pReq->ExtPageType = 0;
5102 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005103
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 for (ii=0; ii < 8; ii++)
5105 pReq->Reserved2[ii] = 0;
5106
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005107 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5108 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5109 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5110 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5111
5112 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5113 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5114 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5115 pReq->ExtPageType = pExtHdr->ExtPageType;
5116 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5117
5118 /* Page Length must be treated as a reserved field for the extended header. */
5119 pReq->Header.PageLength = 0;
5120 }
5121
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5123
5124 /* Add a SGE to the config request.
5125 */
5126 if (pCfg->dir)
5127 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5128 else
5129 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5130
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005131 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5132 flagsLength |= pExtHdr->ExtPageLength * 4;
5133
5134 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5135 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5136 }
5137 else {
5138 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5139
5140 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5141 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143
5144 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5145
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 /* Append pCfg pointer to end of mf
5147 */
5148 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5149
5150 /* Initalize the timer
5151 */
5152 init_timer(&pCfg->timer);
5153 pCfg->timer.data = (unsigned long) ioc;
5154 pCfg->timer.function = mpt_timer_expired;
5155 pCfg->wait_done = 0;
5156
5157 /* Set the timer; ensure 10 second minimum */
5158 if (pCfg->timeout < 10)
5159 pCfg->timer.expires = jiffies + HZ*10;
5160 else
5161 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5162
5163 /* Add to end of Q, set timer and then issue this command */
5164 spin_lock_irqsave(&ioc->FreeQlock, flags);
5165 list_add_tail(&pCfg->linkage, &ioc->configQ);
5166 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5167
5168 add_timer(&pCfg->timer);
5169 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5170 wait_event(mpt_waitq, pCfg->wait_done);
5171
5172 /* mf has been freed - do not access */
5173
5174 rc = pCfg->status;
5175
5176 return rc;
5177}
5178
5179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180/*
5181 * mpt_timer_expired - Call back for timer process.
5182 * Used only internal config functionality.
5183 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5184 */
5185static void
5186mpt_timer_expired(unsigned long data)
5187{
5188 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5189
5190 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5191
5192 /* Perform a FW reload */
5193 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5194 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5195
5196 /* No more processing.
5197 * Hard reset clean-up will wake up
5198 * process and free all resources.
5199 */
5200 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5201
5202 return;
5203}
5204
5205/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5206/*
5207 * mpt_ioc_reset - Base cleanup for hard reset
5208 * @ioc: Pointer to the adapter structure
5209 * @reset_phase: Indicates pre- or post-reset functionality
5210 *
5211 * Remark: Free's resources with internally generated commands.
5212 */
5213static int
5214mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5215{
5216 CONFIGPARMS *pCfg;
5217 unsigned long flags;
5218
5219 dprintk((KERN_WARNING MYNAM
5220 ": IOC %s_reset routed to MPT base driver!\n",
5221 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5222 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5223
5224 if (reset_phase == MPT_IOC_SETUP_RESET) {
5225 ;
5226 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5227 /* If the internal config Q is not empty -
5228 * delete timer. MF resources will be freed when
5229 * the FIFO's are primed.
5230 */
5231 spin_lock_irqsave(&ioc->FreeQlock, flags);
5232 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5233 del_timer(&pCfg->timer);
5234 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5235
5236 } else {
5237 CONFIGPARMS *pNext;
5238
5239 /* Search the configQ for internal commands.
5240 * Flush the Q, and wake up all suspended threads.
5241 */
5242 spin_lock_irqsave(&ioc->FreeQlock, flags);
5243 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5244 list_del(&pCfg->linkage);
5245
5246 pCfg->status = MPT_CONFIG_ERROR;
5247 pCfg->wait_done = 1;
5248 wake_up(&mpt_waitq);
5249 }
5250 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5251 }
5252
5253 return 1; /* currently means nothing really */
5254}
5255
5256
5257#ifdef CONFIG_PROC_FS /* { */
5258/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5259/*
5260 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5261 */
5262/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5263/*
5264 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5265 *
5266 * Returns 0 for success, non-zero for failure.
5267 */
5268static int
5269procmpt_create(void)
5270{
5271 struct proc_dir_entry *ent;
5272
5273 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5274 if (mpt_proc_root_dir == NULL)
5275 return -ENOTDIR;
5276
5277 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5278 if (ent)
5279 ent->read_proc = procmpt_summary_read;
5280
5281 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5282 if (ent)
5283 ent->read_proc = procmpt_version_read;
5284
5285 return 0;
5286}
5287
5288/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5289/*
5290 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5291 *
5292 * Returns 0 for success, non-zero for failure.
5293 */
5294static void
5295procmpt_destroy(void)
5296{
5297 remove_proc_entry("version", mpt_proc_root_dir);
5298 remove_proc_entry("summary", mpt_proc_root_dir);
5299 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5300}
5301
5302/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5303/*
5304 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5305 * or from /proc/mpt/iocN/summary.
5306 * @buf: Pointer to area to write information
5307 * @start: Pointer to start pointer
5308 * @offset: Offset to start writing
5309 * @request:
5310 * @eof: Pointer to EOF integer
5311 * @data: Pointer
5312 *
5313 * Returns number of characters written to process performing the read.
5314 */
5315static int
5316procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5317{
5318 MPT_ADAPTER *ioc;
5319 char *out = buf;
5320 int len;
5321
5322 if (data) {
5323 int more = 0;
5324
5325 ioc = data;
5326 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5327
5328 out += more;
5329 } else {
5330 list_for_each_entry(ioc, &ioc_list, list) {
5331 int more = 0;
5332
5333 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5334
5335 out += more;
5336 if ((out-buf) >= request)
5337 break;
5338 }
5339 }
5340
5341 len = out - buf;
5342
5343 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5344}
5345
5346/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5347/*
5348 * procmpt_version_read - Handle read request from /proc/mpt/version.
5349 * @buf: Pointer to area to write information
5350 * @start: Pointer to start pointer
5351 * @offset: Offset to start writing
5352 * @request:
5353 * @eof: Pointer to EOF integer
5354 * @data: Pointer
5355 *
5356 * Returns number of characters written to process performing the read.
5357 */
5358static int
5359procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5360{
5361 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005362 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 char *drvname;
5364 int len;
5365
5366 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5367 len += sprintf(buf+len, " Fusion MPT base driver\n");
5368
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005369 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5371 drvname = NULL;
5372 if (MptCallbacks[ii]) {
5373 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005374 case MPTSPI_DRIVER:
5375 if (!scsi++) drvname = "SPI host";
5376 break;
5377 case MPTFC_DRIVER:
5378 if (!fc++) drvname = "FC host";
5379 break;
5380 case MPTSAS_DRIVER:
5381 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 break;
5383 case MPTLAN_DRIVER:
5384 if (!lan++) drvname = "LAN";
5385 break;
5386 case MPTSTM_DRIVER:
5387 if (!targ++) drvname = "SCSI target";
5388 break;
5389 case MPTCTL_DRIVER:
5390 if (!ctl++) drvname = "ioctl";
5391 break;
5392 }
5393
5394 if (drvname)
5395 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5396 }
5397 }
5398
5399 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5400}
5401
5402/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5403/*
5404 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5405 * @buf: Pointer to area to write information
5406 * @start: Pointer to start pointer
5407 * @offset: Offset to start writing
5408 * @request:
5409 * @eof: Pointer to EOF integer
5410 * @data: Pointer
5411 *
5412 * Returns number of characters written to process performing the read.
5413 */
5414static int
5415procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5416{
5417 MPT_ADAPTER *ioc = data;
5418 int len;
5419 char expVer[32];
5420 int sz;
5421 int p;
5422
5423 mpt_get_fw_exp_ver(expVer, ioc);
5424
5425 len = sprintf(buf, "%s:", ioc->name);
5426 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5427 len += sprintf(buf+len, " (f/w download boot flag set)");
5428// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5429// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5430
5431 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5432 ioc->facts.ProductID,
5433 ioc->prod_name);
5434 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5435 if (ioc->facts.FWImageSize)
5436 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5437 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5438 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5439 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5440
5441 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5442 ioc->facts.CurrentHostMfaHighAddr);
5443 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5444 ioc->facts.CurrentSenseBufferHighAddr);
5445
5446 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5447 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5448
5449 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5450 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5451 /*
5452 * Rounding UP to nearest 4-kB boundary here...
5453 */
5454 sz = (ioc->req_sz * ioc->req_depth) + 128;
5455 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5456 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5457 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5458 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5459 4*ioc->facts.RequestFrameSize,
5460 ioc->facts.GlobalCredits);
5461
5462 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5463 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5464 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5465 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5466 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5467 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5468 ioc->facts.CurReplyFrameSize,
5469 ioc->facts.ReplyQueueDepth);
5470
5471 len += sprintf(buf+len, " MaxDevices = %d\n",
5472 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5473 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5474
5475 /* per-port info */
5476 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5477 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5478 p+1,
5479 ioc->facts.NumberOfPorts);
5480 if (ioc->bus_type == FC) {
5481 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5482 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5483 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5484 a[5], a[4], a[3], a[2], a[1], a[0]);
5485 }
5486 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5487 ioc->fc_port_page0[p].WWNN.High,
5488 ioc->fc_port_page0[p].WWNN.Low,
5489 ioc->fc_port_page0[p].WWPN.High,
5490 ioc->fc_port_page0[p].WWPN.Low);
5491 }
5492 }
5493
5494 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5495}
5496
5497#endif /* CONFIG_PROC_FS } */
5498
5499/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5500static void
5501mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5502{
5503 buf[0] ='\0';
5504 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5505 sprintf(buf, " (Exp %02d%02d)",
5506 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5507 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5508
5509 /* insider hack! */
5510 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5511 strcat(buf, " [MDBG]");
5512 }
5513}
5514
5515/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5516/**
5517 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5518 * @ioc: Pointer to MPT_ADAPTER structure
5519 * @buffer: Pointer to buffer where IOC summary info should be written
5520 * @size: Pointer to number of bytes we wrote (set by this routine)
5521 * @len: Offset at which to start writing in buffer
5522 * @showlan: Display LAN stuff?
5523 *
5524 * This routine writes (english readable) ASCII text, which represents
5525 * a summary of IOC information, to a buffer.
5526 */
5527void
5528mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5529{
5530 char expVer[32];
5531 int y;
5532
5533 mpt_get_fw_exp_ver(expVer, ioc);
5534
5535 /*
5536 * Shorter summary of attached ioc's...
5537 */
5538 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5539 ioc->name,
5540 ioc->prod_name,
5541 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5542 ioc->facts.FWVersion.Word,
5543 expVer,
5544 ioc->facts.NumberOfPorts,
5545 ioc->req_depth);
5546
5547 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5548 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5549 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5550 a[5], a[4], a[3], a[2], a[1], a[0]);
5551 }
5552
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554
5555 if (!ioc->active)
5556 y += sprintf(buffer+len+y, " (disabled)");
5557
5558 y += sprintf(buffer+len+y, "\n");
5559
5560 *size = y;
5561}
5562
5563/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5564/*
5565 * Reset Handling
5566 */
5567/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5568/**
5569 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5570 * Management call based on input arg values. If TaskMgmt fails,
5571 * return associated SCSI request.
5572 * @ioc: Pointer to MPT_ADAPTER structure
5573 * @sleepFlag: Indicates if sleep or schedule must be called.
5574 *
5575 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5576 * or a non-interrupt thread. In the former, must not call schedule().
5577 *
5578 * Remark: A return of -1 is a FATAL error case, as it means a
5579 * FW reload/initialization failed.
5580 *
5581 * Returns 0 for SUCCESS or -1 if FAILED.
5582 */
5583int
5584mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5585{
5586 int rc;
5587 unsigned long flags;
5588
5589 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5590#ifdef MFCNT
5591 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5592 printk("MF count 0x%x !\n", ioc->mfcnt);
5593#endif
5594
5595 /* Reset the adapter. Prevent more than 1 call to
5596 * mpt_do_ioc_recovery at any instant in time.
5597 */
5598 spin_lock_irqsave(&ioc->diagLock, flags);
5599 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5600 spin_unlock_irqrestore(&ioc->diagLock, flags);
5601 return 0;
5602 } else {
5603 ioc->diagPending = 1;
5604 }
5605 spin_unlock_irqrestore(&ioc->diagLock, flags);
5606
5607 /* FIXME: If do_ioc_recovery fails, repeat....
5608 */
5609
5610 /* The SCSI driver needs to adjust timeouts on all current
5611 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02005612 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613 * For all other protocol drivers, this is a no-op.
5614 */
5615 {
5616 int ii;
5617 int r = 0;
5618
5619 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5620 if (MptResetHandlers[ii]) {
5621 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5622 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005623 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 if (ioc->alt_ioc) {
5625 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5626 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005627 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 }
5629 }
5630 }
5631 }
5632
5633 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5634 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5635 rc, ioc->name);
5636 }
5637 ioc->reload_fw = 0;
5638 if (ioc->alt_ioc)
5639 ioc->alt_ioc->reload_fw = 0;
5640
5641 spin_lock_irqsave(&ioc->diagLock, flags);
5642 ioc->diagPending = 0;
5643 if (ioc->alt_ioc)
5644 ioc->alt_ioc->diagPending = 0;
5645 spin_unlock_irqrestore(&ioc->diagLock, flags);
5646
5647 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5648
5649 return rc;
5650}
5651
Eric Moore509e5e52006-04-26 13:22:37 -06005652# define EVENT_DESCR_STR_SZ 100
5653
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005655static void
5656EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657{
Eric Moore509e5e52006-04-26 13:22:37 -06005658 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659
5660 switch(event) {
5661 case MPI_EVENT_NONE:
5662 ds = "None";
5663 break;
5664 case MPI_EVENT_LOG_DATA:
5665 ds = "Log Data";
5666 break;
5667 case MPI_EVENT_STATE_CHANGE:
5668 ds = "State Change";
5669 break;
5670 case MPI_EVENT_UNIT_ATTENTION:
5671 ds = "Unit Attention";
5672 break;
5673 case MPI_EVENT_IOC_BUS_RESET:
5674 ds = "IOC Bus Reset";
5675 break;
5676 case MPI_EVENT_EXT_BUS_RESET:
5677 ds = "External Bus Reset";
5678 break;
5679 case MPI_EVENT_RESCAN:
5680 ds = "Bus Rescan Event";
5681 /* Ok, do we need to do anything here? As far as
5682 I can tell, this is when a new device gets added
5683 to the loop. */
5684 break;
5685 case MPI_EVENT_LINK_STATUS_CHANGE:
5686 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5687 ds = "Link Status(FAILURE) Change";
5688 else
5689 ds = "Link Status(ACTIVE) Change";
5690 break;
5691 case MPI_EVENT_LOOP_STATE_CHANGE:
5692 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5693 ds = "Loop State(LIP) Change";
5694 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005695 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 else
Eric Moore509e5e52006-04-26 13:22:37 -06005697 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698 break;
5699 case MPI_EVENT_LOGOUT:
5700 ds = "Logout";
5701 break;
5702 case MPI_EVENT_EVENT_CHANGE:
5703 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06005704 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705 else
Eric Moore4f766dc2006-07-11 17:24:07 -06005706 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707 break;
5708 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005709 {
5710 u8 ReasonCode = (u8)(evData0 >> 16);
5711 switch (ReasonCode) {
5712 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5713 ds = "Integrated Raid: Volume Created";
5714 break;
5715 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5716 ds = "Integrated Raid: Volume Deleted";
5717 break;
5718 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5719 ds = "Integrated Raid: Volume Settings Changed";
5720 break;
5721 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5722 ds = "Integrated Raid: Volume Status Changed";
5723 break;
5724 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5725 ds = "Integrated Raid: Volume Physdisk Changed";
5726 break;
5727 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5728 ds = "Integrated Raid: Physdisk Created";
5729 break;
5730 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5731 ds = "Integrated Raid: Physdisk Deleted";
5732 break;
5733 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5734 ds = "Integrated Raid: Physdisk Settings Changed";
5735 break;
5736 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5737 ds = "Integrated Raid: Physdisk Status Changed";
5738 break;
5739 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5740 ds = "Integrated Raid: Domain Validation Needed";
5741 break;
5742 case MPI_EVENT_RAID_RC_SMART_DATA :
5743 ds = "Integrated Raid; Smart Data";
5744 break;
5745 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5746 ds = "Integrated Raid: Replace Action Started";
5747 break;
5748 default:
5749 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005751 }
5752 break;
5753 }
5754 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5755 ds = "SCSI Device Status Change";
5756 break;
5757 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5758 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005759 u8 id = (u8)(evData0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005760 u8 ReasonCode = (u8)(evData0 >> 16);
5761 switch (ReasonCode) {
5762 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005763 snprintf(evStr, EVENT_DESCR_STR_SZ,
5764 "SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005765 break;
5766 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005767 snprintf(evStr, EVENT_DESCR_STR_SZ,
5768 "SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005769 break;
5770 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005771 snprintf(evStr, EVENT_DESCR_STR_SZ,
5772 "SAS Device Status Change: SMART Data: id=%d",
5773 id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005774 break;
5775 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005776 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moore4f766dc2006-07-11 17:24:07 -06005777 "SAS Device Status Change: No Persistancy: id=%d", id);
5778 break;
5779 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
5780 snprintf(evStr, EVENT_DESCR_STR_SZ,
5781 "SAS Device Status Change: Internal Device Reset : id=%d", id);
5782 break;
5783 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
5784 snprintf(evStr, EVENT_DESCR_STR_SZ,
5785 "SAS Device Status Change: Internal Task Abort : id=%d", id);
5786 break;
5787 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
5788 snprintf(evStr, EVENT_DESCR_STR_SZ,
5789 "SAS Device Status Change: Internal Abort Task Set : id=%d", id);
5790 break;
5791 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
5792 snprintf(evStr, EVENT_DESCR_STR_SZ,
5793 "SAS Device Status Change: Internal Clear Task Set : id=%d", id);
5794 break;
5795 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
5796 snprintf(evStr, EVENT_DESCR_STR_SZ,
5797 "SAS Device Status Change: Internal Query Task : id=%d", id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005798 break;
5799 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005800 snprintf(evStr, EVENT_DESCR_STR_SZ,
5801 "SAS Device Status Change: Unknown: id=%d", id);
5802 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005803 }
5804 break;
5805 }
5806 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5807 ds = "Bus Timer Expired";
5808 break;
5809 case MPI_EVENT_QUEUE_FULL:
5810 ds = "Queue Full";
5811 break;
5812 case MPI_EVENT_SAS_SES:
5813 ds = "SAS SES Event";
5814 break;
5815 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5816 ds = "Persistent Table Full";
5817 break;
5818 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005819 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005820 u8 LinkRates = (u8)(evData0 >> 8);
5821 u8 PhyNumber = (u8)(evData0);
5822 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5823 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5824 switch (LinkRates) {
5825 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06005826 snprintf(evStr, EVENT_DESCR_STR_SZ,
5827 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005828 " Rate Unknown",PhyNumber);
5829 break;
5830 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06005831 snprintf(evStr, EVENT_DESCR_STR_SZ,
5832 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005833 " Phy Disabled",PhyNumber);
5834 break;
5835 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06005836 snprintf(evStr, EVENT_DESCR_STR_SZ,
5837 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005838 " Failed Speed Nego",PhyNumber);
5839 break;
5840 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06005841 snprintf(evStr, EVENT_DESCR_STR_SZ,
5842 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005843 " Sata OOB Completed",PhyNumber);
5844 break;
5845 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06005846 snprintf(evStr, EVENT_DESCR_STR_SZ,
5847 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005848 " Rate 1.5 Gbps",PhyNumber);
5849 break;
5850 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06005851 snprintf(evStr, EVENT_DESCR_STR_SZ,
5852 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005853 " Rate 3.0 Gpbs",PhyNumber);
5854 break;
5855 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005856 snprintf(evStr, EVENT_DESCR_STR_SZ,
5857 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07005858 break;
5859 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005860 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005861 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005862 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5863 ds = "SAS Discovery Error";
5864 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005865 case MPI_EVENT_IR_RESYNC_UPDATE:
5866 {
5867 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06005868 snprintf(evStr, EVENT_DESCR_STR_SZ,
5869 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07005870 break;
5871 }
5872 case MPI_EVENT_IR2:
5873 {
5874 u8 ReasonCode = (u8)(evData0 >> 16);
5875 switch (ReasonCode) {
5876 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5877 ds = "IR2: LD State Changed";
5878 break;
5879 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5880 ds = "IR2: PD State Changed";
5881 break;
5882 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5883 ds = "IR2: Bad Block Table Full";
5884 break;
5885 case MPI_EVENT_IR2_RC_PD_INSERTED:
5886 ds = "IR2: PD Inserted";
5887 break;
5888 case MPI_EVENT_IR2_RC_PD_REMOVED:
5889 ds = "IR2: PD Removed";
5890 break;
5891 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5892 ds = "IR2: Foreign CFG Detected";
5893 break;
5894 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5895 ds = "IR2: Rebuild Medium Error";
5896 break;
5897 default:
5898 ds = "IR2";
5899 break;
5900 }
5901 break;
5902 }
5903 case MPI_EVENT_SAS_DISCOVERY:
5904 {
5905 if (evData0)
5906 ds = "SAS Discovery: Start";
5907 else
5908 ds = "SAS Discovery: Stop";
5909 break;
5910 }
5911 case MPI_EVENT_LOG_ENTRY_ADDED:
5912 ds = "SAS Log Entry Added";
5913 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005914
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 /*
5916 * MPT base "custom" events may be added here...
5917 */
5918 default:
5919 ds = "Unknown";
5920 break;
5921 }
Eric Moore509e5e52006-04-26 13:22:37 -06005922 if (ds)
5923 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924}
5925
5926/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5927/*
5928 * ProcessEventNotification - Route a received EventNotificationReply to
5929 * all currently regeistered event handlers.
5930 * @ioc: Pointer to MPT_ADAPTER structure
5931 * @pEventReply: Pointer to EventNotification reply frame
5932 * @evHandlers: Pointer to integer, number of event handlers
5933 *
5934 * Returns sum of event handlers return values.
5935 */
5936static int
5937ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5938{
5939 u16 evDataLen;
5940 u32 evData0 = 0;
5941// u32 evCtx;
5942 int ii;
5943 int r = 0;
5944 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06005945 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 u8 event;
5947
5948 /*
5949 * Do platform normalization of values
5950 */
5951 event = le32_to_cpu(pEventReply->Event) & 0xFF;
5952// evCtx = le32_to_cpu(pEventReply->EventContext);
5953 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
5954 if (evDataLen) {
5955 evData0 = le32_to_cpu(pEventReply->Data[0]);
5956 }
5957
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005958 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07005959 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07005961 event,
5962 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963
Moore, Eric3a892be2006-03-14 09:14:03 -07005964#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
5966 for (ii = 0; ii < evDataLen; ii++)
5967 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
5968 printk("\n");
5969#endif
5970
5971 /*
5972 * Do general / base driver event processing
5973 */
5974 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975 case MPI_EVENT_EVENT_CHANGE: /* 0A */
5976 if (evDataLen) {
5977 u8 evState = evData0 & 0xFF;
5978
5979 /* CHECKME! What if evState unexpectedly says OFF (0)? */
5980
5981 /* Update EventState field in cached IocFacts */
5982 if (ioc->facts.Function) {
5983 ioc->facts.EventState = evState;
5984 }
5985 }
5986 break;
Moore, Ericece50912006-01-16 18:53:19 -07005987 case MPI_EVENT_INTEGRATED_RAID:
5988 mptbase_raid_process_event_data(ioc,
5989 (MpiEventDataRaid_t *)pEventReply->Data);
5990 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005991 default:
5992 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993 }
5994
5995 /*
5996 * Should this event be logged? Events are written sequentially.
5997 * When buffer is full, start again at the top.
5998 */
5999 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6000 int idx;
6001
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006002 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003
6004 ioc->events[idx].event = event;
6005 ioc->events[idx].eventContext = ioc->eventContext;
6006
6007 for (ii = 0; ii < 2; ii++) {
6008 if (ii < evDataLen)
6009 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6010 else
6011 ioc->events[idx].data[ii] = 0;
6012 }
6013
6014 ioc->eventContext++;
6015 }
6016
6017
6018 /*
6019 * Call each currently registered protocol event handler.
6020 */
6021 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6022 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006023 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024 ioc->name, ii));
6025 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6026 handlers++;
6027 }
6028 }
6029 /* FIXME? Examine results here? */
6030
6031 /*
6032 * If needed, send (a single) EventAck.
6033 */
6034 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006035 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006036 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006038 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039 ioc->name, ii));
6040 }
6041 }
6042
6043 *evHandlers = handlers;
6044 return r;
6045}
6046
6047/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6048/*
6049 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6050 * @ioc: Pointer to MPT_ADAPTER structure
6051 * @log_info: U32 LogInfo reply word from the IOC
6052 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006053 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054 */
6055static void
6056mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6057{
6058 static char *subcl_str[8] = {
6059 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6060 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6061 };
6062 u8 subcl = (log_info >> 24) & 0x7;
6063
6064 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6065 ioc->name, log_info, subcl_str[subcl]);
6066}
6067
6068/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6069/*
Moore, Eric335a9412006-01-17 17:06:23 -07006070 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 * @ioc: Pointer to MPT_ADAPTER structure
6072 * @mr: Pointer to MPT reply frame
6073 * @log_info: U32 LogInfo word from the IOC
6074 *
6075 * Refer to lsi/sp_log.h.
6076 */
6077static void
Moore, Eric335a9412006-01-17 17:06:23 -07006078mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079{
6080 u32 info = log_info & 0x00FF0000;
6081 char *desc = "unknown";
6082
6083 switch (info) {
6084 case 0x00010000:
6085 desc = "bug! MID not found";
6086 if (ioc->reload_fw == 0)
6087 ioc->reload_fw++;
6088 break;
6089
6090 case 0x00020000:
6091 desc = "Parity Error";
6092 break;
6093
6094 case 0x00030000:
6095 desc = "ASYNC Outbound Overrun";
6096 break;
6097
6098 case 0x00040000:
6099 desc = "SYNC Offset Error";
6100 break;
6101
6102 case 0x00050000:
6103 desc = "BM Change";
6104 break;
6105
6106 case 0x00060000:
6107 desc = "Msg In Overflow";
6108 break;
6109
6110 case 0x00070000:
6111 desc = "DMA Error";
6112 break;
6113
6114 case 0x00080000:
6115 desc = "Outbound DMA Overrun";
6116 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006117
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 case 0x00090000:
6119 desc = "Task Management";
6120 break;
6121
6122 case 0x000A0000:
6123 desc = "Device Problem";
6124 break;
6125
6126 case 0x000B0000:
6127 desc = "Invalid Phase Change";
6128 break;
6129
6130 case 0x000C0000:
6131 desc = "Untagged Table Size";
6132 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006133
Linus Torvalds1da177e2005-04-16 15:20:36 -07006134 }
6135
6136 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6137}
6138
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006139/* strings for sas loginfo */
6140 static char *originator_str[] = {
6141 "IOP", /* 00h */
6142 "PL", /* 01h */
6143 "IR" /* 02h */
6144 };
6145 static char *iop_code_str[] = {
6146 NULL, /* 00h */
6147 "Invalid SAS Address", /* 01h */
6148 NULL, /* 02h */
6149 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006150 "Diag Message Error", /* 04h */
6151 "Task Terminated", /* 05h */
6152 "Enclosure Management", /* 06h */
6153 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006154 };
6155 static char *pl_code_str[] = {
6156 NULL, /* 00h */
6157 "Open Failure", /* 01h */
6158 "Invalid Scatter Gather List", /* 02h */
6159 "Wrong Relative Offset or Frame Length", /* 03h */
6160 "Frame Transfer Error", /* 04h */
6161 "Transmit Frame Connected Low", /* 05h */
6162 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6163 "SATA Read Log Receive Data Error", /* 07h */
6164 "SATA NCQ Fail All Commands After Error", /* 08h */
6165 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6166 "Receive Frame Invalid Message", /* 0Ah */
6167 "Receive Context Message Valid Error", /* 0Bh */
6168 "Receive Frame Current Frame Error", /* 0Ch */
6169 "SATA Link Down", /* 0Dh */
6170 "Discovery SATA Init W IOS", /* 0Eh */
6171 "Config Invalid Page", /* 0Fh */
6172 "Discovery SATA Init Timeout", /* 10h */
6173 "Reset", /* 11h */
6174 "Abort", /* 12h */
6175 "IO Not Yet Executed", /* 13h */
6176 "IO Executed", /* 14h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006177 "Persistant Reservation Out Not Affiliation Owner", /* 15h */
6178 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006179 "IO Device Missing Delay Retry", /* 17h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006180 NULL, /* 18h */
6181 NULL, /* 19h */
6182 NULL, /* 1Ah */
6183 NULL, /* 1Bh */
6184 NULL, /* 1Ch */
6185 NULL, /* 1Dh */
6186 NULL, /* 1Eh */
6187 NULL, /* 1Fh */
6188 "Enclosure Management" /* 20h */
6189 };
6190
6191/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6192/*
6193 * mpt_sas_log_info - Log information returned from SAS IOC.
6194 * @ioc: Pointer to MPT_ADAPTER structure
6195 * @log_info: U32 LogInfo reply word from the IOC
6196 *
6197 * Refer to lsi/mpi_log_sas.h.
6198 */
6199static void
6200mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6201{
6202union loginfo_type {
6203 u32 loginfo;
6204 struct {
6205 u32 subcode:16;
6206 u32 code:8;
6207 u32 originator:4;
6208 u32 bus_type:4;
6209 }dw;
6210};
6211 union loginfo_type sas_loginfo;
6212 char *code_desc = NULL;
6213
6214 sas_loginfo.loginfo = log_info;
6215 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6216 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6217 return;
6218 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6219 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6220 code_desc = iop_code_str[sas_loginfo.dw.code];
6221 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6222 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6223 code_desc = pl_code_str[sas_loginfo.dw.code];
6224 }
6225
6226 if (code_desc != NULL)
6227 printk(MYIOC_s_INFO_FMT
6228 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6229 " SubCode(0x%04x)\n",
6230 ioc->name,
6231 log_info,
6232 originator_str[sas_loginfo.dw.originator],
6233 code_desc,
6234 sas_loginfo.dw.subcode);
6235 else
6236 printk(MYIOC_s_INFO_FMT
6237 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6238 " SubCode(0x%04x)\n",
6239 ioc->name,
6240 log_info,
6241 originator_str[sas_loginfo.dw.originator],
6242 sas_loginfo.dw.code,
6243 sas_loginfo.dw.subcode);
6244}
6245
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6247/*
6248 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6249 * @ioc: Pointer to MPT_ADAPTER structure
6250 * @ioc_status: U32 IOCStatus word from IOC
6251 * @mf: Pointer to MPT request frame
6252 *
6253 * Refer to lsi/mpi.h.
6254 */
6255static void
6256mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6257{
6258 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06006259 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260
6261 switch (status) {
6262 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6263 desc = "Invalid Function";
6264 break;
6265
6266 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6267 desc = "Busy";
6268 break;
6269
6270 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6271 desc = "Invalid SGL";
6272 break;
6273
6274 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6275 desc = "Internal Error";
6276 break;
6277
6278 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6279 desc = "Reserved";
6280 break;
6281
6282 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6283 desc = "Insufficient Resources";
6284 break;
6285
6286 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6287 desc = "Invalid Field";
6288 break;
6289
6290 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6291 desc = "Invalid State";
6292 break;
6293
6294 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6295 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6296 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6297 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6298 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6299 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6300 /* No message for Config IOCStatus values */
6301 break;
6302
6303 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6304 /* No message for recovered error
6305 desc = "SCSI Recovered Error";
6306 */
6307 break;
6308
6309 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6310 desc = "SCSI Invalid Bus";
6311 break;
6312
6313 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6314 desc = "SCSI Invalid TargetID";
6315 break;
6316
6317 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6318 {
6319 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6320 U8 cdb = pScsiReq->CDB[0];
6321 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6322 desc = "SCSI Device Not There";
6323 }
6324 break;
6325 }
6326
6327 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6328 desc = "SCSI Data Overrun";
6329 break;
6330
6331 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006332 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333 desc = "SCSI Data Underrun";
6334 */
6335 break;
6336
6337 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6338 desc = "SCSI I/O Data Error";
6339 break;
6340
6341 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6342 desc = "SCSI Protocol Error";
6343 break;
6344
6345 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6346 desc = "SCSI Task Terminated";
6347 break;
6348
6349 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6350 desc = "SCSI Residual Mismatch";
6351 break;
6352
6353 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6354 desc = "SCSI Task Management Failed";
6355 break;
6356
6357 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6358 desc = "SCSI IOC Terminated";
6359 break;
6360
6361 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6362 desc = "SCSI Ext Terminated";
6363 break;
6364
6365 default:
6366 desc = "Others";
6367 break;
6368 }
Eric Moore4f766dc2006-07-11 17:24:07 -06006369 if (desc != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6371}
6372
6373/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006374EXPORT_SYMBOL(mpt_attach);
6375EXPORT_SYMBOL(mpt_detach);
6376#ifdef CONFIG_PM
6377EXPORT_SYMBOL(mpt_resume);
6378EXPORT_SYMBOL(mpt_suspend);
6379#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006381EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382EXPORT_SYMBOL(mpt_register);
6383EXPORT_SYMBOL(mpt_deregister);
6384EXPORT_SYMBOL(mpt_event_register);
6385EXPORT_SYMBOL(mpt_event_deregister);
6386EXPORT_SYMBOL(mpt_reset_register);
6387EXPORT_SYMBOL(mpt_reset_deregister);
6388EXPORT_SYMBOL(mpt_device_driver_register);
6389EXPORT_SYMBOL(mpt_device_driver_deregister);
6390EXPORT_SYMBOL(mpt_get_msg_frame);
6391EXPORT_SYMBOL(mpt_put_msg_frame);
6392EXPORT_SYMBOL(mpt_free_msg_frame);
6393EXPORT_SYMBOL(mpt_add_sge);
6394EXPORT_SYMBOL(mpt_send_handshake_request);
6395EXPORT_SYMBOL(mpt_verify_adapter);
6396EXPORT_SYMBOL(mpt_GetIocState);
6397EXPORT_SYMBOL(mpt_print_ioc_summary);
6398EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006399EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400EXPORT_SYMBOL(mpt_HardResetHandler);
6401EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403EXPORT_SYMBOL(mpt_alloc_fw_memory);
6404EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006405EXPORT_SYMBOL(mptbase_sas_persist_operation);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407
6408/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6409/*
6410 * fusion_init - Fusion MPT base driver initialization routine.
6411 *
6412 * Returns 0 for success, non-zero for failure.
6413 */
6414static int __init
6415fusion_init(void)
6416{
6417 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006418
6419 show_mptmod_ver(my_NAME, my_VERSION);
6420 printk(KERN_INFO COPYRIGHT "\n");
6421
6422 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6423 MptCallbacks[i] = NULL;
6424 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6425 MptEvHandlers[i] = NULL;
6426 MptResetHandlers[i] = NULL;
6427 }
6428
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006429 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006430 * EventNotification handling.
6431 */
6432 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6433
6434 /* Register for hard reset handling callbacks.
6435 */
6436 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6437 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6438 } else {
6439 /* FIXME! */
6440 }
6441
6442#ifdef CONFIG_PROC_FS
6443 (void) procmpt_create();
6444#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006445 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446}
6447
6448/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6449/*
6450 * fusion_exit - Perform driver unload cleanup.
6451 *
6452 * This routine frees all resources associated with each MPT adapter
6453 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6454 */
6455static void __exit
6456fusion_exit(void)
6457{
6458
6459 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6460
Linus Torvalds1da177e2005-04-16 15:20:36 -07006461 mpt_reset_deregister(mpt_base_index);
6462
6463#ifdef CONFIG_PROC_FS
6464 procmpt_destroy();
6465#endif
6466}
6467
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468module_init(fusion_init);
6469module_exit(fusion_exit);