blob: 8ac77caf9337e611e1dfd0f9474e2a812e0513f3 [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
49#include <linux/config.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/kernel.h>
51#include <linux/module.h>
52#include <linux/errno.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/types.h>
56#include <linux/pci.h>
57#include <linux/kdev_t.h>
58#include <linux/blkdev.h>
59#include <linux/delay.h>
60#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040061#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/io.h>
63#ifdef CONFIG_MTRR
64#include <asm/mtrr.h>
65#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
68
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
77
78/*
79 * cmd line parameters
80 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000081static int mpt_msi_enable;
82module_param(mpt_msi_enable, int, 0);
83MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#ifdef MFCNT
86static int mfcounter = 0;
87#define PRINT_MF_COUNT 20000
88#endif
89
90/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
91/*
92 * Public data...
93 */
94int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080095int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Linus Torvaldsf7473072005-11-29 14:21:57 -080097struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99#define WHOINIT_UNKNOWN 0xAA
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Private data...
104 */
105 /* Adapter link list */
106LIST_HEAD(ioc_list);
107 /* Callback lookup table */
108static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
109 /* Protocol driver class lookup table */
110static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
111 /* Event handler lookup table */
112static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
113 /* Reset handler lookup table */
114static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
115static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
116
117static int mpt_base_index = -1;
118static int last_drv_idx = -1;
119
120static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
121
122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
123/*
124 * Forward protos...
125 */
126static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
127static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
128static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
129 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
130 int sleepFlag);
131static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
132static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
133static void mpt_adapter_disable(MPT_ADAPTER *ioc);
134static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
135
136static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
137static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
139static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
140static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
141static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
142static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200143static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
145static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
146static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
147static int PrimeIocFifos(MPT_ADAPTER *ioc);
148static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
149static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
150static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
151static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200153int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
155static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
156static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
157static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
158static void mpt_timer_expired(unsigned long data);
159static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
160static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200161static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
162static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164#ifdef CONFIG_PROC_FS
165static int procmpt_summary_read(char *buf, char **start, off_t offset,
166 int request, int *eof, void *data);
167static int procmpt_version_read(char *buf, char **start, off_t offset,
168 int request, int *eof, void *data);
169static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
170 int request, int *eof, void *data);
171#endif
172static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
173
174//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
175static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
176static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
177static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700178static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600179static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700180static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183static int __init fusion_init (void);
184static void __exit fusion_exit (void);
185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186#define CHIPREG_READ32(addr) readl_relaxed(addr)
187#define CHIPREG_READ32_dmasync(addr) readl(addr)
188#define CHIPREG_WRITE32(addr,val) writel(val, addr)
189#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
190#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
191
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600192static void
193pci_disable_io_access(struct pci_dev *pdev)
194{
195 u16 command_reg;
196
197 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
198 command_reg &= ~1;
199 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
200}
201
202static void
203pci_enable_io_access(struct pci_dev *pdev)
204{
205 u16 command_reg;
206
207 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
208 command_reg |= 1;
209 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
210}
211
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600212/*
213 * Process turbo (context) reply...
214 */
215static void
216mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
217{
218 MPT_FRAME_HDR *mf = NULL;
219 MPT_FRAME_HDR *mr = NULL;
220 int req_idx = 0;
221 int cb_idx;
222
223 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
224 ioc->name, pa));
225
226 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
227 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
228 req_idx = pa & 0x0000FFFF;
229 cb_idx = (pa & 0x00FF0000) >> 16;
230 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
231 break;
232 case MPI_CONTEXT_REPLY_TYPE_LAN:
233 cb_idx = mpt_lan_index;
234 /*
235 * Blind set of mf to NULL here was fatal
236 * after lan_reply says "freeme"
237 * Fix sort of combined with an optimization here;
238 * added explicit check for case where lan_reply
239 * was just returning 1 and doing nothing else.
240 * For this case skip the callback, but set up
241 * proper mf value first here:-)
242 */
243 if ((pa & 0x58000000) == 0x58000000) {
244 req_idx = pa & 0x0000FFFF;
245 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
246 mpt_free_msg_frame(ioc, mf);
247 mb();
248 return;
249 break;
250 }
251 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
252 break;
253 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
254 cb_idx = mpt_stm_index;
255 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
256 break;
257 default:
258 cb_idx = 0;
259 BUG();
260 }
261
262 /* Check for (valid) IO callback! */
263 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
264 MptCallbacks[cb_idx] == NULL) {
265 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
266 __FUNCTION__, ioc->name, cb_idx);
267 goto out;
268 }
269
270 if (MptCallbacks[cb_idx](ioc, mf, mr))
271 mpt_free_msg_frame(ioc, mf);
272 out:
273 mb();
274}
275
276static void
277mpt_reply(MPT_ADAPTER *ioc, u32 pa)
278{
279 MPT_FRAME_HDR *mf;
280 MPT_FRAME_HDR *mr;
281 int req_idx;
282 int cb_idx;
283 int freeme;
284
285 u32 reply_dma_low;
286 u16 ioc_stat;
287
288 /* non-TURBO reply! Hmmm, something may be up...
289 * Newest turbo reply mechanism; get address
290 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
291 */
292
293 /* Map DMA address of reply header to cpu address.
294 * pa is 32 bits - but the dma address may be 32 or 64 bits
295 * get offset based only only the low addresses
296 */
297
298 reply_dma_low = (pa <<= 1);
299 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
300 (reply_dma_low - ioc->reply_frames_low_dma));
301
302 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
303 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
304 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
305
306 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
307 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
308 DBG_DUMP_REPLY_FRAME(mr)
309
310 /* Check/log IOC log info
311 */
312 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
313 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
314 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
315 if (ioc->bus_type == FC)
316 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700317 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700318 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600319 else if (ioc->bus_type == SAS)
320 mpt_sas_log_info(ioc, log_info);
321 }
322 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700323 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600324 cb_idx != mpt_stm_index &&
325 cb_idx != mpt_lan_index)
326 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
327 }
328
329
330 /* Check for (valid) IO callback! */
331 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
332 MptCallbacks[cb_idx] == NULL) {
333 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
334 __FUNCTION__, ioc->name, cb_idx);
335 freeme = 0;
336 goto out;
337 }
338
339 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
340
341 out:
342 /* Flush (non-TURBO) reply with a WRITE! */
343 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
344
345 if (freeme)
346 mpt_free_msg_frame(ioc, mf);
347 mb();
348}
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
351/*
352 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
353 * @irq: irq number (not used)
354 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
355 * @r: pt_regs pointer (not used)
356 *
357 * This routine is registered via the request_irq() kernel API call,
358 * and handles all interrupts generated from a specific MPT adapter
359 * (also referred to as a IO Controller or IOC).
360 * This routine must clear the interrupt from the adapter and does
361 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200362 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 *
364 * This routine handles register-level access of the adapter but
365 * dispatches (calls) a protocol-specific callback routine to handle
366 * the protocol-specific details of the MPT request completion.
367 */
368static irqreturn_t
369mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
370{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600371 MPT_ADAPTER *ioc = bus_id;
372 u32 pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374 /*
375 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 */
377 while (1) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600378 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
379 if (pa == 0xFFFFFFFF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 return IRQ_HANDLED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600381 else if (pa & MPI_ADDRESS_REPLY_A_BIT)
382 mpt_reply(ioc, pa);
383 else
384 mpt_turbo_reply(ioc, pa);
385 }
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;
Moore, Eric3a892be2006-03-14 09:14:03 -0700439 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200440 ioc->name, pEvReply));
441 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700442 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200443 ioc->name, pEvReply));
444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446#ifdef CONFIG_PROC_FS
447// LogEvent(ioc, pEvReply);
448#endif
449
450 } else if (func == MPI_FUNCTION_EVENT_ACK) {
451 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
452 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700453 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 CONFIGPARMS *pCfg;
455 unsigned long flags;
456
457 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
458 ioc->name, mf, reply));
459
460 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
461
462 if (pCfg) {
463 /* disable timer and remove from linked list */
464 del_timer(&pCfg->timer);
465
466 spin_lock_irqsave(&ioc->FreeQlock, flags);
467 list_del(&pCfg->linkage);
468 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
469
470 /*
471 * If IOC Status is SUCCESS, save the header
472 * and set the status code to GOOD.
473 */
474 pCfg->status = MPT_CONFIG_ERROR;
475 if (reply) {
476 ConfigReply_t *pReply = (ConfigReply_t *)reply;
477 u16 status;
478
479 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
480 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
481 status, le32_to_cpu(pReply->IOCLogInfo)));
482
483 pCfg->status = status;
484 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200485 if ((pReply->Header.PageType &
486 MPI_CONFIG_PAGETYPE_MASK) ==
487 MPI_CONFIG_PAGETYPE_EXTENDED) {
488 pCfg->cfghdr.ehdr->ExtPageLength =
489 le16_to_cpu(pReply->ExtPageLength);
490 pCfg->cfghdr.ehdr->ExtPageType =
491 pReply->ExtPageType;
492 }
493 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
494
495 /* If this is a regular header, save PageLength. */
496 /* LMP Do this better so not using a reserved field! */
497 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
498 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
499 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501 }
502
503 /*
504 * Wake up the original calling thread
505 */
506 pCfg->wait_done = 1;
507 wake_up(&mpt_waitq);
508 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200509 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
510 /* we should be always getting a reply frame */
511 memcpy(ioc->persist_reply_frame, reply,
512 min(MPT_DEFAULT_FRAME_SIZE,
513 4*reply->u.reply.MsgLength));
514 del_timer(&ioc->persist_timer);
515 ioc->persist_wait_done = 1;
516 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 } else {
518 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
519 ioc->name, func);
520 }
521
522 /*
523 * Conditionally tell caller to free the original
524 * EventNotification/EventAck/unexpected request frame!
525 */
526 return freereq;
527}
528
529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
530/**
531 * mpt_register - Register protocol-specific main callback handler.
532 * @cbfunc: callback function pointer
533 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
534 *
535 * This routine is called by a protocol-specific driver (SCSI host,
536 * LAN, SCSI target) to register it's reply callback routine. Each
537 * protocol-specific driver must do this before it will be able to
538 * use any IOC resources, such as obtaining request frames.
539 *
540 * NOTES: The SCSI protocol driver currently calls this routine thrice
541 * in order to register separate callbacks; one for "normal" SCSI IO;
542 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
543 *
544 * Returns a positive integer valued "handle" in the
545 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
546 * Any non-positive return value (including zero!) should be considered
547 * an error by the caller.
548 */
549int
550mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
551{
552 int i;
553
554 last_drv_idx = -1;
555
556 /*
557 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
558 * (slot/handle 0 is reserved!)
559 */
560 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
561 if (MptCallbacks[i] == NULL) {
562 MptCallbacks[i] = cbfunc;
563 MptDriverClass[i] = dclass;
564 MptEvHandlers[i] = NULL;
565 last_drv_idx = i;
566 break;
567 }
568 }
569
570 return last_drv_idx;
571}
572
573/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
574/**
575 * mpt_deregister - Deregister a protocol drivers resources.
576 * @cb_idx: previously registered callback handle
577 *
578 * Each protocol-specific driver should call this routine when it's
579 * module is unloaded.
580 */
581void
582mpt_deregister(int cb_idx)
583{
584 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
585 MptCallbacks[cb_idx] = NULL;
586 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
587 MptEvHandlers[cb_idx] = NULL;
588
589 last_drv_idx++;
590 }
591}
592
593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
594/**
595 * mpt_event_register - Register protocol-specific event callback
596 * handler.
597 * @cb_idx: previously registered (via mpt_register) callback handle
598 * @ev_cbfunc: callback function
599 *
600 * This routine can be called by one or more protocol-specific drivers
601 * if/when they choose to be notified of MPT events.
602 *
603 * Returns 0 for success.
604 */
605int
606mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
607{
608 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
609 return -1;
610
611 MptEvHandlers[cb_idx] = ev_cbfunc;
612 return 0;
613}
614
615/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
616/**
617 * mpt_event_deregister - Deregister protocol-specific event callback
618 * handler.
619 * @cb_idx: previously registered callback handle
620 *
621 * Each protocol-specific driver should call this routine
622 * when it does not (or can no longer) handle events,
623 * or when it's module is unloaded.
624 */
625void
626mpt_event_deregister(int cb_idx)
627{
628 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
629 return;
630
631 MptEvHandlers[cb_idx] = NULL;
632}
633
634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
635/**
636 * mpt_reset_register - Register protocol-specific IOC reset handler.
637 * @cb_idx: previously registered (via mpt_register) callback handle
638 * @reset_func: reset function
639 *
640 * This routine can be called by one or more protocol-specific drivers
641 * if/when they choose to be notified of IOC resets.
642 *
643 * Returns 0 for success.
644 */
645int
646mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
647{
648 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
649 return -1;
650
651 MptResetHandlers[cb_idx] = reset_func;
652 return 0;
653}
654
655/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
656/**
657 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
658 * @cb_idx: previously registered callback handle
659 *
660 * Each protocol-specific driver should call this routine
661 * when it does not (or can no longer) handle IOC reset handling,
662 * or when it's module is unloaded.
663 */
664void
665mpt_reset_deregister(int cb_idx)
666{
667 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
668 return;
669
670 MptResetHandlers[cb_idx] = NULL;
671}
672
673/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
674/**
675 * mpt_device_driver_register - Register device driver hooks
676 */
677int
678mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
679{
680 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400683 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
685
686 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
687
688 /* call per pci device probe entry point */
689 list_for_each_entry(ioc, &ioc_list, list) {
690 if(dd_cbfunc->probe) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400691 dd_cbfunc->probe(ioc->pcidev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 ioc->pcidev->driver->id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
694 }
695
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400696 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697}
698
699/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
700/**
701 * mpt_device_driver_deregister - DeRegister device driver hooks
702 */
703void
704mpt_device_driver_deregister(int cb_idx)
705{
706 struct mpt_pci_driver *dd_cbfunc;
707 MPT_ADAPTER *ioc;
708
709 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
710 return;
711
712 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
713
714 list_for_each_entry(ioc, &ioc_list, list) {
715 if (dd_cbfunc->remove)
716 dd_cbfunc->remove(ioc->pcidev);
717 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 MptDeviceDriverHandlers[cb_idx] = NULL;
720}
721
722
723/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
724/**
725 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
726 * allocated per MPT adapter.
727 * @handle: Handle of registered MPT protocol driver
728 * @ioc: Pointer to MPT adapter structure
729 *
730 * Returns pointer to a MPT request frame or %NULL if none are available
731 * or IOC is not active.
732 */
733MPT_FRAME_HDR*
734mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
735{
736 MPT_FRAME_HDR *mf;
737 unsigned long flags;
738 u16 req_idx; /* Request index */
739
740 /* validate handle and ioc identifier */
741
742#ifdef MFCNT
743 if (!ioc->active)
744 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
745#endif
746
747 /* If interrupts are not attached, do not return a request frame */
748 if (!ioc->active)
749 return NULL;
750
751 spin_lock_irqsave(&ioc->FreeQlock, flags);
752 if (!list_empty(&ioc->FreeQ)) {
753 int req_offset;
754
755 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
756 u.frame.linkage.list);
757 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200758 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
760 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
761 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500762 req_idx = req_offset / ioc->req_sz;
763 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
765 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
766#ifdef MFCNT
767 ioc->mfcnt++;
768#endif
769 }
770 else
771 mf = NULL;
772 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
773
774#ifdef MFCNT
775 if (mf == NULL)
776 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
777 mfcounter++;
778 if (mfcounter == PRINT_MF_COUNT)
779 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
780#endif
781
782 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
783 ioc->name, handle, ioc->id, mf));
784 return mf;
785}
786
787/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
788/**
789 * mpt_put_msg_frame - Send a protocol specific MPT request frame
790 * to a IOC.
791 * @handle: Handle of registered MPT protocol driver
792 * @ioc: Pointer to MPT adapter structure
793 * @mf: Pointer to MPT request frame
794 *
795 * This routine posts a MPT request frame to the request post FIFO of a
796 * specific MPT adapter.
797 */
798void
799mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
800{
801 u32 mf_dma_addr;
802 int req_offset;
803 u16 req_idx; /* Request index */
804
805 /* ensure values are reset properly! */
806 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
807 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
808 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500809 req_idx = req_offset / ioc->req_sz;
810 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
812
813#ifdef MPT_DEBUG_MSG_FRAME
814 {
815 u32 *m = mf->u.frame.hwhdr.__hdr;
816 int ii, n;
817
818 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
819 ioc->name, m);
820 n = ioc->req_sz/4 - 1;
821 while (m[n] == 0)
822 n--;
823 for (ii=0; ii<=n; ii++) {
824 if (ii && ((ii%8)==0))
825 printk("\n" KERN_INFO " ");
826 printk(" %08x", le32_to_cpu(m[ii]));
827 }
828 printk("\n");
829 }
830#endif
831
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200832 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 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]));
834 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
835}
836
837/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
838/**
839 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
840 * @handle: Handle of registered MPT protocol driver
841 * @ioc: Pointer to MPT adapter structure
842 * @mf: Pointer to MPT request frame
843 *
844 * This routine places a MPT request frame back on the MPT adapter's
845 * FreeQ.
846 */
847void
848mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
849{
850 unsigned long flags;
851
852 /* Put Request back on FreeQ! */
853 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200854 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
856#ifdef MFCNT
857 ioc->mfcnt--;
858#endif
859 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
860}
861
862/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
863/**
864 * mpt_add_sge - Place a simple SGE at address pAddr.
865 * @pAddr: virtual address for SGE
866 * @flagslength: SGE flags and data transfer length
867 * @dma_addr: Physical address
868 *
869 * This routine places a MPT request frame back on the MPT adapter's
870 * FreeQ.
871 */
872void
873mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
874{
875 if (sizeof(dma_addr_t) == sizeof(u64)) {
876 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
877 u32 tmp = dma_addr & 0xFFFFFFFF;
878
879 pSge->FlagsLength = cpu_to_le32(flagslength);
880 pSge->Address.Low = cpu_to_le32(tmp);
881 tmp = (u32) ((u64)dma_addr >> 32);
882 pSge->Address.High = cpu_to_le32(tmp);
883
884 } else {
885 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
886 pSge->FlagsLength = cpu_to_le32(flagslength);
887 pSge->Address = cpu_to_le32(dma_addr);
888 }
889}
890
891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
892/**
893 * mpt_send_handshake_request - Send MPT request via doorbell
894 * handshake method.
895 * @handle: Handle of registered MPT protocol driver
896 * @ioc: Pointer to MPT adapter structure
897 * @reqBytes: Size of the request in bytes
898 * @req: Pointer to MPT request frame
899 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
900 *
901 * This routine is used exclusively to send MptScsiTaskMgmt
902 * requests since they are required to be sent via doorbell handshake.
903 *
904 * NOTE: It is the callers responsibility to byte-swap fields in the
905 * request which are greater than 1 byte in size.
906 *
907 * Returns 0 for success, non-zero for failure.
908 */
909int
910mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
911{
912 int r = 0;
913 u8 *req_as_bytes;
914 int ii;
915
916 /* State is known to be good upon entering
917 * this function so issue the bus reset
918 * request.
919 */
920
921 /*
922 * Emulate what mpt_put_msg_frame() does /wrt to sanity
923 * setting cb_idx/req_idx. But ONLY if this request
924 * is in proper (pre-alloc'd) request buffer range...
925 */
926 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
927 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
928 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
929 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
930 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
931 }
932
933 /* Make sure there are no doorbells */
934 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 CHIPREG_WRITE32(&ioc->chip->Doorbell,
937 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
938 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
939
940 /* Wait for IOC doorbell int */
941 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
942 return ii;
943 }
944
945 /* Read doorbell and check for active bit */
946 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
947 return -5;
948
949 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200950 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
953
954 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
955 return -2;
956 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 /* Send request via doorbell handshake */
959 req_as_bytes = (u8 *) req;
960 for (ii = 0; ii < reqBytes/4; ii++) {
961 u32 word;
962
963 word = ((req_as_bytes[(ii*4) + 0] << 0) |
964 (req_as_bytes[(ii*4) + 1] << 8) |
965 (req_as_bytes[(ii*4) + 2] << 16) |
966 (req_as_bytes[(ii*4) + 3] << 24));
967 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
968 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
969 r = -3;
970 break;
971 }
972 }
973
974 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
975 r = 0;
976 else
977 r = -4;
978
979 /* Make sure there are no doorbells */
980 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 return r;
983}
984
985/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
986/**
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200987 * mpt_host_page_access_control - provides mechanism for the host
988 * driver to control the IOC's Host Page Buffer access.
989 * @ioc: Pointer to MPT adapter structure
990 * @access_control_value: define bits below
991 *
992 * Access Control Value - bits[15:12]
993 * 0h Reserved
994 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
995 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
996 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
997 *
998 * Returns 0 for success, non-zero for failure.
999 */
1000
1001static int
1002mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1003{
1004 int r = 0;
1005
1006 /* return if in use */
1007 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1008 & MPI_DOORBELL_ACTIVE)
1009 return -1;
1010
1011 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1012
1013 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1014 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1015 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1016 (access_control_value<<12)));
1017
1018 /* Wait for IOC to clear Doorbell Status bit */
1019 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1020 return -2;
1021 }else
1022 return 0;
1023}
1024
1025/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1026/**
1027 * mpt_host_page_alloc - allocate system memory for the fw
1028 * If we already allocated memory in past, then resend the same pointer.
1029 * ioc@: Pointer to pointer to IOC adapter
1030 * ioc_init@: Pointer to ioc init config page
1031 *
1032 * Returns 0 for success, non-zero for failure.
1033 */
1034static int
1035mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1036{
1037 char *psge;
1038 int flags_length;
1039 u32 host_page_buffer_sz=0;
1040
1041 if(!ioc->HostPageBuffer) {
1042
1043 host_page_buffer_sz =
1044 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1045
1046 if(!host_page_buffer_sz)
1047 return 0; /* fw doesn't need any host buffers */
1048
1049 /* spin till we get enough memory */
1050 while(host_page_buffer_sz > 0) {
1051
1052 if((ioc->HostPageBuffer = pci_alloc_consistent(
1053 ioc->pcidev,
1054 host_page_buffer_sz,
1055 &ioc->HostPageBuffer_dma)) != NULL) {
1056
1057 dinitprintk((MYIOC_s_INFO_FMT
1058 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
1059 ioc->name,
1060 ioc->HostPageBuffer,
1061 ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001062 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001063 ioc->alloc_total += host_page_buffer_sz;
1064 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1065 break;
1066 }
1067
1068 host_page_buffer_sz -= (4*1024);
1069 }
1070 }
1071
1072 if(!ioc->HostPageBuffer) {
1073 printk(MYIOC_s_ERR_FMT
1074 "Failed to alloc memory for host_page_buffer!\n",
1075 ioc->name);
1076 return -999;
1077 }
1078
1079 psge = (char *)&ioc_init->HostPageBufferSGE;
1080 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1081 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1082 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1083 MPI_SGE_FLAGS_HOST_TO_IOC |
1084 MPI_SGE_FLAGS_END_OF_BUFFER;
1085 if (sizeof(dma_addr_t) == sizeof(u64)) {
1086 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1087 }
1088 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1089 flags_length |= ioc->HostPageBuffer_sz;
1090 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1091 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1092
1093return 0;
1094}
1095
1096/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1097/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
1099 * the associated MPT adapter structure.
1100 * @iocid: IOC unique identifier (integer)
1101 * @iocpp: Pointer to pointer to IOC adapter
1102 *
1103 * Returns iocid and sets iocpp.
1104 */
1105int
1106mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1107{
1108 MPT_ADAPTER *ioc;
1109
1110 list_for_each_entry(ioc,&ioc_list,list) {
1111 if (ioc->id == iocid) {
1112 *iocpp =ioc;
1113 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 *iocpp = NULL;
1118 return -1;
1119}
1120
1121/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1122/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001123 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 * @pdev: Pointer to pci_dev structure
1125 *
1126 * This routine performs all the steps necessary to bring the IOC of
1127 * a MPT adapter to a OPERATIONAL state. This includes registering
1128 * memory regions, registering the interrupt, and allocating request
1129 * and reply memory pools.
1130 *
1131 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1132 * MPT adapter.
1133 *
1134 * Returns 0 for success, non-zero for failure.
1135 *
1136 * TODO: Add support for polled controllers
1137 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001138int
1139mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140{
1141 MPT_ADAPTER *ioc;
1142 u8 __iomem *mem;
1143 unsigned long mem_phys;
1144 unsigned long port;
1145 u32 msize;
1146 u32 psize;
1147 int ii;
1148 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 u8 revision;
1150 u8 pcixcmd;
1151 static int mpt_ids = 0;
1152#ifdef CONFIG_PROC_FS
1153 struct proc_dir_entry *dent, *ent;
1154#endif
1155
1156 if (pci_enable_device(pdev))
1157 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001160
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001161 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 dprintk((KERN_INFO MYNAM
1163 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001164 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1166 return r;
1167 }
1168
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001169 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 dprintk((KERN_INFO MYNAM
1171 ": Using 64 bit consistent mask\n"));
1172 else
1173 dprintk((KERN_INFO MYNAM
1174 ": Not using 64 bit consistent mask\n"));
1175
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001176 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 if (ioc == NULL) {
1178 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1179 return -ENOMEM;
1180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 ioc->alloc_total = sizeof(MPT_ADAPTER);
1182 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1183 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 ioc->pcidev = pdev;
1186 ioc->diagPending = 0;
1187 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001188 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 /* Initialize the event logging.
1191 */
1192 ioc->eventTypes = 0; /* None */
1193 ioc->eventContext = 0;
1194 ioc->eventLogSize = 0;
1195 ioc->events = NULL;
1196
1197#ifdef MFCNT
1198 ioc->mfcnt = 0;
1199#endif
1200
1201 ioc->cached_fw = NULL;
1202
1203 /* Initilize SCSI Config Data structure
1204 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001205 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
1207 /* Initialize the running configQ head.
1208 */
1209 INIT_LIST_HEAD(&ioc->configQ);
1210
Michael Reed05e8ec12006-01-13 14:31:54 -06001211 /* Initialize the fc rport list head.
1212 */
1213 INIT_LIST_HEAD(&ioc->fc_rports);
1214
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 /* Find lookup slot. */
1216 INIT_LIST_HEAD(&ioc->list);
1217 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 mem_phys = msize = 0;
1220 port = psize = 0;
1221 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1222 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001223 if (psize)
1224 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 /* Get I/O space! */
1226 port = pci_resource_start(pdev, ii);
1227 psize = pci_resource_len(pdev,ii);
1228 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001229 if (msize)
1230 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 /* Get memmap */
1232 mem_phys = pci_resource_start(pdev, ii);
1233 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
1235 }
1236 ioc->mem_size = msize;
1237
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 mem = NULL;
1239 /* Get logical ptr for PciMem0 space */
1240 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001241 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 if (mem == NULL) {
1243 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1244 kfree(ioc);
1245 return -EINVAL;
1246 }
1247 ioc->memmap = mem;
1248 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1249
1250 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1251 &ioc->facts, &ioc->pfacts[0]));
1252
1253 ioc->mem_phys = mem_phys;
1254 ioc->chip = (SYSIF_REGS __iomem *)mem;
1255
1256 /* Save Port IO values in case we need to do downloadboot */
1257 {
1258 u8 *pmem = (u8*)port;
1259 ioc->pio_mem_phys = port;
1260 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1261 }
1262
1263 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1264 ioc->prod_name = "LSIFC909";
1265 ioc->bus_type = FC;
1266 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001267 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 ioc->prod_name = "LSIFC929";
1269 ioc->bus_type = FC;
1270 }
1271 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1272 ioc->prod_name = "LSIFC919";
1273 ioc->bus_type = FC;
1274 }
1275 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1276 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1277 ioc->bus_type = FC;
1278 if (revision < XL_929) {
1279 ioc->prod_name = "LSIFC929X";
1280 /* 929X Chip Fix. Set Split transactions level
1281 * for PCIX. Set MOST bits to zero.
1282 */
1283 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1284 pcixcmd &= 0x8F;
1285 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1286 } else {
1287 ioc->prod_name = "LSIFC929XL";
1288 /* 929XL Chip Fix. Set MMRBC to 0x08.
1289 */
1290 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1291 pcixcmd |= 0x08;
1292 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1293 }
1294 }
1295 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1296 ioc->prod_name = "LSIFC919X";
1297 ioc->bus_type = FC;
1298 /* 919X Chip Fix. Set Split transactions level
1299 * for PCIX. Set MOST bits to zero.
1300 */
1301 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1302 pcixcmd &= 0x8F;
1303 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1304 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001305 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1306 ioc->prod_name = "LSIFC939X";
1307 ioc->bus_type = FC;
1308 ioc->errata_flag_1064 = 1;
1309 }
1310 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1311 ioc->prod_name = "LSIFC949X";
1312 ioc->bus_type = FC;
1313 ioc->errata_flag_1064 = 1;
1314 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001315 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1316 ioc->prod_name = "LSIFC949E";
1317 ioc->bus_type = FC;
1318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1320 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001321 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 /* 1030 Chip Fix. Disable Split transactions
1323 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1324 */
1325 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1326 if (revision < C0_1030) {
1327 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1328 pcixcmd &= 0x8F;
1329 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1330 }
1331 }
1332 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1333 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001334 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001336 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1337 ioc->prod_name = "LSISAS1064";
1338 ioc->bus_type = SAS;
1339 ioc->errata_flag_1064 = 1;
1340 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001341 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1342 ioc->prod_name = "LSISAS1068";
1343 ioc->bus_type = SAS;
1344 ioc->errata_flag_1064 = 1;
1345 }
1346 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1347 ioc->prod_name = "LSISAS1064E";
1348 ioc->bus_type = SAS;
1349 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001350 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1351 ioc->prod_name = "LSISAS1068E";
1352 ioc->bus_type = SAS;
1353 }
Eric Moore87cf8982006-06-27 16:09:26 -06001354 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
1355 ioc->prod_name = "LSISAS1078";
1356 ioc->bus_type = SAS;
1357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001359 if (ioc->errata_flag_1064)
1360 pci_disable_io_access(pdev);
1361
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 sprintf(ioc->name, "ioc%d", ioc->id);
1363
1364 spin_lock_init(&ioc->FreeQlock);
1365
1366 /* Disable all! */
1367 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1368 ioc->active = 0;
1369 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1370
1371 /* Set lookup ptr. */
1372 list_add_tail(&ioc->list, &ioc_list);
1373
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001374 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 */
1376 mpt_detect_bound_ports(ioc, pdev);
1377
James Bottomleyc92f2222006-03-01 09:02:49 -06001378 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1379 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 printk(KERN_WARNING MYNAM
1381 ": WARNING - %s did not initialize properly! (%d)\n",
1382 ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001384 if (ioc->alt_ioc)
1385 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 iounmap(mem);
1387 kfree(ioc);
1388 pci_set_drvdata(pdev, NULL);
1389 return r;
1390 }
1391
1392 /* call per device driver probe entry point */
1393 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1394 if(MptDeviceDriverHandlers[ii] &&
1395 MptDeviceDriverHandlers[ii]->probe) {
1396 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1397 }
1398 }
1399
1400#ifdef CONFIG_PROC_FS
1401 /*
1402 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1403 */
1404 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1405 if (dent) {
1406 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1407 if (ent) {
1408 ent->read_proc = procmpt_iocinfo_read;
1409 ent->data = ioc;
1410 }
1411 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1412 if (ent) {
1413 ent->read_proc = procmpt_summary_read;
1414 ent->data = ioc;
1415 }
1416 }
1417#endif
1418
1419 return 0;
1420}
1421
1422/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1423/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001424 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 * @pdev: Pointer to pci_dev structure
1426 *
1427 */
1428
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001429void
1430mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431{
1432 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1433 char pname[32];
1434 int ii;
1435
1436 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1437 remove_proc_entry(pname, NULL);
1438 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1439 remove_proc_entry(pname, NULL);
1440 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1441 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001442
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 /* call per device driver remove entry point */
1444 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1445 if(MptDeviceDriverHandlers[ii] &&
1446 MptDeviceDriverHandlers[ii]->remove) {
1447 MptDeviceDriverHandlers[ii]->remove(pdev);
1448 }
1449 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001450
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 /* Disable interrupts! */
1452 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1453
1454 ioc->active = 0;
1455 synchronize_irq(pdev->irq);
1456
1457 /* Clear any lingering interrupt */
1458 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1459
1460 CHIPREG_READ32(&ioc->chip->IntStatus);
1461
1462 mpt_adapter_dispose(ioc);
1463
1464 pci_set_drvdata(pdev, NULL);
1465}
1466
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467/**************************************************************************
1468 * Power Management
1469 */
1470#ifdef CONFIG_PM
1471/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1472/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001473 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 *
1475 *
1476 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001477int
1478mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479{
1480 u32 device_state;
1481 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
Pavel Machek2a569572005-07-07 17:56:40 -07001483 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484
1485 printk(MYIOC_s_INFO_FMT
1486 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1487 ioc->name, pdev, pci_name(pdev), device_state);
1488
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 pci_save_state(pdev);
1490
1491 /* put ioc into READY_STATE */
1492 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1493 printk(MYIOC_s_ERR_FMT
1494 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1495 }
1496
1497 /* disable interrupts */
1498 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1499 ioc->active = 0;
1500
1501 /* Clear any lingering interrupt */
1502 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1503
1504 pci_disable_device(pdev);
1505 pci_set_power_state(pdev, device_state);
1506
1507 return 0;
1508}
1509
1510/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1511/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001512 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 *
1514 *
1515 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001516int
1517mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518{
1519 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1520 u32 device_state = pdev->current_state;
1521 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001522
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 printk(MYIOC_s_INFO_FMT
1524 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1525 ioc->name, pdev, pci_name(pdev), device_state);
1526
1527 pci_set_power_state(pdev, 0);
1528 pci_restore_state(pdev);
1529 pci_enable_device(pdev);
1530
1531 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001532 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 ioc->active = 1;
1534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 printk(MYIOC_s_INFO_FMT
1536 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1537 ioc->name,
1538 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1539 CHIPREG_READ32(&ioc->chip->Doorbell));
1540
1541 /* bring ioc to operational state */
1542 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1543 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1544 printk(MYIOC_s_INFO_FMT
1545 "pci-resume: Cannot recover, error:[%x]\n",
1546 ioc->name, recovery_state);
1547 } else {
1548 printk(MYIOC_s_INFO_FMT
1549 "pci-resume: success\n", ioc->name);
1550 }
1551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 return 0;
1553}
1554#endif
1555
James Bottomley4ff42a62006-05-17 18:06:52 -05001556static int
1557mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1558{
1559 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1560 ioc->bus_type != SPI) ||
1561 (MptDriverClass[index] == MPTFC_DRIVER &&
1562 ioc->bus_type != FC) ||
1563 (MptDriverClass[index] == MPTSAS_DRIVER &&
1564 ioc->bus_type != SAS))
1565 /* make sure we only call the relevant reset handler
1566 * for the bus */
1567 return 0;
1568 return (MptResetHandlers[index])(ioc, reset_phase);
1569}
1570
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1572/*
1573 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1574 * @ioc: Pointer to MPT adapter structure
1575 * @reason: Event word / reason
1576 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1577 *
1578 * This routine performs all the steps necessary to bring the IOC
1579 * to a OPERATIONAL state.
1580 *
1581 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1582 * MPT adapter.
1583 *
1584 * Returns:
1585 * 0 for success
1586 * -1 if failed to get board READY
1587 * -2 if READY but IOCFacts Failed
1588 * -3 if READY but PrimeIOCFifos Failed
1589 * -4 if READY but IOCInit Failed
1590 */
1591static int
1592mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1593{
1594 int hard_reset_done = 0;
1595 int alt_ioc_ready = 0;
1596 int hard;
1597 int rc=0;
1598 int ii;
1599 int handlers;
1600 int ret = 0;
1601 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001602 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603
1604 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1605 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1606
1607 /* Disable reply interrupts (also blocks FreeQ) */
1608 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1609 ioc->active = 0;
1610
1611 if (ioc->alt_ioc) {
1612 if (ioc->alt_ioc->active)
1613 reset_alt_ioc_active = 1;
1614
1615 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1616 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1617 ioc->alt_ioc->active = 0;
1618 }
1619
1620 hard = 1;
1621 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1622 hard = 0;
1623
1624 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1625 if (hard_reset_done == -4) {
1626 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1627 ioc->name);
1628
1629 if (reset_alt_ioc_active && ioc->alt_ioc) {
1630 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1631 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1632 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001633 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 ioc->alt_ioc->active = 1;
1635 }
1636
1637 } else {
1638 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1639 ioc->name);
1640 }
1641 return -1;
1642 }
1643
1644 /* hard_reset_done = 0 if a soft reset was performed
1645 * and 1 if a hard reset was performed.
1646 */
1647 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1648 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1649 alt_ioc_ready = 1;
1650 else
1651 printk(KERN_WARNING MYNAM
1652 ": alt-%s: Not ready WARNING!\n",
1653 ioc->alt_ioc->name);
1654 }
1655
1656 for (ii=0; ii<5; ii++) {
1657 /* Get IOC facts! Allow 5 retries */
1658 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1659 break;
1660 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001661
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
1663 if (ii == 5) {
1664 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1665 ret = -2;
1666 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1667 MptDisplayIocCapabilities(ioc);
1668 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 if (alt_ioc_ready) {
1671 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1672 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1673 /* Retry - alt IOC was initialized once
1674 */
1675 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1676 }
1677 if (rc) {
1678 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1679 alt_ioc_ready = 0;
1680 reset_alt_ioc_active = 0;
1681 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1682 MptDisplayIocCapabilities(ioc->alt_ioc);
1683 }
1684 }
1685
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001686 /*
1687 * Device is reset now. It must have de-asserted the interrupt line
1688 * (if it was asserted) and it should be safe to register for the
1689 * interrupt now.
1690 */
1691 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1692 ioc->pci_irq = -1;
1693 if (ioc->pcidev->irq) {
1694 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1695 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1696 ioc->name);
1697 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
1698 SA_SHIRQ, ioc->name, ioc);
1699 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001700 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1701 "interrupt %d!\n", ioc->name,
1702 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001703 if (mpt_msi_enable)
1704 pci_disable_msi(ioc->pcidev);
1705 return -EBUSY;
1706 }
1707 irq_allocated = 1;
1708 ioc->pci_irq = ioc->pcidev->irq;
1709 pci_set_master(ioc->pcidev); /* ?? */
1710 pci_set_drvdata(ioc->pcidev, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001711 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1712 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001713 }
1714 }
1715
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 /* Prime reply & request queues!
1717 * (mucho alloc's) Must be done prior to
1718 * init as upper addresses are needed for init.
1719 * If fails, continue with alt-ioc processing
1720 */
1721 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1722 ret = -3;
1723
1724 /* May need to check/upload firmware & data here!
1725 * If fails, continue with alt-ioc processing
1726 */
1727 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1728 ret = -4;
1729// NEW!
1730 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1731 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1732 ioc->alt_ioc->name, rc);
1733 alt_ioc_ready = 0;
1734 reset_alt_ioc_active = 0;
1735 }
1736
1737 if (alt_ioc_ready) {
1738 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1739 alt_ioc_ready = 0;
1740 reset_alt_ioc_active = 0;
1741 printk(KERN_WARNING MYNAM
1742 ": alt-%s: (%d) init failure WARNING!\n",
1743 ioc->alt_ioc->name, rc);
1744 }
1745 }
1746
1747 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1748 if (ioc->upload_fw) {
1749 ddlprintk((MYIOC_s_INFO_FMT
1750 "firmware upload required!\n", ioc->name));
1751
1752 /* Controller is not operational, cannot do upload
1753 */
1754 if (ret == 0) {
1755 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001756 if (rc == 0) {
1757 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1758 /*
1759 * Maintain only one pointer to FW memory
1760 * so there will not be two attempt to
1761 * downloadboot onboard dual function
1762 * chips (mpt_adapter_disable,
1763 * mpt_diag_reset)
1764 */
1765 ioc->cached_fw = NULL;
1766 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1767 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1768 }
1769 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001771 ret = -5;
1772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 }
1774 }
1775 }
1776
1777 if (ret == 0) {
1778 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001779 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 ioc->active = 1;
1781 }
1782
1783 if (reset_alt_ioc_active && ioc->alt_ioc) {
1784 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001785 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001787 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 ioc->alt_ioc->active = 1;
1789 }
1790
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001791 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 * and EventAck handling.
1793 */
1794 if ((ret == 0) && (!ioc->facts.EventState))
1795 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1796
1797 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1798 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1799
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001800 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1802 * recursive scenario; GetLanConfigPages times out, timer expired
1803 * routine calls HardResetHandler, which calls into here again,
1804 * and we try GetLanConfigPages again...
1805 */
1806 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001807 if (ioc->bus_type == SAS) {
1808
1809 /* clear persistency table */
1810 if(ioc->facts.IOCExceptions &
1811 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1812 ret = mptbase_sas_persist_operation(ioc,
1813 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1814 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001815 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001816 }
1817
1818 /* Find IM volumes
1819 */
1820 mpt_findImVolumes(ioc);
1821
1822 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1824 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1825 /*
1826 * Pre-fetch the ports LAN MAC address!
1827 * (LANPage1_t stuff)
1828 */
1829 (void) GetLanConfigPages(ioc);
1830#ifdef MPT_DEBUG
1831 {
1832 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1833 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1834 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1835 }
1836#endif
1837 }
1838 } else {
1839 /* Get NVRAM and adapter maximums from SPP 0 and 2
1840 */
1841 mpt_GetScsiPortSettings(ioc, 0);
1842
1843 /* Get version and length of SDP 1
1844 */
1845 mpt_readScsiDevicePageHeaders(ioc, 0);
1846
1847 /* Find IM volumes
1848 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001849 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 mpt_findImVolumes(ioc);
1851
1852 /* Check, and possibly reset, the coalescing value
1853 */
1854 mpt_read_ioc_pg_1(ioc);
1855
1856 mpt_read_ioc_pg_4(ioc);
1857 }
1858
1859 GetIoUnitPage2(ioc);
1860 }
1861
1862 /*
1863 * Call each currently registered protocol IOC reset handler
1864 * with post-reset indication.
1865 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1866 * MptResetHandlers[] registered yet.
1867 */
1868 if (hard_reset_done) {
1869 rc = handlers = 0;
1870 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1871 if ((ret == 0) && MptResetHandlers[ii]) {
1872 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1873 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001874 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 handlers++;
1876 }
1877
1878 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001879 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001881 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 handlers++;
1883 }
1884 }
1885 /* FIXME? Examine results here? */
1886 }
1887
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001888out:
1889 if ((ret != 0) && irq_allocated) {
1890 free_irq(ioc->pci_irq, ioc);
1891 if (mpt_msi_enable)
1892 pci_disable_msi(ioc->pcidev);
1893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 return ret;
1895}
1896
1897/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1898/*
1899 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1900 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1901 * 929X, 1030 or 1035.
1902 * @ioc: Pointer to MPT adapter structure
1903 * @pdev: Pointer to (struct pci_dev) structure
1904 *
1905 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1906 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1907 */
1908static void
1909mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1910{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001911 struct pci_dev *peer=NULL;
1912 unsigned int slot = PCI_SLOT(pdev->devfn);
1913 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 MPT_ADAPTER *ioc_srch;
1915
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001916 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1917 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001918 ioc->name, pci_name(pdev), pdev->bus->number,
1919 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001920
1921 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1922 if (!peer) {
1923 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1924 if (!peer)
1925 return;
1926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
1928 list_for_each_entry(ioc_srch, &ioc_list, list) {
1929 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001930 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 /* Paranoia checks */
1932 if (ioc->alt_ioc != NULL) {
1933 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001934 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 break;
1936 } else if (ioc_srch->alt_ioc != NULL) {
1937 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001938 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 break;
1940 }
1941 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001942 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 ioc_srch->alt_ioc = ioc;
1944 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 }
1946 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001947 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948}
1949
1950/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1951/*
1952 * mpt_adapter_disable - Disable misbehaving MPT adapter.
1953 * @this: Pointer to MPT adapter structure
1954 */
1955static void
1956mpt_adapter_disable(MPT_ADAPTER *ioc)
1957{
1958 int sz;
1959 int ret;
1960
1961 if (ioc->cached_fw != NULL) {
1962 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001963 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 printk(KERN_WARNING MYNAM
1965 ": firmware downloadboot failure (%d)!\n", ret);
1966 }
1967 }
1968
1969 /* Disable adapter interrupts! */
1970 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1971 ioc->active = 0;
1972 /* Clear any lingering interrupt */
1973 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1974
1975 if (ioc->alloc != NULL) {
1976 sz = ioc->alloc_sz;
1977 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1978 ioc->name, ioc->alloc, ioc->alloc_sz));
1979 pci_free_consistent(ioc->pcidev, sz,
1980 ioc->alloc, ioc->alloc_dma);
1981 ioc->reply_frames = NULL;
1982 ioc->req_frames = NULL;
1983 ioc->alloc = NULL;
1984 ioc->alloc_total -= sz;
1985 }
1986
1987 if (ioc->sense_buf_pool != NULL) {
1988 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
1989 pci_free_consistent(ioc->pcidev, sz,
1990 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
1991 ioc->sense_buf_pool = NULL;
1992 ioc->alloc_total -= sz;
1993 }
1994
1995 if (ioc->events != NULL){
1996 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
1997 kfree(ioc->events);
1998 ioc->events = NULL;
1999 ioc->alloc_total -= sz;
2000 }
2001
2002 if (ioc->cached_fw != NULL) {
2003 sz = ioc->facts.FWImageSize;
2004 pci_free_consistent(ioc->pcidev, sz,
2005 ioc->cached_fw, ioc->cached_fw_dma);
2006 ioc->cached_fw = NULL;
2007 ioc->alloc_total -= sz;
2008 }
2009
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002010 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002011 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002012 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002013 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
2015 if (ioc->spi_data.pIocPg4 != NULL) {
2016 sz = ioc->spi_data.IocPg4Sz;
2017 pci_free_consistent(ioc->pcidev, sz,
2018 ioc->spi_data.pIocPg4,
2019 ioc->spi_data.IocPg4_dma);
2020 ioc->spi_data.pIocPg4 = NULL;
2021 ioc->alloc_total -= sz;
2022 }
2023
2024 if (ioc->ReqToChain != NULL) {
2025 kfree(ioc->ReqToChain);
2026 kfree(ioc->RequestNB);
2027 ioc->ReqToChain = NULL;
2028 }
2029
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002030 kfree(ioc->ChainToChain);
2031 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002032
2033 if (ioc->HostPageBuffer != NULL) {
2034 if((ret = mpt_host_page_access_control(ioc,
2035 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2036 printk(KERN_ERR MYNAM
2037 ": %s: host page buffers free failed (%d)!\n",
2038 __FUNCTION__, ret);
2039 }
2040 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2041 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2042 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2043 ioc->HostPageBuffer,
2044 ioc->HostPageBuffer_dma);
2045 ioc->HostPageBuffer = NULL;
2046 ioc->HostPageBuffer_sz = 0;
2047 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049}
2050
2051/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2052/*
2053 * mpt_adapter_dispose - Free all resources associated with a MPT
2054 * adapter.
2055 * @ioc: Pointer to MPT adapter structure
2056 *
2057 * This routine unregisters h/w resources and frees all alloc'd memory
2058 * associated with a MPT adapter structure.
2059 */
2060static void
2061mpt_adapter_dispose(MPT_ADAPTER *ioc)
2062{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002063 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002065 if (ioc == NULL)
2066 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002068 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002070 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002072 if (ioc->pci_irq != -1) {
2073 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002074 if (mpt_msi_enable)
2075 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002076 ioc->pci_irq = -1;
2077 }
2078
2079 if (ioc->memmap != NULL) {
2080 iounmap(ioc->memmap);
2081 ioc->memmap = NULL;
2082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
2084#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002085 if (ioc->mtrr_reg > 0) {
2086 mtrr_del(ioc->mtrr_reg, 0, 0);
2087 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2088 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089#endif
2090
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002091 /* Zap the adapter lookup ptr! */
2092 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002094 sz_last = ioc->alloc_total;
2095 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2096 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002097
2098 if (ioc->alt_ioc)
2099 ioc->alt_ioc->alt_ioc = NULL;
2100
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002101 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102}
2103
2104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2105/*
2106 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2107 * @ioc: Pointer to MPT adapter structure
2108 */
2109static void
2110MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2111{
2112 int i = 0;
2113
2114 printk(KERN_INFO "%s: ", ioc->name);
2115 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2116 printk("%s: ", ioc->prod_name+3);
2117 printk("Capabilities={");
2118
2119 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2120 printk("Initiator");
2121 i++;
2122 }
2123
2124 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2125 printk("%sTarget", i ? "," : "");
2126 i++;
2127 }
2128
2129 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2130 printk("%sLAN", i ? "," : "");
2131 i++;
2132 }
2133
2134#if 0
2135 /*
2136 * This would probably evoke more questions than it's worth
2137 */
2138 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2139 printk("%sLogBusAddr", i ? "," : "");
2140 i++;
2141 }
2142#endif
2143
2144 printk("}\n");
2145}
2146
2147/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2148/*
2149 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2150 * @ioc: Pointer to MPT_ADAPTER structure
2151 * @force: Force hard KickStart of IOC
2152 * @sleepFlag: Specifies whether the process can sleep
2153 *
2154 * Returns:
2155 * 1 - DIAG reset and READY
2156 * 0 - READY initially OR soft reset and READY
2157 * -1 - Any failure on KickStart
2158 * -2 - Msg Unit Reset Failed
2159 * -3 - IO Unit Reset Failed
2160 * -4 - IOC owned by a PEER
2161 */
2162static int
2163MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2164{
2165 u32 ioc_state;
2166 int statefault = 0;
2167 int cntdn;
2168 int hard_reset_done = 0;
2169 int r;
2170 int ii;
2171 int whoinit;
2172
2173 /* Get current [raw] IOC state */
2174 ioc_state = mpt_GetIocState(ioc, 0);
2175 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2176
2177 /*
2178 * Check to see if IOC got left/stuck in doorbell handshake
2179 * grip of death. If so, hard reset the IOC.
2180 */
2181 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2182 statefault = 1;
2183 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2184 ioc->name);
2185 }
2186
2187 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002188 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 return 0;
2190
2191 /*
2192 * Check to see if IOC is in FAULT state.
2193 */
2194 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2195 statefault = 2;
2196 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2197 ioc->name);
2198 printk(KERN_WARNING " FAULT code = %04xh\n",
2199 ioc_state & MPI_DOORBELL_DATA_MASK);
2200 }
2201
2202 /*
2203 * Hmmm... Did it get left operational?
2204 */
2205 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002206 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 ioc->name));
2208
2209 /* Check WhoInit.
2210 * If PCI Peer, exit.
2211 * Else, if no fault conditions are present, issue a MessageUnitReset
2212 * Else, fall through to KickStart case
2213 */
2214 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002215 dinitprintk((KERN_INFO MYNAM
2216 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 whoinit, statefault, force));
2218 if (whoinit == MPI_WHOINIT_PCI_PEER)
2219 return -4;
2220 else {
2221 if ((statefault == 0 ) && (force == 0)) {
2222 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2223 return 0;
2224 }
2225 statefault = 3;
2226 }
2227 }
2228
2229 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2230 if (hard_reset_done < 0)
2231 return -1;
2232
2233 /*
2234 * Loop here waiting for IOC to come READY.
2235 */
2236 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002237 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
2239 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2240 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2241 /*
2242 * BIOS or previous driver load left IOC in OP state.
2243 * Reset messaging FIFOs.
2244 */
2245 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2246 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2247 return -2;
2248 }
2249 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2250 /*
2251 * Something is wrong. Try to get IOC back
2252 * to a known state.
2253 */
2254 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2255 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2256 return -3;
2257 }
2258 }
2259
2260 ii++; cntdn--;
2261 if (!cntdn) {
2262 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2263 ioc->name, (int)((ii+5)/HZ));
2264 return -ETIME;
2265 }
2266
2267 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002268 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 } else {
2270 mdelay (1); /* 1 msec delay */
2271 }
2272
2273 }
2274
2275 if (statefault < 3) {
2276 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2277 ioc->name,
2278 statefault==1 ? "stuck handshake" : "IOC FAULT");
2279 }
2280
2281 return hard_reset_done;
2282}
2283
2284/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2285/*
2286 * mpt_GetIocState - Get the current state of a MPT adapter.
2287 * @ioc: Pointer to MPT_ADAPTER structure
2288 * @cooked: Request raw or cooked IOC state
2289 *
2290 * Returns all IOC Doorbell register bits if cooked==0, else just the
2291 * Doorbell bits in MPI_IOC_STATE_MASK.
2292 */
2293u32
2294mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2295{
2296 u32 s, sc;
2297
2298 /* Get! */
2299 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2300// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2301 sc = s & MPI_IOC_STATE_MASK;
2302
2303 /* Save! */
2304 ioc->last_state = sc;
2305
2306 return cooked ? sc : s;
2307}
2308
2309/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2310/*
2311 * GetIocFacts - Send IOCFacts request to MPT adapter.
2312 * @ioc: Pointer to MPT_ADAPTER structure
2313 * @sleepFlag: Specifies whether the process can sleep
2314 * @reason: If recovery, only update facts.
2315 *
2316 * Returns 0 for success, non-zero for failure.
2317 */
2318static int
2319GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2320{
2321 IOCFacts_t get_facts;
2322 IOCFactsReply_t *facts;
2323 int r;
2324 int req_sz;
2325 int reply_sz;
2326 int sz;
2327 u32 status, vv;
2328 u8 shiftFactor=1;
2329
2330 /* IOC *must* NOT be in RESET state! */
2331 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2332 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2333 ioc->name,
2334 ioc->last_state );
2335 return -44;
2336 }
2337
2338 facts = &ioc->facts;
2339
2340 /* Destination (reply area)... */
2341 reply_sz = sizeof(*facts);
2342 memset(facts, 0, reply_sz);
2343
2344 /* Request area (get_facts on the stack right now!) */
2345 req_sz = sizeof(get_facts);
2346 memset(&get_facts, 0, req_sz);
2347
2348 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2349 /* Assert: All other get_facts fields are zero! */
2350
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002351 dinitprintk((MYIOC_s_INFO_FMT
2352 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 ioc->name, req_sz, reply_sz));
2354
2355 /* No non-zero fields in the get_facts request are greater than
2356 * 1 byte in size, so we can just fire it off as is.
2357 */
2358 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2359 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2360 if (r != 0)
2361 return r;
2362
2363 /*
2364 * Now byte swap (GRRR) the necessary fields before any further
2365 * inspection of reply contents.
2366 *
2367 * But need to do some sanity checks on MsgLength (byte) field
2368 * to make sure we don't zero IOC's req_sz!
2369 */
2370 /* Did we get a valid reply? */
2371 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2372 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2373 /*
2374 * If not been here, done that, save off first WhoInit value
2375 */
2376 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2377 ioc->FirstWhoInit = facts->WhoInit;
2378 }
2379
2380 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2381 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2382 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2383 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2384 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002385 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 /* CHECKME! IOCStatus, IOCLogInfo */
2387
2388 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2389 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2390
2391 /*
2392 * FC f/w version changed between 1.1 and 1.2
2393 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2394 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2395 */
2396 if (facts->MsgVersion < 0x0102) {
2397 /*
2398 * Handle old FC f/w style, convert to new...
2399 */
2400 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2401 facts->FWVersion.Word =
2402 ((oldv<<12) & 0xFF000000) |
2403 ((oldv<<8) & 0x000FFF00);
2404 } else
2405 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2406
2407 facts->ProductID = le16_to_cpu(facts->ProductID);
2408 facts->CurrentHostMfaHighAddr =
2409 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2410 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2411 facts->CurrentSenseBufferHighAddr =
2412 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2413 facts->CurReplyFrameSize =
2414 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002415 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
2417 /*
2418 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2419 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2420 * to 14 in MPI-1.01.0x.
2421 */
2422 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2423 facts->MsgVersion > 0x0100) {
2424 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2425 }
2426
2427 sz = facts->FWImageSize;
2428 if ( sz & 0x01 )
2429 sz += 1;
2430 if ( sz & 0x02 )
2431 sz += 2;
2432 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002433
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 if (!facts->RequestFrameSize) {
2435 /* Something is wrong! */
2436 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2437 ioc->name);
2438 return -55;
2439 }
2440
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002441 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 vv = ((63 / (sz * 4)) + 1) & 0x03;
2443 ioc->NB_for_64_byte_frame = vv;
2444 while ( sz )
2445 {
2446 shiftFactor++;
2447 sz = sz >> 1;
2448 }
2449 ioc->NBShiftFactor = shiftFactor;
2450 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2451 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2454 /*
2455 * Set values for this IOC's request & reply frame sizes,
2456 * and request & reply queue depths...
2457 */
2458 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2459 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2460 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2461 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2462
2463 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2464 ioc->name, ioc->reply_sz, ioc->reply_depth));
2465 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2466 ioc->name, ioc->req_sz, ioc->req_depth));
2467
2468 /* Get port facts! */
2469 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2470 return r;
2471 }
2472 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002473 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2475 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2476 RequestFrameSize)/sizeof(u32)));
2477 return -66;
2478 }
2479
2480 return 0;
2481}
2482
2483/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2484/*
2485 * GetPortFacts - Send PortFacts request to MPT adapter.
2486 * @ioc: Pointer to MPT_ADAPTER structure
2487 * @portnum: Port number
2488 * @sleepFlag: Specifies whether the process can sleep
2489 *
2490 * Returns 0 for success, non-zero for failure.
2491 */
2492static int
2493GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2494{
2495 PortFacts_t get_pfacts;
2496 PortFactsReply_t *pfacts;
2497 int ii;
2498 int req_sz;
2499 int reply_sz;
2500
2501 /* IOC *must* NOT be in RESET state! */
2502 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2503 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2504 ioc->name,
2505 ioc->last_state );
2506 return -4;
2507 }
2508
2509 pfacts = &ioc->pfacts[portnum];
2510
2511 /* Destination (reply area)... */
2512 reply_sz = sizeof(*pfacts);
2513 memset(pfacts, 0, reply_sz);
2514
2515 /* Request area (get_pfacts on the stack right now!) */
2516 req_sz = sizeof(get_pfacts);
2517 memset(&get_pfacts, 0, req_sz);
2518
2519 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2520 get_pfacts.PortNumber = portnum;
2521 /* Assert: All other get_pfacts fields are zero! */
2522
2523 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2524 ioc->name, portnum));
2525
2526 /* No non-zero fields in the get_pfacts request are greater than
2527 * 1 byte in size, so we can just fire it off as is.
2528 */
2529 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2530 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2531 if (ii != 0)
2532 return ii;
2533
2534 /* Did we get a valid reply? */
2535
2536 /* Now byte swap the necessary fields in the response. */
2537 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2538 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2539 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2540 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2541 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2542 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2543 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2544 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2545 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2546
2547 return 0;
2548}
2549
2550/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2551/*
2552 * SendIocInit - Send IOCInit request to MPT adapter.
2553 * @ioc: Pointer to MPT_ADAPTER structure
2554 * @sleepFlag: Specifies whether the process can sleep
2555 *
2556 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2557 *
2558 * Returns 0 for success, non-zero for failure.
2559 */
2560static int
2561SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2562{
2563 IOCInit_t ioc_init;
2564 MPIDefaultReply_t init_reply;
2565 u32 state;
2566 int r;
2567 int count;
2568 int cntdn;
2569
2570 memset(&ioc_init, 0, sizeof(ioc_init));
2571 memset(&init_reply, 0, sizeof(init_reply));
2572
2573 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2574 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2575
2576 /* If we are in a recovery mode and we uploaded the FW image,
2577 * then this pointer is not NULL. Skip the upload a second time.
2578 * Set this flag if cached_fw set for either IOC.
2579 */
2580 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2581 ioc->upload_fw = 1;
2582 else
2583 ioc->upload_fw = 0;
2584 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2585 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2586
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002587 if(ioc->bus_type == SAS)
2588 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2589 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2591 else
2592 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002594 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2595 ioc->name, ioc->facts.MsgVersion));
2596 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2597 // set MsgVersion and HeaderVersion host driver was built with
2598 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2599 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002601 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2602 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2603 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2604 return -99;
2605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2607
2608 if (sizeof(dma_addr_t) == sizeof(u64)) {
2609 /* Save the upper 32-bits of the request
2610 * (reply) and sense buffers.
2611 */
2612 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2613 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2614 } else {
2615 /* Force 32-bit addressing */
2616 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2617 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2618 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002619
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2621 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002622 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2623 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624
2625 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2626 ioc->name, &ioc_init));
2627
2628 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2629 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002630 if (r != 0) {
2631 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634
2635 /* No need to byte swap the multibyte fields in the reply
2636 * since we don't even look at it's contents.
2637 */
2638
2639 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2640 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002641
2642 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2643 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
2647 /* YIKES! SUPER IMPORTANT!!!
2648 * Poll IocState until _OPERATIONAL while IOC is doing
2649 * LoopInit and TargetDiscovery!
2650 */
2651 count = 0;
2652 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2653 state = mpt_GetIocState(ioc, 1);
2654 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2655 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002656 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 } else {
2658 mdelay(1);
2659 }
2660
2661 if (!cntdn) {
2662 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2663 ioc->name, (int)((count+5)/HZ));
2664 return -9;
2665 }
2666
2667 state = mpt_GetIocState(ioc, 1);
2668 count++;
2669 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002670 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 ioc->name, count));
2672
2673 return r;
2674}
2675
2676/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2677/*
2678 * SendPortEnable - Send PortEnable request to MPT adapter port.
2679 * @ioc: Pointer to MPT_ADAPTER structure
2680 * @portnum: Port number to enable
2681 * @sleepFlag: Specifies whether the process can sleep
2682 *
2683 * Send PortEnable to bring IOC to OPERATIONAL state.
2684 *
2685 * Returns 0 for success, non-zero for failure.
2686 */
2687static int
2688SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2689{
2690 PortEnable_t port_enable;
2691 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002692 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 int req_sz;
2694 int reply_sz;
2695
2696 /* Destination... */
2697 reply_sz = sizeof(MPIDefaultReply_t);
2698 memset(&reply_buf, 0, reply_sz);
2699
2700 req_sz = sizeof(PortEnable_t);
2701 memset(&port_enable, 0, req_sz);
2702
2703 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2704 port_enable.PortNumber = portnum;
2705/* port_enable.ChainOffset = 0; */
2706/* port_enable.MsgFlags = 0; */
2707/* port_enable.MsgContext = 0; */
2708
2709 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2710 ioc->name, portnum, &port_enable));
2711
2712 /* RAID FW may take a long time to enable
2713 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002714 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2715 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2716 (ioc->bus_type == SAS)) {
2717 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2718 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2719 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002720 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002721 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2722 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2723 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002725 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726}
2727
2728/*
2729 * ioc: Pointer to MPT_ADAPTER structure
2730 * size - total FW bytes
2731 */
2732void
2733mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2734{
2735 if (ioc->cached_fw)
2736 return; /* use already allocated memory */
2737 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2738 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2739 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2740 } else {
2741 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2742 ioc->alloc_total += size;
2743 }
2744}
2745/*
2746 * If alt_img is NULL, delete from ioc structure.
2747 * Else, delete a secondary image in same format.
2748 */
2749void
2750mpt_free_fw_memory(MPT_ADAPTER *ioc)
2751{
2752 int sz;
2753
2754 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002755 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2757 pci_free_consistent(ioc->pcidev, sz,
2758 ioc->cached_fw, ioc->cached_fw_dma);
2759 ioc->cached_fw = NULL;
2760
2761 return;
2762}
2763
2764
2765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2766/*
2767 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2768 * @ioc: Pointer to MPT_ADAPTER structure
2769 * @sleepFlag: Specifies whether the process can sleep
2770 *
2771 * Returns 0 for success, >0 for handshake failure
2772 * <0 for fw upload failure.
2773 *
2774 * Remark: If bound IOC and a successful FWUpload was performed
2775 * on the bound IOC, the second image is discarded
2776 * and memory is free'd. Both channels must upload to prevent
2777 * IOC from running in degraded mode.
2778 */
2779static int
2780mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2781{
2782 u8 request[ioc->req_sz];
2783 u8 reply[sizeof(FWUploadReply_t)];
2784 FWUpload_t *prequest;
2785 FWUploadReply_t *preply;
2786 FWUploadTCSGE_t *ptcsge;
2787 int sgeoffset;
2788 u32 flagsLength;
2789 int ii, sz, reply_sz;
2790 int cmdStatus;
2791
2792 /* If the image size is 0, we are done.
2793 */
2794 if ((sz = ioc->facts.FWImageSize) == 0)
2795 return 0;
2796
2797 mpt_alloc_fw_memory(ioc, sz);
2798
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002799 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002801
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 if (ioc->cached_fw == NULL) {
2803 /* Major Failure.
2804 */
2805 return -ENOMEM;
2806 }
2807
2808 prequest = (FWUpload_t *)&request;
2809 preply = (FWUploadReply_t *)&reply;
2810
2811 /* Destination... */
2812 memset(prequest, 0, ioc->req_sz);
2813
2814 reply_sz = sizeof(reply);
2815 memset(preply, 0, reply_sz);
2816
2817 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2818 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2819
2820 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2821 ptcsge->DetailsLength = 12;
2822 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2823 ptcsge->ImageSize = cpu_to_le32(sz);
2824
2825 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2826
2827 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2828 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2829
2830 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002831 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 prequest, sgeoffset));
2833 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2834
2835 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2836 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2837
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002838 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839
2840 cmdStatus = -EFAULT;
2841 if (ii == 0) {
2842 /* Handshake transfer was complete and successful.
2843 * Check the Reply Frame.
2844 */
2845 int status, transfer_sz;
2846 status = le16_to_cpu(preply->IOCStatus);
2847 if (status == MPI_IOCSTATUS_SUCCESS) {
2848 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2849 if (transfer_sz == sz)
2850 cmdStatus = 0;
2851 }
2852 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002853 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 ioc->name, cmdStatus));
2855
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002856
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 if (cmdStatus) {
2858
2859 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2860 ioc->name));
2861 mpt_free_fw_memory(ioc);
2862 }
2863
2864 return cmdStatus;
2865}
2866
2867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2868/*
2869 * mpt_downloadboot - DownloadBoot code
2870 * @ioc: Pointer to MPT_ADAPTER structure
2871 * @flag: Specify which part of IOC memory is to be uploaded.
2872 * @sleepFlag: Specifies whether the process can sleep
2873 *
2874 * FwDownloadBoot requires Programmed IO access.
2875 *
2876 * Returns 0 for success
2877 * -1 FW Image size is 0
2878 * -2 No valid cached_fw Pointer
2879 * <0 for fw upload failure.
2880 */
2881static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002882mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 MpiExtImageHeader_t *pExtImage;
2885 u32 fwSize;
2886 u32 diag0val;
2887 int count;
2888 u32 *ptrFw;
2889 u32 diagRwData;
2890 u32 nextImage;
2891 u32 load_addr;
2892 u32 ioc_state=0;
2893
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002894 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2895 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002896
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2898 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2899 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2900 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2901 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2902 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2903
2904 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2905
2906 /* wait 1 msec */
2907 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002908 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 } else {
2910 mdelay (1);
2911 }
2912
2913 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2914 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2915
2916 for (count = 0; count < 30; count ++) {
2917 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2918 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2919 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2920 ioc->name, count));
2921 break;
2922 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002923 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002925 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002927 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 }
2929 }
2930
2931 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002932 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2933 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 ioc->name, diag0val));
2935 return -3;
2936 }
2937
2938 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2939 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2940 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2941 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2942 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2943 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2944
2945 /* Set the DiagRwEn and Disable ARM bits */
2946 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2947
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 fwSize = (pFwHeader->ImageSize + 3)/4;
2949 ptrFw = (u32 *) pFwHeader;
2950
2951 /* Write the LoadStartAddress to the DiagRw Address Register
2952 * using Programmed IO
2953 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002954 if (ioc->errata_flag_1064)
2955 pci_enable_io_access(ioc->pcidev);
2956
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2958 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2959 ioc->name, pFwHeader->LoadStartAddress));
2960
2961 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2962 ioc->name, fwSize*4, ptrFw));
2963 while (fwSize--) {
2964 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2965 }
2966
2967 nextImage = pFwHeader->NextImageHeaderOffset;
2968 while (nextImage) {
2969 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
2970
2971 load_addr = pExtImage->LoadStartAddress;
2972
2973 fwSize = (pExtImage->ImageSize + 3) >> 2;
2974 ptrFw = (u32 *)pExtImage;
2975
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002976 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
2977 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
2979
2980 while (fwSize--) {
2981 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2982 }
2983 nextImage = pExtImage->NextImageHeaderOffset;
2984 }
2985
2986 /* Write the IopResetVectorRegAddr */
2987 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
2988 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
2989
2990 /* Write the IopResetVectorValue */
2991 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
2992 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
2993
2994 /* Clear the internal flash bad bit - autoincrementing register,
2995 * so must do two writes.
2996 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002997 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002998 /*
2999 * 1030 and 1035 H/W errata, workaround to access
3000 * the ClearFlashBadSignatureBit
3001 */
3002 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3003 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3004 diagRwData |= 0x40000000;
3005 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3006 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3007
3008 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3009 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3010 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3011 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3012
3013 /* wait 1 msec */
3014 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003015 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003016 } else {
3017 mdelay (1);
3018 }
3019 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003021 if (ioc->errata_flag_1064)
3022 pci_disable_io_access(ioc->pcidev);
3023
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003025 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3026 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003028 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3030 ioc->name, diag0val));
3031 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3032
3033 /* Write 0xFF to reset the sequencer */
3034 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3035
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003036 if (ioc->bus_type == SAS) {
3037 ioc_state = mpt_GetIocState(ioc, 0);
3038 if ( (GetIocFacts(ioc, sleepFlag,
3039 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3040 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3041 ioc->name, ioc_state));
3042 return -EFAULT;
3043 }
3044 }
3045
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 for (count=0; count<HZ*20; count++) {
3047 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3048 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3049 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003050 if (ioc->bus_type == SAS) {
3051 return 0;
3052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3054 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3055 ioc->name));
3056 return -EFAULT;
3057 }
3058 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3059 ioc->name));
3060 return 0;
3061 }
3062 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003063 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 } else {
3065 mdelay (10);
3066 }
3067 }
3068 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3069 ioc->name, ioc_state));
3070 return -EFAULT;
3071}
3072
3073/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3074/*
3075 * KickStart - Perform hard reset of MPT adapter.
3076 * @ioc: Pointer to MPT_ADAPTER structure
3077 * @force: Force hard reset
3078 * @sleepFlag: Specifies whether the process can sleep
3079 *
3080 * This routine places MPT adapter in diagnostic mode via the
3081 * WriteSequence register, and then performs a hard reset of adapter
3082 * via the Diagnostic register.
3083 *
3084 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3085 * or NO_SLEEP (interrupt thread, use mdelay)
3086 * force - 1 if doorbell active, board fault state
3087 * board operational, IOC_RECOVERY or
3088 * IOC_BRINGUP and there is an alt_ioc.
3089 * 0 else
3090 *
3091 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003092 * 1 - hard reset, READY
3093 * 0 - no reset due to History bit, READY
3094 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 * OR reset but failed to come READY
3096 * -2 - no reset, could not enter DIAG mode
3097 * -3 - reset but bad FW bit
3098 */
3099static int
3100KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3101{
3102 int hard_reset_done = 0;
3103 u32 ioc_state=0;
3104 int cnt,cntdn;
3105
3106 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003107 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 /* Always issue a Msg Unit Reset first. This will clear some
3109 * SCSI bus hang conditions.
3110 */
3111 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3112
3113 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003114 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 } else {
3116 mdelay (1000);
3117 }
3118 }
3119
3120 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3121 if (hard_reset_done < 0)
3122 return hard_reset_done;
3123
3124 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3125 ioc->name));
3126
3127 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3128 for (cnt=0; cnt<cntdn; cnt++) {
3129 ioc_state = mpt_GetIocState(ioc, 1);
3130 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3131 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3132 ioc->name, cnt));
3133 return hard_reset_done;
3134 }
3135 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003136 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 } else {
3138 mdelay (10);
3139 }
3140 }
3141
3142 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3143 ioc->name, ioc_state);
3144 return -1;
3145}
3146
3147/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3148/*
3149 * mpt_diag_reset - Perform hard reset of the adapter.
3150 * @ioc: Pointer to MPT_ADAPTER structure
3151 * @ignore: Set if to honor and clear to ignore
3152 * the reset history bit
3153 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3154 * else set to NO_SLEEP (use mdelay instead)
3155 *
3156 * This routine places the adapter in diagnostic mode via the
3157 * WriteSequence register and then performs a hard reset of adapter
3158 * via the Diagnostic register. Adapter should be in ready state
3159 * upon successful completion.
3160 *
3161 * Returns: 1 hard reset successful
3162 * 0 no reset performed because reset history bit set
3163 * -2 enabling diagnostic mode failed
3164 * -3 diagnostic reset failed
3165 */
3166static int
3167mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3168{
3169 u32 diag0val;
3170 u32 doorbell;
3171 int hard_reset_done = 0;
3172 int count = 0;
3173#ifdef MPT_DEBUG
3174 u32 diag1val = 0;
3175#endif
3176
Eric Moore87cf8982006-06-27 16:09:26 -06003177 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
3178 drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
3179 "address=%p\n", ioc->name, __FUNCTION__,
3180 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3181 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3182 if (sleepFlag == CAN_SLEEP)
3183 msleep(1);
3184 else
3185 mdelay(1);
3186
3187 for (count = 0; count < 60; count ++) {
3188 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3189 doorbell &= MPI_IOC_STATE_MASK;
3190
3191 drsprintk((MYIOC_s_INFO_FMT
3192 "looking for READY STATE: doorbell=%x"
3193 " count=%d\n",
3194 ioc->name, doorbell, count));
3195 if (doorbell == MPI_IOC_STATE_READY) {
3196 return 0;
3197 }
3198
3199 /* wait 1 sec */
3200 if (sleepFlag == CAN_SLEEP)
3201 msleep(1000);
3202 else
3203 mdelay(1000);
3204 }
3205 return -1;
3206 }
3207
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 /* Clear any existing interrupts */
3209 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3210
3211 /* Use "Diagnostic reset" method! (only thing available!) */
3212 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3213
3214#ifdef MPT_DEBUG
3215 if (ioc->alt_ioc)
3216 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3217 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3218 ioc->name, diag0val, diag1val));
3219#endif
3220
3221 /* Do the reset if we are told to ignore the reset history
3222 * or if the reset history is 0
3223 */
3224 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3225 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3226 /* Write magic sequence to WriteSequence register
3227 * Loop until in diagnostic mode
3228 */
3229 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3230 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3231 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3232 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3233 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3234 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3235
3236 /* wait 100 msec */
3237 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003238 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 } else {
3240 mdelay (100);
3241 }
3242
3243 count++;
3244 if (count > 20) {
3245 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3246 ioc->name, diag0val);
3247 return -2;
3248
3249 }
3250
3251 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3252
3253 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3254 ioc->name, diag0val));
3255 }
3256
3257#ifdef MPT_DEBUG
3258 if (ioc->alt_ioc)
3259 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3260 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3261 ioc->name, diag0val, diag1val));
3262#endif
3263 /*
3264 * Disable the ARM (Bug fix)
3265 *
3266 */
3267 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003268 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269
3270 /*
3271 * Now hit the reset bit in the Diagnostic register
3272 * (THE BIG HAMMER!) (Clears DRWE bit).
3273 */
3274 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3275 hard_reset_done = 1;
3276 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3277 ioc->name));
3278
3279 /*
3280 * Call each currently registered protocol IOC reset handler
3281 * with pre-reset indication.
3282 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3283 * MptResetHandlers[] registered yet.
3284 */
3285 {
3286 int ii;
3287 int r = 0;
3288
3289 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3290 if (MptResetHandlers[ii]) {
3291 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3292 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003293 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 if (ioc->alt_ioc) {
3295 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3296 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003297 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 }
3299 }
3300 }
3301 /* FIXME? Examine results here? */
3302 }
3303
3304 if (ioc->cached_fw) {
3305 /* If the DownloadBoot operation fails, the
3306 * IOC will be left unusable. This is a fatal error
3307 * case. _diag_reset will return < 0
3308 */
3309 for (count = 0; count < 30; count ++) {
3310 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3311 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3312 break;
3313 }
3314
3315 /* wait 1 sec */
3316 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003317 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 } else {
3319 mdelay (1000);
3320 }
3321 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003322 if ((count = mpt_downloadboot(ioc,
3323 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 printk(KERN_WARNING MYNAM
3325 ": firmware downloadboot failure (%d)!\n", count);
3326 }
3327
3328 } else {
3329 /* Wait for FW to reload and for board
3330 * to go to the READY state.
3331 * Maximum wait is 60 seconds.
3332 * If fail, no error will check again
3333 * with calling program.
3334 */
3335 for (count = 0; count < 60; count ++) {
3336 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3337 doorbell &= MPI_IOC_STATE_MASK;
3338
3339 if (doorbell == MPI_IOC_STATE_READY) {
3340 break;
3341 }
3342
3343 /* wait 1 sec */
3344 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003345 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 } else {
3347 mdelay (1000);
3348 }
3349 }
3350 }
3351 }
3352
3353 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3354#ifdef MPT_DEBUG
3355 if (ioc->alt_ioc)
3356 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3357 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3358 ioc->name, diag0val, diag1val));
3359#endif
3360
3361 /* Clear RESET_HISTORY bit! Place board in the
3362 * diagnostic mode to update the diag register.
3363 */
3364 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3365 count = 0;
3366 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3367 /* Write magic sequence to WriteSequence register
3368 * Loop until in diagnostic mode
3369 */
3370 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3371 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3372 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3373 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3374 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3375 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3376
3377 /* wait 100 msec */
3378 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003379 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 } else {
3381 mdelay (100);
3382 }
3383
3384 count++;
3385 if (count > 20) {
3386 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3387 ioc->name, diag0val);
3388 break;
3389 }
3390 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3391 }
3392 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3393 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3394 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3395 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3396 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3397 ioc->name);
3398 }
3399
3400 /* Disable Diagnostic Mode
3401 */
3402 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3403
3404 /* Check FW reload status flags.
3405 */
3406 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3407 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3408 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3409 ioc->name, diag0val);
3410 return -3;
3411 }
3412
3413#ifdef MPT_DEBUG
3414 if (ioc->alt_ioc)
3415 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3416 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3417 ioc->name, diag0val, diag1val));
3418#endif
3419
3420 /*
3421 * Reset flag that says we've enabled event notification
3422 */
3423 ioc->facts.EventState = 0;
3424
3425 if (ioc->alt_ioc)
3426 ioc->alt_ioc->facts.EventState = 0;
3427
3428 return hard_reset_done;
3429}
3430
3431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3432/*
3433 * SendIocReset - Send IOCReset request to MPT adapter.
3434 * @ioc: Pointer to MPT_ADAPTER structure
3435 * @reset_type: reset type, expected values are
3436 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3437 *
3438 * Send IOCReset request to the MPT adapter.
3439 *
3440 * Returns 0 for success, non-zero for failure.
3441 */
3442static int
3443SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3444{
3445 int r;
3446 u32 state;
3447 int cntdn, count;
3448
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003449 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 ioc->name, reset_type));
3451 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3452 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3453 return r;
3454
3455 /* FW ACK'd request, wait for READY state
3456 */
3457 count = 0;
3458 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3459
3460 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3461 cntdn--;
3462 count++;
3463 if (!cntdn) {
3464 if (sleepFlag != CAN_SLEEP)
3465 count *= 10;
3466
3467 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3468 ioc->name, (int)((count+5)/HZ));
3469 return -ETIME;
3470 }
3471
3472 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003473 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 } else {
3475 mdelay (1); /* 1 msec delay */
3476 }
3477 }
3478
3479 /* TODO!
3480 * Cleanup all event stuff for this IOC; re-issue EventNotification
3481 * request if needed.
3482 */
3483 if (ioc->facts.Function)
3484 ioc->facts.EventState = 0;
3485
3486 return 0;
3487}
3488
3489/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3490/*
3491 * initChainBuffers - Allocate memory for and initialize
3492 * chain buffers, chain buffer control arrays and spinlock.
3493 * @hd: Pointer to MPT_SCSI_HOST structure
3494 * @init: If set, initialize the spin lock.
3495 */
3496static int
3497initChainBuffers(MPT_ADAPTER *ioc)
3498{
3499 u8 *mem;
3500 int sz, ii, num_chain;
3501 int scale, num_sge, numSGE;
3502
3503 /* ReqToChain size must equal the req_depth
3504 * index = req_idx
3505 */
3506 if (ioc->ReqToChain == NULL) {
3507 sz = ioc->req_depth * sizeof(int);
3508 mem = kmalloc(sz, GFP_ATOMIC);
3509 if (mem == NULL)
3510 return -1;
3511
3512 ioc->ReqToChain = (int *) mem;
3513 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3514 ioc->name, mem, sz));
3515 mem = kmalloc(sz, GFP_ATOMIC);
3516 if (mem == NULL)
3517 return -1;
3518
3519 ioc->RequestNB = (int *) mem;
3520 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3521 ioc->name, mem, sz));
3522 }
3523 for (ii = 0; ii < ioc->req_depth; ii++) {
3524 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3525 }
3526
3527 /* ChainToChain size must equal the total number
3528 * of chain buffers to be allocated.
3529 * index = chain_idx
3530 *
3531 * Calculate the number of chain buffers needed(plus 1) per I/O
3532 * then multiply the the maximum number of simultaneous cmds
3533 *
3534 * num_sge = num sge in request frame + last chain buffer
3535 * scale = num sge per chain buffer if no chain element
3536 */
3537 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3538 if (sizeof(dma_addr_t) == sizeof(u64))
3539 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3540 else
3541 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3542
3543 if (sizeof(dma_addr_t) == sizeof(u64)) {
3544 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3545 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3546 } else {
3547 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3548 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3549 }
3550 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3551 ioc->name, num_sge, numSGE));
3552
3553 if ( numSGE > MPT_SCSI_SG_DEPTH )
3554 numSGE = MPT_SCSI_SG_DEPTH;
3555
3556 num_chain = 1;
3557 while (numSGE - num_sge > 0) {
3558 num_chain++;
3559 num_sge += (scale - 1);
3560 }
3561 num_chain++;
3562
3563 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3564 ioc->name, numSGE, num_sge, num_chain));
3565
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003566 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 num_chain *= MPT_SCSI_CAN_QUEUE;
3568 else
3569 num_chain *= MPT_FC_CAN_QUEUE;
3570
3571 ioc->num_chain = num_chain;
3572
3573 sz = num_chain * sizeof(int);
3574 if (ioc->ChainToChain == NULL) {
3575 mem = kmalloc(sz, GFP_ATOMIC);
3576 if (mem == NULL)
3577 return -1;
3578
3579 ioc->ChainToChain = (int *) mem;
3580 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3581 ioc->name, mem, sz));
3582 } else {
3583 mem = (u8 *) ioc->ChainToChain;
3584 }
3585 memset(mem, 0xFF, sz);
3586 return num_chain;
3587}
3588
3589/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3590/*
3591 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3592 * @ioc: Pointer to MPT_ADAPTER structure
3593 *
3594 * This routine allocates memory for the MPT reply and request frame
3595 * pools (if necessary), and primes the IOC reply FIFO with
3596 * reply frames.
3597 *
3598 * Returns 0 for success, non-zero for failure.
3599 */
3600static int
3601PrimeIocFifos(MPT_ADAPTER *ioc)
3602{
3603 MPT_FRAME_HDR *mf;
3604 unsigned long flags;
3605 dma_addr_t alloc_dma;
3606 u8 *mem;
3607 int i, reply_sz, sz, total_size, num_chain;
3608
3609 /* Prime reply FIFO... */
3610
3611 if (ioc->reply_frames == NULL) {
3612 if ( (num_chain = initChainBuffers(ioc)) < 0)
3613 return -1;
3614
3615 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3616 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3617 ioc->name, ioc->reply_sz, ioc->reply_depth));
3618 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3619 ioc->name, reply_sz, reply_sz));
3620
3621 sz = (ioc->req_sz * ioc->req_depth);
3622 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3623 ioc->name, ioc->req_sz, ioc->req_depth));
3624 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3625 ioc->name, sz, sz));
3626 total_size += sz;
3627
3628 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3629 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3630 ioc->name, ioc->req_sz, num_chain));
3631 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3632 ioc->name, sz, sz, num_chain));
3633
3634 total_size += sz;
3635 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3636 if (mem == NULL) {
3637 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3638 ioc->name);
3639 goto out_fail;
3640 }
3641
3642 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3643 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3644
3645 memset(mem, 0, total_size);
3646 ioc->alloc_total += total_size;
3647 ioc->alloc = mem;
3648 ioc->alloc_dma = alloc_dma;
3649 ioc->alloc_sz = total_size;
3650 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3651 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3652
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003653 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3654 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3655
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 alloc_dma += reply_sz;
3657 mem += reply_sz;
3658
3659 /* Request FIFO - WE manage this! */
3660
3661 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3662 ioc->req_frames_dma = alloc_dma;
3663
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003664 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 ioc->name, mem, (void *)(ulong)alloc_dma));
3666
3667 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3668
3669#if defined(CONFIG_MTRR) && 0
3670 /*
3671 * Enable Write Combining MTRR for IOC's memory region.
3672 * (at least as much as we can; "size and base must be
3673 * multiples of 4 kiB"
3674 */
3675 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3676 sz,
3677 MTRR_TYPE_WRCOMB, 1);
3678 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3679 ioc->name, ioc->req_frames_dma, sz));
3680#endif
3681
3682 for (i = 0; i < ioc->req_depth; i++) {
3683 alloc_dma += ioc->req_sz;
3684 mem += ioc->req_sz;
3685 }
3686
3687 ioc->ChainBuffer = mem;
3688 ioc->ChainBufferDMA = alloc_dma;
3689
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003690 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3692
3693 /* Initialize the free chain Q.
3694 */
3695
3696 INIT_LIST_HEAD(&ioc->FreeChainQ);
3697
3698 /* Post the chain buffers to the FreeChainQ.
3699 */
3700 mem = (u8 *)ioc->ChainBuffer;
3701 for (i=0; i < num_chain; i++) {
3702 mf = (MPT_FRAME_HDR *) mem;
3703 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3704 mem += ioc->req_sz;
3705 }
3706
3707 /* Initialize Request frames linked list
3708 */
3709 alloc_dma = ioc->req_frames_dma;
3710 mem = (u8 *) ioc->req_frames;
3711
3712 spin_lock_irqsave(&ioc->FreeQlock, flags);
3713 INIT_LIST_HEAD(&ioc->FreeQ);
3714 for (i = 0; i < ioc->req_depth; i++) {
3715 mf = (MPT_FRAME_HDR *) mem;
3716
3717 /* Queue REQUESTs *internally*! */
3718 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3719
3720 mem += ioc->req_sz;
3721 }
3722 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3723
3724 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3725 ioc->sense_buf_pool =
3726 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3727 if (ioc->sense_buf_pool == NULL) {
3728 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3729 ioc->name);
3730 goto out_fail;
3731 }
3732
3733 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3734 ioc->alloc_total += sz;
3735 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3736 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3737
3738 }
3739
3740 /* Post Reply frames to FIFO
3741 */
3742 alloc_dma = ioc->alloc_dma;
3743 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3744 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3745
3746 for (i = 0; i < ioc->reply_depth; i++) {
3747 /* Write each address to the IOC! */
3748 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3749 alloc_dma += ioc->reply_sz;
3750 }
3751
3752 return 0;
3753
3754out_fail:
3755 if (ioc->alloc != NULL) {
3756 sz = ioc->alloc_sz;
3757 pci_free_consistent(ioc->pcidev,
3758 sz,
3759 ioc->alloc, ioc->alloc_dma);
3760 ioc->reply_frames = NULL;
3761 ioc->req_frames = NULL;
3762 ioc->alloc_total -= sz;
3763 }
3764 if (ioc->sense_buf_pool != NULL) {
3765 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3766 pci_free_consistent(ioc->pcidev,
3767 sz,
3768 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3769 ioc->sense_buf_pool = NULL;
3770 }
3771 return -1;
3772}
3773
3774/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3775/**
3776 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3777 * from IOC via doorbell handshake method.
3778 * @ioc: Pointer to MPT_ADAPTER structure
3779 * @reqBytes: Size of the request in bytes
3780 * @req: Pointer to MPT request frame
3781 * @replyBytes: Expected size of the reply in bytes
3782 * @u16reply: Pointer to area where reply should be written
3783 * @maxwait: Max wait time for a reply (in seconds)
3784 * @sleepFlag: Specifies whether the process can sleep
3785 *
3786 * NOTES: It is the callers responsibility to byte-swap fields in the
3787 * request which are greater than 1 byte in size. It is also the
3788 * callers responsibility to byte-swap response fields which are
3789 * greater than 1 byte in size.
3790 *
3791 * Returns 0 for success, non-zero for failure.
3792 */
3793static int
3794mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003795 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796{
3797 MPIDefaultReply_t *mptReply;
3798 int failcnt = 0;
3799 int t;
3800
3801 /*
3802 * Get ready to cache a handshake reply
3803 */
3804 ioc->hs_reply_idx = 0;
3805 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3806 mptReply->MsgLength = 0;
3807
3808 /*
3809 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3810 * then tell IOC that we want to handshake a request of N words.
3811 * (WRITE u32val to Doorbell reg).
3812 */
3813 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3814 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3815 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3816 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3817
3818 /*
3819 * Wait for IOC's doorbell handshake int
3820 */
3821 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3822 failcnt++;
3823
3824 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3825 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3826
3827 /* Read doorbell and check for active bit */
3828 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3829 return -1;
3830
3831 /*
3832 * Clear doorbell int (WRITE 0 to IntStatus reg),
3833 * then wait for IOC to ACKnowledge that it's ready for
3834 * our handshake request.
3835 */
3836 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3837 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3838 failcnt++;
3839
3840 if (!failcnt) {
3841 int ii;
3842 u8 *req_as_bytes = (u8 *) req;
3843
3844 /*
3845 * Stuff request words via doorbell handshake,
3846 * with ACK from IOC for each.
3847 */
3848 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3849 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3850 (req_as_bytes[(ii*4) + 1] << 8) |
3851 (req_as_bytes[(ii*4) + 2] << 16) |
3852 (req_as_bytes[(ii*4) + 3] << 24));
3853
3854 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3855 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3856 failcnt++;
3857 }
3858
3859 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3860 DBG_DUMP_REQUEST_FRAME_HDR(req)
3861
3862 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3863 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3864
3865 /*
3866 * Wait for completion of doorbell handshake reply from the IOC
3867 */
3868 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3869 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003870
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3872 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3873
3874 /*
3875 * Copy out the cached reply...
3876 */
3877 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3878 u16reply[ii] = ioc->hs_reply[ii];
3879 } else {
3880 return -99;
3881 }
3882
3883 return -failcnt;
3884}
3885
3886/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3887/*
3888 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3889 * in it's IntStatus register.
3890 * @ioc: Pointer to MPT_ADAPTER structure
3891 * @howlong: How long to wait (in seconds)
3892 * @sleepFlag: Specifies whether the process can sleep
3893 *
3894 * This routine waits (up to ~2 seconds max) for IOC doorbell
3895 * handshake ACKnowledge.
3896 *
3897 * Returns a negative value on failure, else wait loop count.
3898 */
3899static int
3900WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3901{
3902 int cntdn;
3903 int count = 0;
3904 u32 intstat=0;
3905
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003906 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
3908 if (sleepFlag == CAN_SLEEP) {
3909 while (--cntdn) {
3910 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3911 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3912 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05003913 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 count++;
3915 }
3916 } else {
3917 while (--cntdn) {
3918 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3919 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3920 break;
3921 mdelay (1);
3922 count++;
3923 }
3924 }
3925
3926 if (cntdn) {
3927 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3928 ioc->name, count));
3929 return count;
3930 }
3931
3932 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3933 ioc->name, count, intstat);
3934 return -1;
3935}
3936
3937/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3938/*
3939 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3940 * in it's IntStatus register.
3941 * @ioc: Pointer to MPT_ADAPTER structure
3942 * @howlong: How long to wait (in seconds)
3943 * @sleepFlag: Specifies whether the process can sleep
3944 *
3945 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3946 *
3947 * Returns a negative value on failure, else wait loop count.
3948 */
3949static int
3950WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3951{
3952 int cntdn;
3953 int count = 0;
3954 u32 intstat=0;
3955
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003956 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 if (sleepFlag == CAN_SLEEP) {
3958 while (--cntdn) {
3959 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3960 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3961 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05003962 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 count++;
3964 }
3965 } else {
3966 while (--cntdn) {
3967 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3968 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3969 break;
3970 mdelay(1);
3971 count++;
3972 }
3973 }
3974
3975 if (cntdn) {
3976 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3977 ioc->name, count, howlong));
3978 return count;
3979 }
3980
3981 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3982 ioc->name, count, intstat);
3983 return -1;
3984}
3985
3986/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3987/*
3988 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3989 * @ioc: Pointer to MPT_ADAPTER structure
3990 * @howlong: How long to wait (in seconds)
3991 * @sleepFlag: Specifies whether the process can sleep
3992 *
3993 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3994 * Reply is cached to IOC private area large enough to hold a maximum
3995 * of 128 bytes of reply data.
3996 *
3997 * Returns a negative value on failure, else size of reply in WORDS.
3998 */
3999static int
4000WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4001{
4002 int u16cnt = 0;
4003 int failcnt = 0;
4004 int t;
4005 u16 *hs_reply = ioc->hs_reply;
4006 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4007 u16 hword;
4008
4009 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4010
4011 /*
4012 * Get first two u16's so we can look at IOC's intended reply MsgLength
4013 */
4014 u16cnt=0;
4015 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4016 failcnt++;
4017 } else {
4018 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4019 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4020 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4021 failcnt++;
4022 else {
4023 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4024 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4025 }
4026 }
4027
4028 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004029 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4031
4032 /*
4033 * If no error (and IOC said MsgLength is > 0), piece together
4034 * reply 16 bits at a time.
4035 */
4036 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4037 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4038 failcnt++;
4039 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4040 /* don't overflow our IOC hs_reply[] buffer! */
4041 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4042 hs_reply[u16cnt] = hword;
4043 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4044 }
4045
4046 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4047 failcnt++;
4048 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4049
4050 if (failcnt) {
4051 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4052 ioc->name);
4053 return -failcnt;
4054 }
4055#if 0
4056 else if (u16cnt != (2 * mptReply->MsgLength)) {
4057 return -101;
4058 }
4059 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4060 return -102;
4061 }
4062#endif
4063
4064 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4065 DBG_DUMP_REPLY_FRAME(mptReply)
4066
4067 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4068 ioc->name, t, u16cnt/2));
4069 return u16cnt/2;
4070}
4071
4072/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4073/*
4074 * GetLanConfigPages - Fetch LANConfig pages.
4075 * @ioc: Pointer to MPT_ADAPTER structure
4076 *
4077 * Return: 0 for success
4078 * -ENOMEM if no memory available
4079 * -EPERM if not allowed due to ISR context
4080 * -EAGAIN if no msg frames currently available
4081 * -EFAULT for non-successful reply or no reply (timeout)
4082 */
4083static int
4084GetLanConfigPages(MPT_ADAPTER *ioc)
4085{
4086 ConfigPageHeader_t hdr;
4087 CONFIGPARMS cfg;
4088 LANPage0_t *ppage0_alloc;
4089 dma_addr_t page0_dma;
4090 LANPage1_t *ppage1_alloc;
4091 dma_addr_t page1_dma;
4092 int rc = 0;
4093 int data_sz;
4094 int copy_sz;
4095
4096 /* Get LAN Page 0 header */
4097 hdr.PageVersion = 0;
4098 hdr.PageLength = 0;
4099 hdr.PageNumber = 0;
4100 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004101 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 cfg.physAddr = -1;
4103 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4104 cfg.dir = 0;
4105 cfg.pageAddr = 0;
4106 cfg.timeout = 0;
4107
4108 if ((rc = mpt_config(ioc, &cfg)) != 0)
4109 return rc;
4110
4111 if (hdr.PageLength > 0) {
4112 data_sz = hdr.PageLength * 4;
4113 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4114 rc = -ENOMEM;
4115 if (ppage0_alloc) {
4116 memset((u8 *)ppage0_alloc, 0, data_sz);
4117 cfg.physAddr = page0_dma;
4118 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4119
4120 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4121 /* save the data */
4122 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4123 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4124
4125 }
4126
4127 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4128
4129 /* FIXME!
4130 * Normalize endianness of structure data,
4131 * by byte-swapping all > 1 byte fields!
4132 */
4133
4134 }
4135
4136 if (rc)
4137 return rc;
4138 }
4139
4140 /* Get LAN Page 1 header */
4141 hdr.PageVersion = 0;
4142 hdr.PageLength = 0;
4143 hdr.PageNumber = 1;
4144 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004145 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 cfg.physAddr = -1;
4147 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4148 cfg.dir = 0;
4149 cfg.pageAddr = 0;
4150
4151 if ((rc = mpt_config(ioc, &cfg)) != 0)
4152 return rc;
4153
4154 if (hdr.PageLength == 0)
4155 return 0;
4156
4157 data_sz = hdr.PageLength * 4;
4158 rc = -ENOMEM;
4159 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4160 if (ppage1_alloc) {
4161 memset((u8 *)ppage1_alloc, 0, data_sz);
4162 cfg.physAddr = page1_dma;
4163 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4164
4165 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4166 /* save the data */
4167 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4168 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4169 }
4170
4171 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4172
4173 /* FIXME!
4174 * Normalize endianness of structure data,
4175 * by byte-swapping all > 1 byte fields!
4176 */
4177
4178 }
4179
4180 return rc;
4181}
4182
4183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4184/*
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004185 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4186 * @ioc: Pointer to MPT_ADAPTER structure
4187 * @sas_address: 64bit SAS Address for operation.
4188 * @target_id: specified target for operation
4189 * @bus: specified bus for operation
4190 * @persist_opcode: see below
4191 *
4192 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4193 * devices not currently present.
4194 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4195 *
4196 * NOTE: Don't use not this function during interrupt time.
4197 *
4198 * Returns: 0 for success, non-zero error
4199 */
4200
4201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4202int
4203mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4204{
4205 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4206 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4207 MPT_FRAME_HDR *mf = NULL;
4208 MPIHeader_t *mpi_hdr;
4209
4210
4211 /* insure garbage is not sent to fw */
4212 switch(persist_opcode) {
4213
4214 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4215 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4216 break;
4217
4218 default:
4219 return -1;
4220 break;
4221 }
4222
4223 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4224
4225 /* Get a MF for this command.
4226 */
4227 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4228 printk("%s: no msg frames!\n",__FUNCTION__);
4229 return -1;
4230 }
4231
4232 mpi_hdr = (MPIHeader_t *) mf;
4233 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4234 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4235 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4236 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4237 sasIoUnitCntrReq->Operation = persist_opcode;
4238
4239 init_timer(&ioc->persist_timer);
4240 ioc->persist_timer.data = (unsigned long) ioc;
4241 ioc->persist_timer.function = mpt_timer_expired;
4242 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4243 ioc->persist_wait_done=0;
4244 add_timer(&ioc->persist_timer);
4245 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4246 wait_event(mpt_waitq, ioc->persist_wait_done);
4247
4248 sasIoUnitCntrReply =
4249 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4250 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4251 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4252 __FUNCTION__,
4253 sasIoUnitCntrReply->IOCStatus,
4254 sasIoUnitCntrReply->IOCLogInfo);
4255 return -1;
4256 }
4257
4258 printk("%s: success\n",__FUNCTION__);
4259 return 0;
4260}
4261
4262/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004263
4264static void
4265mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4266 MpiEventDataRaid_t * pRaidEventData)
4267{
4268 int volume;
4269 int reason;
4270 int disk;
4271 int status;
4272 int flags;
4273 int state;
4274
4275 volume = pRaidEventData->VolumeID;
4276 reason = pRaidEventData->ReasonCode;
4277 disk = pRaidEventData->PhysDiskNum;
4278 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4279 flags = (status >> 0) & 0xff;
4280 state = (status >> 8) & 0xff;
4281
4282 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4283 return;
4284 }
4285
4286 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4287 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4288 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4289 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4290 ioc->name, disk);
4291 } else {
4292 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4293 ioc->name, volume);
4294 }
4295
4296 switch(reason) {
4297 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4298 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4299 ioc->name);
4300 break;
4301
4302 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4303
4304 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4305 ioc->name);
4306 break;
4307
4308 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4309 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4310 ioc->name);
4311 break;
4312
4313 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4314 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4315 ioc->name,
4316 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4317 ? "optimal"
4318 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4319 ? "degraded"
4320 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4321 ? "failed"
4322 : "state unknown",
4323 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4324 ? ", enabled" : "",
4325 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4326 ? ", quiesced" : "",
4327 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4328 ? ", resync in progress" : "" );
4329 break;
4330
4331 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4332 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4333 ioc->name, disk);
4334 break;
4335
4336 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4337 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4338 ioc->name);
4339 break;
4340
4341 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4342 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4343 ioc->name);
4344 break;
4345
4346 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4347 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4348 ioc->name);
4349 break;
4350
4351 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4352 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4353 ioc->name,
4354 state == MPI_PHYSDISK0_STATUS_ONLINE
4355 ? "online"
4356 : state == MPI_PHYSDISK0_STATUS_MISSING
4357 ? "missing"
4358 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4359 ? "not compatible"
4360 : state == MPI_PHYSDISK0_STATUS_FAILED
4361 ? "failed"
4362 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4363 ? "initializing"
4364 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4365 ? "offline requested"
4366 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4367 ? "failed requested"
4368 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4369 ? "offline"
4370 : "state unknown",
4371 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4372 ? ", out of sync" : "",
4373 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4374 ? ", quiesced" : "" );
4375 break;
4376
4377 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4378 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4379 ioc->name, disk);
4380 break;
4381
4382 case MPI_EVENT_RAID_RC_SMART_DATA:
4383 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4384 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4385 break;
4386
4387 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4388 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4389 ioc->name, disk);
4390 break;
4391 }
4392}
4393
4394/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004395/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4397 * @ioc: Pointer to MPT_ADAPTER structure
4398 *
4399 * Returns: 0 for success
4400 * -ENOMEM if no memory available
4401 * -EPERM if not allowed due to ISR context
4402 * -EAGAIN if no msg frames currently available
4403 * -EFAULT for non-successful reply or no reply (timeout)
4404 */
4405static int
4406GetIoUnitPage2(MPT_ADAPTER *ioc)
4407{
4408 ConfigPageHeader_t hdr;
4409 CONFIGPARMS cfg;
4410 IOUnitPage2_t *ppage_alloc;
4411 dma_addr_t page_dma;
4412 int data_sz;
4413 int rc;
4414
4415 /* Get the page header */
4416 hdr.PageVersion = 0;
4417 hdr.PageLength = 0;
4418 hdr.PageNumber = 2;
4419 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004420 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 cfg.physAddr = -1;
4422 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4423 cfg.dir = 0;
4424 cfg.pageAddr = 0;
4425 cfg.timeout = 0;
4426
4427 if ((rc = mpt_config(ioc, &cfg)) != 0)
4428 return rc;
4429
4430 if (hdr.PageLength == 0)
4431 return 0;
4432
4433 /* Read the config page */
4434 data_sz = hdr.PageLength * 4;
4435 rc = -ENOMEM;
4436 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4437 if (ppage_alloc) {
4438 memset((u8 *)ppage_alloc, 0, data_sz);
4439 cfg.physAddr = page_dma;
4440 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4441
4442 /* If Good, save data */
4443 if ((rc = mpt_config(ioc, &cfg)) == 0)
4444 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4445
4446 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4447 }
4448
4449 return rc;
4450}
4451
4452/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4453/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4454 * @ioc: Pointer to a Adapter Strucutre
4455 * @portnum: IOC port number
4456 *
4457 * Return: -EFAULT if read of config page header fails
4458 * or if no nvram
4459 * If read of SCSI Port Page 0 fails,
4460 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4461 * Adapter settings: async, narrow
4462 * Return 1
4463 * If read of SCSI Port Page 2 fails,
4464 * Adapter settings valid
4465 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4466 * Return 1
4467 * Else
4468 * Both valid
4469 * Return 0
4470 * CHECK - what type of locking mechanisms should be used????
4471 */
4472static int
4473mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4474{
4475 u8 *pbuf;
4476 dma_addr_t buf_dma;
4477 CONFIGPARMS cfg;
4478 ConfigPageHeader_t header;
4479 int ii;
4480 int data, rc = 0;
4481
4482 /* Allocate memory
4483 */
4484 if (!ioc->spi_data.nvram) {
4485 int sz;
4486 u8 *mem;
4487 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4488 mem = kmalloc(sz, GFP_ATOMIC);
4489 if (mem == NULL)
4490 return -EFAULT;
4491
4492 ioc->spi_data.nvram = (int *) mem;
4493
4494 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4495 ioc->name, ioc->spi_data.nvram, sz));
4496 }
4497
4498 /* Invalidate NVRAM information
4499 */
4500 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4501 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4502 }
4503
4504 /* Read SPP0 header, allocate memory, then read page.
4505 */
4506 header.PageVersion = 0;
4507 header.PageLength = 0;
4508 header.PageNumber = 0;
4509 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004510 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 cfg.physAddr = -1;
4512 cfg.pageAddr = portnum;
4513 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4514 cfg.dir = 0;
4515 cfg.timeout = 0; /* use default */
4516 if (mpt_config(ioc, &cfg) != 0)
4517 return -EFAULT;
4518
4519 if (header.PageLength > 0) {
4520 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4521 if (pbuf) {
4522 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4523 cfg.physAddr = buf_dma;
4524 if (mpt_config(ioc, &cfg) != 0) {
4525 ioc->spi_data.maxBusWidth = MPT_NARROW;
4526 ioc->spi_data.maxSyncOffset = 0;
4527 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4528 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4529 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004530 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4531 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 } else {
4533 /* Save the Port Page 0 data
4534 */
4535 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4536 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4537 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4538
4539 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4540 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004541 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 ioc->name, pPP0->Capabilities));
4543 }
4544 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4545 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4546 if (data) {
4547 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4548 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4549 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004550 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4551 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 } else {
4553 ioc->spi_data.maxSyncOffset = 0;
4554 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4555 }
4556
4557 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4558
4559 /* Update the minSyncFactor based on bus type.
4560 */
4561 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4562 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4563
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004564 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004566 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4567 ioc->name, ioc->spi_data.minSyncFactor));
4568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 }
4570 }
4571 if (pbuf) {
4572 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4573 }
4574 }
4575 }
4576
4577 /* SCSI Port Page 2 - Read the header then the page.
4578 */
4579 header.PageVersion = 0;
4580 header.PageLength = 0;
4581 header.PageNumber = 2;
4582 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004583 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 cfg.physAddr = -1;
4585 cfg.pageAddr = portnum;
4586 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4587 cfg.dir = 0;
4588 if (mpt_config(ioc, &cfg) != 0)
4589 return -EFAULT;
4590
4591 if (header.PageLength > 0) {
4592 /* Allocate memory and read SCSI Port Page 2
4593 */
4594 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4595 if (pbuf) {
4596 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4597 cfg.physAddr = buf_dma;
4598 if (mpt_config(ioc, &cfg) != 0) {
4599 /* Nvram data is left with INVALID mark
4600 */
4601 rc = 1;
4602 } else {
4603 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4604 MpiDeviceInfo_t *pdevice = NULL;
4605
Moore, Ericd8e925d2006-01-16 18:53:06 -07004606 /*
4607 * Save "Set to Avoid SCSI Bus Resets" flag
4608 */
4609 ioc->spi_data.bus_reset =
4610 (le32_to_cpu(pPP2->PortFlags) &
4611 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4612 0 : 1 ;
4613
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 /* Save the Port Page 2 data
4615 * (reformat into a 32bit quantity)
4616 */
4617 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4618 ioc->spi_data.PortFlags = data;
4619 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4620 pdevice = &pPP2->DeviceSettings[ii];
4621 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4622 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4623 ioc->spi_data.nvram[ii] = data;
4624 }
4625 }
4626
4627 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4628 }
4629 }
4630
4631 /* Update Adapter limits with those from NVRAM
4632 * Comment: Don't need to do this. Target performance
4633 * parameters will never exceed the adapters limits.
4634 */
4635
4636 return rc;
4637}
4638
4639/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4640/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4641 * @ioc: Pointer to a Adapter Strucutre
4642 * @portnum: IOC port number
4643 *
4644 * Return: -EFAULT if read of config page header fails
4645 * or 0 if success.
4646 */
4647static int
4648mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4649{
4650 CONFIGPARMS cfg;
4651 ConfigPageHeader_t header;
4652
4653 /* Read the SCSI Device Page 1 header
4654 */
4655 header.PageVersion = 0;
4656 header.PageLength = 0;
4657 header.PageNumber = 1;
4658 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004659 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 cfg.physAddr = -1;
4661 cfg.pageAddr = portnum;
4662 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4663 cfg.dir = 0;
4664 cfg.timeout = 0;
4665 if (mpt_config(ioc, &cfg) != 0)
4666 return -EFAULT;
4667
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004668 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4669 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670
4671 header.PageVersion = 0;
4672 header.PageLength = 0;
4673 header.PageNumber = 0;
4674 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4675 if (mpt_config(ioc, &cfg) != 0)
4676 return -EFAULT;
4677
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004678 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4679 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680
4681 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4682 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4683
4684 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4685 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4686 return 0;
4687}
4688
4689/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4690/**
4691 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4692 * @ioc: Pointer to a Adapter Strucutre
4693 * @portnum: IOC port number
4694 *
4695 * Return:
4696 * 0 on success
4697 * -EFAULT if read of config page header fails or data pointer not NULL
4698 * -ENOMEM if pci_alloc failed
4699 */
4700int
4701mpt_findImVolumes(MPT_ADAPTER *ioc)
4702{
4703 IOCPage2_t *pIoc2;
4704 u8 *mem;
4705 ConfigPageIoc2RaidVol_t *pIocRv;
4706 dma_addr_t ioc2_dma;
4707 CONFIGPARMS cfg;
4708 ConfigPageHeader_t header;
4709 int jj;
4710 int rc = 0;
4711 int iocpage2sz;
4712 u8 nVols, nPhys;
4713 u8 vid, vbus, vioc;
4714
4715 /* Read IOCP2 header then the page.
4716 */
4717 header.PageVersion = 0;
4718 header.PageLength = 0;
4719 header.PageNumber = 2;
4720 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004721 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 cfg.physAddr = -1;
4723 cfg.pageAddr = 0;
4724 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4725 cfg.dir = 0;
4726 cfg.timeout = 0;
4727 if (mpt_config(ioc, &cfg) != 0)
4728 return -EFAULT;
4729
4730 if (header.PageLength == 0)
4731 return -EFAULT;
4732
4733 iocpage2sz = header.PageLength * 4;
4734 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4735 if (!pIoc2)
4736 return -ENOMEM;
4737
4738 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4739 cfg.physAddr = ioc2_dma;
4740 if (mpt_config(ioc, &cfg) != 0)
4741 goto done_and_free;
4742
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004743 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4745 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004746 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 } else {
4748 goto done_and_free;
4749 }
4750 }
4751 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4752
4753 /* Identify RAID Volume Id's */
4754 nVols = pIoc2->NumActiveVolumes;
4755 if ( nVols == 0) {
4756 /* No RAID Volume.
4757 */
4758 goto done_and_free;
4759 } else {
4760 /* At least 1 RAID Volume
4761 */
4762 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004763 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4765 vid = pIocRv->VolumeID;
4766 vbus = pIocRv->VolumeBus;
4767 vioc = pIocRv->VolumeIOC;
4768
4769 /* find the match
4770 */
4771 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004772 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 } else {
4774 /* Error! Always bus 0
4775 */
4776 }
4777 }
4778 }
4779
4780 /* Identify Hidden Physical Disk Id's */
4781 nPhys = pIoc2->NumActivePhysDisks;
4782 if (nPhys == 0) {
4783 /* No physical disks.
4784 */
4785 } else {
4786 mpt_read_ioc_pg_3(ioc);
4787 }
4788
4789done_and_free:
4790 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4791
4792 return rc;
4793}
4794
Moore, Ericc972c702006-03-14 09:14:06 -07004795static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4797{
4798 IOCPage3_t *pIoc3;
4799 u8 *mem;
4800 CONFIGPARMS cfg;
4801 ConfigPageHeader_t header;
4802 dma_addr_t ioc3_dma;
4803 int iocpage3sz = 0;
4804
4805 /* Free the old page
4806 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004807 kfree(ioc->raid_data.pIocPg3);
4808 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809
4810 /* There is at least one physical disk.
4811 * Read and save IOC Page 3
4812 */
4813 header.PageVersion = 0;
4814 header.PageLength = 0;
4815 header.PageNumber = 3;
4816 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004817 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 cfg.physAddr = -1;
4819 cfg.pageAddr = 0;
4820 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4821 cfg.dir = 0;
4822 cfg.timeout = 0;
4823 if (mpt_config(ioc, &cfg) != 0)
4824 return 0;
4825
4826 if (header.PageLength == 0)
4827 return 0;
4828
4829 /* Read Header good, alloc memory
4830 */
4831 iocpage3sz = header.PageLength * 4;
4832 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4833 if (!pIoc3)
4834 return 0;
4835
4836 /* Read the Page and save the data
4837 * into malloc'd memory.
4838 */
4839 cfg.physAddr = ioc3_dma;
4840 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4841 if (mpt_config(ioc, &cfg) == 0) {
4842 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4843 if (mem) {
4844 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004845 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 }
4847 }
4848
4849 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4850
4851 return 0;
4852}
4853
4854static void
4855mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4856{
4857 IOCPage4_t *pIoc4;
4858 CONFIGPARMS cfg;
4859 ConfigPageHeader_t header;
4860 dma_addr_t ioc4_dma;
4861 int iocpage4sz;
4862
4863 /* Read and save IOC Page 4
4864 */
4865 header.PageVersion = 0;
4866 header.PageLength = 0;
4867 header.PageNumber = 4;
4868 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004869 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 cfg.physAddr = -1;
4871 cfg.pageAddr = 0;
4872 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4873 cfg.dir = 0;
4874 cfg.timeout = 0;
4875 if (mpt_config(ioc, &cfg) != 0)
4876 return;
4877
4878 if (header.PageLength == 0)
4879 return;
4880
4881 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4882 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4883 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4884 if (!pIoc4)
4885 return;
4886 } else {
4887 ioc4_dma = ioc->spi_data.IocPg4_dma;
4888 iocpage4sz = ioc->spi_data.IocPg4Sz;
4889 }
4890
4891 /* Read the Page into dma memory.
4892 */
4893 cfg.physAddr = ioc4_dma;
4894 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4895 if (mpt_config(ioc, &cfg) == 0) {
4896 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4897 ioc->spi_data.IocPg4_dma = ioc4_dma;
4898 ioc->spi_data.IocPg4Sz = iocpage4sz;
4899 } else {
4900 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4901 ioc->spi_data.pIocPg4 = NULL;
4902 }
4903}
4904
4905static void
4906mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4907{
4908 IOCPage1_t *pIoc1;
4909 CONFIGPARMS cfg;
4910 ConfigPageHeader_t header;
4911 dma_addr_t ioc1_dma;
4912 int iocpage1sz = 0;
4913 u32 tmp;
4914
4915 /* Check the Coalescing Timeout in IOC Page 1
4916 */
4917 header.PageVersion = 0;
4918 header.PageLength = 0;
4919 header.PageNumber = 1;
4920 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004921 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 cfg.physAddr = -1;
4923 cfg.pageAddr = 0;
4924 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4925 cfg.dir = 0;
4926 cfg.timeout = 0;
4927 if (mpt_config(ioc, &cfg) != 0)
4928 return;
4929
4930 if (header.PageLength == 0)
4931 return;
4932
4933 /* Read Header good, alloc memory
4934 */
4935 iocpage1sz = header.PageLength * 4;
4936 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
4937 if (!pIoc1)
4938 return;
4939
4940 /* Read the Page and check coalescing timeout
4941 */
4942 cfg.physAddr = ioc1_dma;
4943 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4944 if (mpt_config(ioc, &cfg) == 0) {
4945
4946 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
4947 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
4948 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
4949
4950 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
4951 ioc->name, tmp));
4952
4953 if (tmp > MPT_COALESCING_TIMEOUT) {
4954 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
4955
4956 /* Write NVRAM and current
4957 */
4958 cfg.dir = 1;
4959 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4960 if (mpt_config(ioc, &cfg) == 0) {
4961 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
4962 ioc->name, MPT_COALESCING_TIMEOUT));
4963
4964 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
4965 if (mpt_config(ioc, &cfg) == 0) {
4966 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
4967 ioc->name, MPT_COALESCING_TIMEOUT));
4968 } else {
4969 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
4970 ioc->name));
4971 }
4972
4973 } else {
4974 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
4975 ioc->name));
4976 }
4977 }
4978
4979 } else {
4980 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
4981 }
4982 }
4983
4984 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
4985
4986 return;
4987}
4988
4989/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4990/*
4991 * SendEventNotification - Send EventNotification (on or off) request
4992 * to MPT adapter.
4993 * @ioc: Pointer to MPT_ADAPTER structure
4994 * @EvSwitch: Event switch flags
4995 */
4996static int
4997SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
4998{
4999 EventNotification_t *evnp;
5000
5001 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5002 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005003 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 ioc->name));
5005 return 0;
5006 }
5007 memset(evnp, 0, sizeof(*evnp));
5008
Moore, Eric3a892be2006-03-14 09:14:03 -07005009 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010
5011 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5012 evnp->ChainOffset = 0;
5013 evnp->MsgFlags = 0;
5014 evnp->Switch = EvSwitch;
5015
5016 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5017
5018 return 0;
5019}
5020
5021/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5022/**
5023 * SendEventAck - Send EventAck request to MPT adapter.
5024 * @ioc: Pointer to MPT_ADAPTER structure
5025 * @evnp: Pointer to original EventNotification request
5026 */
5027static int
5028SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5029{
5030 EventAck_t *pAck;
5031
5032 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005033 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5034 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5035 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5036 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 return -1;
5038 }
5039 memset(pAck, 0, sizeof(*pAck));
5040
5041 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5042
5043 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5044 pAck->ChainOffset = 0;
5045 pAck->MsgFlags = 0;
5046 pAck->Event = evnp->Event;
5047 pAck->EventContext = evnp->EventContext;
5048
5049 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5050
5051 return 0;
5052}
5053
5054/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5055/**
5056 * mpt_config - Generic function to issue config message
5057 * @ioc - Pointer to an adapter structure
5058 * @cfg - Pointer to a configuration structure. Struct contains
5059 * action, page address, direction, physical address
5060 * and pointer to a configuration page header
5061 * Page header is updated.
5062 *
5063 * Returns 0 for success
5064 * -EPERM if not allowed due to ISR context
5065 * -EAGAIN if no msg frames currently available
5066 * -EFAULT for non-successful reply or no reply (timeout)
5067 */
5068int
5069mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5070{
5071 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005072 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 MPT_FRAME_HDR *mf;
5074 unsigned long flags;
5075 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005076 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 int in_isr;
5078
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005079 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 * to be in ISR context, because that is fatal!
5081 */
5082 in_isr = in_interrupt();
5083 if (in_isr) {
5084 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5085 ioc->name));
5086 return -EPERM;
5087 }
5088
5089 /* Get and Populate a free Frame
5090 */
5091 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5092 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5093 ioc->name));
5094 return -EAGAIN;
5095 }
5096 pReq = (Config_t *)mf;
5097 pReq->Action = pCfg->action;
5098 pReq->Reserved = 0;
5099 pReq->ChainOffset = 0;
5100 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005101
5102 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 pReq->ExtPageLength = 0;
5104 pReq->ExtPageType = 0;
5105 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005106
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 for (ii=0; ii < 8; ii++)
5108 pReq->Reserved2[ii] = 0;
5109
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005110 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5111 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5112 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5113 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5114
5115 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5116 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5117 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5118 pReq->ExtPageType = pExtHdr->ExtPageType;
5119 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5120
5121 /* Page Length must be treated as a reserved field for the extended header. */
5122 pReq->Header.PageLength = 0;
5123 }
5124
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5126
5127 /* Add a SGE to the config request.
5128 */
5129 if (pCfg->dir)
5130 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5131 else
5132 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5133
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005134 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5135 flagsLength |= pExtHdr->ExtPageLength * 4;
5136
5137 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5138 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5139 }
5140 else {
5141 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5142
5143 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5144 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146
5147 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5148
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 /* Append pCfg pointer to end of mf
5150 */
5151 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5152
5153 /* Initalize the timer
5154 */
5155 init_timer(&pCfg->timer);
5156 pCfg->timer.data = (unsigned long) ioc;
5157 pCfg->timer.function = mpt_timer_expired;
5158 pCfg->wait_done = 0;
5159
5160 /* Set the timer; ensure 10 second minimum */
5161 if (pCfg->timeout < 10)
5162 pCfg->timer.expires = jiffies + HZ*10;
5163 else
5164 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5165
5166 /* Add to end of Q, set timer and then issue this command */
5167 spin_lock_irqsave(&ioc->FreeQlock, flags);
5168 list_add_tail(&pCfg->linkage, &ioc->configQ);
5169 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5170
5171 add_timer(&pCfg->timer);
5172 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5173 wait_event(mpt_waitq, pCfg->wait_done);
5174
5175 /* mf has been freed - do not access */
5176
5177 rc = pCfg->status;
5178
5179 return rc;
5180}
5181
5182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183/*
5184 * mpt_timer_expired - Call back for timer process.
5185 * Used only internal config functionality.
5186 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5187 */
5188static void
5189mpt_timer_expired(unsigned long data)
5190{
5191 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5192
5193 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5194
5195 /* Perform a FW reload */
5196 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5197 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5198
5199 /* No more processing.
5200 * Hard reset clean-up will wake up
5201 * process and free all resources.
5202 */
5203 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5204
5205 return;
5206}
5207
5208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5209/*
5210 * mpt_ioc_reset - Base cleanup for hard reset
5211 * @ioc: Pointer to the adapter structure
5212 * @reset_phase: Indicates pre- or post-reset functionality
5213 *
5214 * Remark: Free's resources with internally generated commands.
5215 */
5216static int
5217mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5218{
5219 CONFIGPARMS *pCfg;
5220 unsigned long flags;
5221
5222 dprintk((KERN_WARNING MYNAM
5223 ": IOC %s_reset routed to MPT base driver!\n",
5224 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5225 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5226
5227 if (reset_phase == MPT_IOC_SETUP_RESET) {
5228 ;
5229 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5230 /* If the internal config Q is not empty -
5231 * delete timer. MF resources will be freed when
5232 * the FIFO's are primed.
5233 */
5234 spin_lock_irqsave(&ioc->FreeQlock, flags);
5235 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5236 del_timer(&pCfg->timer);
5237 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5238
5239 } else {
5240 CONFIGPARMS *pNext;
5241
5242 /* Search the configQ for internal commands.
5243 * Flush the Q, and wake up all suspended threads.
5244 */
5245 spin_lock_irqsave(&ioc->FreeQlock, flags);
5246 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5247 list_del(&pCfg->linkage);
5248
5249 pCfg->status = MPT_CONFIG_ERROR;
5250 pCfg->wait_done = 1;
5251 wake_up(&mpt_waitq);
5252 }
5253 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5254 }
5255
5256 return 1; /* currently means nothing really */
5257}
5258
5259
5260#ifdef CONFIG_PROC_FS /* { */
5261/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5262/*
5263 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5264 */
5265/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5266/*
5267 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5268 *
5269 * Returns 0 for success, non-zero for failure.
5270 */
5271static int
5272procmpt_create(void)
5273{
5274 struct proc_dir_entry *ent;
5275
5276 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5277 if (mpt_proc_root_dir == NULL)
5278 return -ENOTDIR;
5279
5280 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5281 if (ent)
5282 ent->read_proc = procmpt_summary_read;
5283
5284 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5285 if (ent)
5286 ent->read_proc = procmpt_version_read;
5287
5288 return 0;
5289}
5290
5291/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5292/*
5293 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5294 *
5295 * Returns 0 for success, non-zero for failure.
5296 */
5297static void
5298procmpt_destroy(void)
5299{
5300 remove_proc_entry("version", mpt_proc_root_dir);
5301 remove_proc_entry("summary", mpt_proc_root_dir);
5302 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5303}
5304
5305/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5306/*
5307 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5308 * or from /proc/mpt/iocN/summary.
5309 * @buf: Pointer to area to write information
5310 * @start: Pointer to start pointer
5311 * @offset: Offset to start writing
5312 * @request:
5313 * @eof: Pointer to EOF integer
5314 * @data: Pointer
5315 *
5316 * Returns number of characters written to process performing the read.
5317 */
5318static int
5319procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5320{
5321 MPT_ADAPTER *ioc;
5322 char *out = buf;
5323 int len;
5324
5325 if (data) {
5326 int more = 0;
5327
5328 ioc = data;
5329 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5330
5331 out += more;
5332 } else {
5333 list_for_each_entry(ioc, &ioc_list, list) {
5334 int more = 0;
5335
5336 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5337
5338 out += more;
5339 if ((out-buf) >= request)
5340 break;
5341 }
5342 }
5343
5344 len = out - buf;
5345
5346 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5347}
5348
5349/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5350/*
5351 * procmpt_version_read - Handle read request from /proc/mpt/version.
5352 * @buf: Pointer to area to write information
5353 * @start: Pointer to start pointer
5354 * @offset: Offset to start writing
5355 * @request:
5356 * @eof: Pointer to EOF integer
5357 * @data: Pointer
5358 *
5359 * Returns number of characters written to process performing the read.
5360 */
5361static int
5362procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5363{
5364 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005365 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 char *drvname;
5367 int len;
5368
5369 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5370 len += sprintf(buf+len, " Fusion MPT base driver\n");
5371
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005372 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5374 drvname = NULL;
5375 if (MptCallbacks[ii]) {
5376 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005377 case MPTSPI_DRIVER:
5378 if (!scsi++) drvname = "SPI host";
5379 break;
5380 case MPTFC_DRIVER:
5381 if (!fc++) drvname = "FC host";
5382 break;
5383 case MPTSAS_DRIVER:
5384 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 break;
5386 case MPTLAN_DRIVER:
5387 if (!lan++) drvname = "LAN";
5388 break;
5389 case MPTSTM_DRIVER:
5390 if (!targ++) drvname = "SCSI target";
5391 break;
5392 case MPTCTL_DRIVER:
5393 if (!ctl++) drvname = "ioctl";
5394 break;
5395 }
5396
5397 if (drvname)
5398 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5399 }
5400 }
5401
5402 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5403}
5404
5405/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5406/*
5407 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5408 * @buf: Pointer to area to write information
5409 * @start: Pointer to start pointer
5410 * @offset: Offset to start writing
5411 * @request:
5412 * @eof: Pointer to EOF integer
5413 * @data: Pointer
5414 *
5415 * Returns number of characters written to process performing the read.
5416 */
5417static int
5418procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5419{
5420 MPT_ADAPTER *ioc = data;
5421 int len;
5422 char expVer[32];
5423 int sz;
5424 int p;
5425
5426 mpt_get_fw_exp_ver(expVer, ioc);
5427
5428 len = sprintf(buf, "%s:", ioc->name);
5429 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5430 len += sprintf(buf+len, " (f/w download boot flag set)");
5431// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5432// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5433
5434 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5435 ioc->facts.ProductID,
5436 ioc->prod_name);
5437 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5438 if (ioc->facts.FWImageSize)
5439 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5440 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5441 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5442 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5443
5444 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5445 ioc->facts.CurrentHostMfaHighAddr);
5446 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5447 ioc->facts.CurrentSenseBufferHighAddr);
5448
5449 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5450 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5451
5452 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5453 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5454 /*
5455 * Rounding UP to nearest 4-kB boundary here...
5456 */
5457 sz = (ioc->req_sz * ioc->req_depth) + 128;
5458 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5459 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5460 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5461 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5462 4*ioc->facts.RequestFrameSize,
5463 ioc->facts.GlobalCredits);
5464
5465 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5466 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5467 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5468 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5469 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5470 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5471 ioc->facts.CurReplyFrameSize,
5472 ioc->facts.ReplyQueueDepth);
5473
5474 len += sprintf(buf+len, " MaxDevices = %d\n",
5475 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5476 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5477
5478 /* per-port info */
5479 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5480 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5481 p+1,
5482 ioc->facts.NumberOfPorts);
5483 if (ioc->bus_type == FC) {
5484 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5485 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5486 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5487 a[5], a[4], a[3], a[2], a[1], a[0]);
5488 }
5489 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5490 ioc->fc_port_page0[p].WWNN.High,
5491 ioc->fc_port_page0[p].WWNN.Low,
5492 ioc->fc_port_page0[p].WWPN.High,
5493 ioc->fc_port_page0[p].WWPN.Low);
5494 }
5495 }
5496
5497 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5498}
5499
5500#endif /* CONFIG_PROC_FS } */
5501
5502/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5503static void
5504mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5505{
5506 buf[0] ='\0';
5507 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5508 sprintf(buf, " (Exp %02d%02d)",
5509 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5510 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5511
5512 /* insider hack! */
5513 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5514 strcat(buf, " [MDBG]");
5515 }
5516}
5517
5518/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5519/**
5520 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5521 * @ioc: Pointer to MPT_ADAPTER structure
5522 * @buffer: Pointer to buffer where IOC summary info should be written
5523 * @size: Pointer to number of bytes we wrote (set by this routine)
5524 * @len: Offset at which to start writing in buffer
5525 * @showlan: Display LAN stuff?
5526 *
5527 * This routine writes (english readable) ASCII text, which represents
5528 * a summary of IOC information, to a buffer.
5529 */
5530void
5531mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5532{
5533 char expVer[32];
5534 int y;
5535
5536 mpt_get_fw_exp_ver(expVer, ioc);
5537
5538 /*
5539 * Shorter summary of attached ioc's...
5540 */
5541 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5542 ioc->name,
5543 ioc->prod_name,
5544 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5545 ioc->facts.FWVersion.Word,
5546 expVer,
5547 ioc->facts.NumberOfPorts,
5548 ioc->req_depth);
5549
5550 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5551 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5552 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5553 a[5], a[4], a[3], a[2], a[1], a[0]);
5554 }
5555
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557
5558 if (!ioc->active)
5559 y += sprintf(buffer+len+y, " (disabled)");
5560
5561 y += sprintf(buffer+len+y, "\n");
5562
5563 *size = y;
5564}
5565
5566/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5567/*
5568 * Reset Handling
5569 */
5570/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5571/**
5572 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5573 * Management call based on input arg values. If TaskMgmt fails,
5574 * return associated SCSI request.
5575 * @ioc: Pointer to MPT_ADAPTER structure
5576 * @sleepFlag: Indicates if sleep or schedule must be called.
5577 *
5578 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5579 * or a non-interrupt thread. In the former, must not call schedule().
5580 *
5581 * Remark: A return of -1 is a FATAL error case, as it means a
5582 * FW reload/initialization failed.
5583 *
5584 * Returns 0 for SUCCESS or -1 if FAILED.
5585 */
5586int
5587mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5588{
5589 int rc;
5590 unsigned long flags;
5591
5592 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5593#ifdef MFCNT
5594 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5595 printk("MF count 0x%x !\n", ioc->mfcnt);
5596#endif
5597
5598 /* Reset the adapter. Prevent more than 1 call to
5599 * mpt_do_ioc_recovery at any instant in time.
5600 */
5601 spin_lock_irqsave(&ioc->diagLock, flags);
5602 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5603 spin_unlock_irqrestore(&ioc->diagLock, flags);
5604 return 0;
5605 } else {
5606 ioc->diagPending = 1;
5607 }
5608 spin_unlock_irqrestore(&ioc->diagLock, flags);
5609
5610 /* FIXME: If do_ioc_recovery fails, repeat....
5611 */
5612
5613 /* The SCSI driver needs to adjust timeouts on all current
5614 * commands prior to the diagnostic reset being issued.
5615 * Prevents timeouts occuring during a diagnostic reset...very bad.
5616 * For all other protocol drivers, this is a no-op.
5617 */
5618 {
5619 int ii;
5620 int r = 0;
5621
5622 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5623 if (MptResetHandlers[ii]) {
5624 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5625 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005626 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 if (ioc->alt_ioc) {
5628 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5629 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005630 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 }
5632 }
5633 }
5634 }
5635
5636 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5637 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5638 rc, ioc->name);
5639 }
5640 ioc->reload_fw = 0;
5641 if (ioc->alt_ioc)
5642 ioc->alt_ioc->reload_fw = 0;
5643
5644 spin_lock_irqsave(&ioc->diagLock, flags);
5645 ioc->diagPending = 0;
5646 if (ioc->alt_ioc)
5647 ioc->alt_ioc->diagPending = 0;
5648 spin_unlock_irqrestore(&ioc->diagLock, flags);
5649
5650 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5651
5652 return rc;
5653}
5654
Eric Moore509e5e52006-04-26 13:22:37 -06005655# define EVENT_DESCR_STR_SZ 100
5656
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005658static void
5659EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660{
Eric Moore509e5e52006-04-26 13:22:37 -06005661 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662
5663 switch(event) {
5664 case MPI_EVENT_NONE:
5665 ds = "None";
5666 break;
5667 case MPI_EVENT_LOG_DATA:
5668 ds = "Log Data";
5669 break;
5670 case MPI_EVENT_STATE_CHANGE:
5671 ds = "State Change";
5672 break;
5673 case MPI_EVENT_UNIT_ATTENTION:
5674 ds = "Unit Attention";
5675 break;
5676 case MPI_EVENT_IOC_BUS_RESET:
5677 ds = "IOC Bus Reset";
5678 break;
5679 case MPI_EVENT_EXT_BUS_RESET:
5680 ds = "External Bus Reset";
5681 break;
5682 case MPI_EVENT_RESCAN:
5683 ds = "Bus Rescan Event";
5684 /* Ok, do we need to do anything here? As far as
5685 I can tell, this is when a new device gets added
5686 to the loop. */
5687 break;
5688 case MPI_EVENT_LINK_STATUS_CHANGE:
5689 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5690 ds = "Link Status(FAILURE) Change";
5691 else
5692 ds = "Link Status(ACTIVE) Change";
5693 break;
5694 case MPI_EVENT_LOOP_STATE_CHANGE:
5695 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5696 ds = "Loop State(LIP) Change";
5697 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005698 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699 else
Eric Moore509e5e52006-04-26 13:22:37 -06005700 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701 break;
5702 case MPI_EVENT_LOGOUT:
5703 ds = "Logout";
5704 break;
5705 case MPI_EVENT_EVENT_CHANGE:
5706 if (evData0)
5707 ds = "Events(ON) Change";
5708 else
5709 ds = "Events(OFF) Change";
5710 break;
5711 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005712 {
5713 u8 ReasonCode = (u8)(evData0 >> 16);
5714 switch (ReasonCode) {
5715 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5716 ds = "Integrated Raid: Volume Created";
5717 break;
5718 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5719 ds = "Integrated Raid: Volume Deleted";
5720 break;
5721 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5722 ds = "Integrated Raid: Volume Settings Changed";
5723 break;
5724 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5725 ds = "Integrated Raid: Volume Status Changed";
5726 break;
5727 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5728 ds = "Integrated Raid: Volume Physdisk Changed";
5729 break;
5730 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5731 ds = "Integrated Raid: Physdisk Created";
5732 break;
5733 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5734 ds = "Integrated Raid: Physdisk Deleted";
5735 break;
5736 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5737 ds = "Integrated Raid: Physdisk Settings Changed";
5738 break;
5739 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5740 ds = "Integrated Raid: Physdisk Status Changed";
5741 break;
5742 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5743 ds = "Integrated Raid: Domain Validation Needed";
5744 break;
5745 case MPI_EVENT_RAID_RC_SMART_DATA :
5746 ds = "Integrated Raid; Smart Data";
5747 break;
5748 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5749 ds = "Integrated Raid: Replace Action Started";
5750 break;
5751 default:
5752 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005754 }
5755 break;
5756 }
5757 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5758 ds = "SCSI Device Status Change";
5759 break;
5760 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5761 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005762 u8 id = (u8)(evData0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005763 u8 ReasonCode = (u8)(evData0 >> 16);
5764 switch (ReasonCode) {
5765 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005766 snprintf(evStr, EVENT_DESCR_STR_SZ,
5767 "SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005768 break;
5769 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005770 snprintf(evStr, EVENT_DESCR_STR_SZ,
5771 "SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005772 break;
5773 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005774 snprintf(evStr, EVENT_DESCR_STR_SZ,
5775 "SAS Device Status Change: SMART Data: id=%d",
5776 id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005777 break;
5778 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005779 snprintf(evStr, EVENT_DESCR_STR_SZ,
5780 "SAS Device Status Change: No Persistancy "
5781 "Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005782 break;
5783 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005784 snprintf(evStr, EVENT_DESCR_STR_SZ,
5785 "SAS Device Status Change: Unknown: id=%d", id);
5786 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005787 }
5788 break;
5789 }
5790 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5791 ds = "Bus Timer Expired";
5792 break;
5793 case MPI_EVENT_QUEUE_FULL:
5794 ds = "Queue Full";
5795 break;
5796 case MPI_EVENT_SAS_SES:
5797 ds = "SAS SES Event";
5798 break;
5799 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5800 ds = "Persistent Table Full";
5801 break;
5802 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005803 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005804 u8 LinkRates = (u8)(evData0 >> 8);
5805 u8 PhyNumber = (u8)(evData0);
5806 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5807 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5808 switch (LinkRates) {
5809 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06005810 snprintf(evStr, EVENT_DESCR_STR_SZ,
5811 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005812 " Rate Unknown",PhyNumber);
5813 break;
5814 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06005815 snprintf(evStr, EVENT_DESCR_STR_SZ,
5816 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005817 " Phy Disabled",PhyNumber);
5818 break;
5819 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06005820 snprintf(evStr, EVENT_DESCR_STR_SZ,
5821 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005822 " Failed Speed Nego",PhyNumber);
5823 break;
5824 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06005825 snprintf(evStr, EVENT_DESCR_STR_SZ,
5826 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005827 " Sata OOB Completed",PhyNumber);
5828 break;
5829 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06005830 snprintf(evStr, EVENT_DESCR_STR_SZ,
5831 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005832 " Rate 1.5 Gbps",PhyNumber);
5833 break;
5834 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06005835 snprintf(evStr, EVENT_DESCR_STR_SZ,
5836 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005837 " Rate 3.0 Gpbs",PhyNumber);
5838 break;
5839 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005840 snprintf(evStr, EVENT_DESCR_STR_SZ,
5841 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07005842 break;
5843 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005844 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005845 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005846 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5847 ds = "SAS Discovery Error";
5848 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005849 case MPI_EVENT_IR_RESYNC_UPDATE:
5850 {
5851 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06005852 snprintf(evStr, EVENT_DESCR_STR_SZ,
5853 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07005854 break;
5855 }
5856 case MPI_EVENT_IR2:
5857 {
5858 u8 ReasonCode = (u8)(evData0 >> 16);
5859 switch (ReasonCode) {
5860 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5861 ds = "IR2: LD State Changed";
5862 break;
5863 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5864 ds = "IR2: PD State Changed";
5865 break;
5866 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5867 ds = "IR2: Bad Block Table Full";
5868 break;
5869 case MPI_EVENT_IR2_RC_PD_INSERTED:
5870 ds = "IR2: PD Inserted";
5871 break;
5872 case MPI_EVENT_IR2_RC_PD_REMOVED:
5873 ds = "IR2: PD Removed";
5874 break;
5875 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5876 ds = "IR2: Foreign CFG Detected";
5877 break;
5878 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5879 ds = "IR2: Rebuild Medium Error";
5880 break;
5881 default:
5882 ds = "IR2";
5883 break;
5884 }
5885 break;
5886 }
5887 case MPI_EVENT_SAS_DISCOVERY:
5888 {
5889 if (evData0)
5890 ds = "SAS Discovery: Start";
5891 else
5892 ds = "SAS Discovery: Stop";
5893 break;
5894 }
5895 case MPI_EVENT_LOG_ENTRY_ADDED:
5896 ds = "SAS Log Entry Added";
5897 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005898
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 /*
5900 * MPT base "custom" events may be added here...
5901 */
5902 default:
5903 ds = "Unknown";
5904 break;
5905 }
Eric Moore509e5e52006-04-26 13:22:37 -06005906 if (ds)
5907 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908}
5909
5910/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5911/*
5912 * ProcessEventNotification - Route a received EventNotificationReply to
5913 * all currently regeistered event handlers.
5914 * @ioc: Pointer to MPT_ADAPTER structure
5915 * @pEventReply: Pointer to EventNotification reply frame
5916 * @evHandlers: Pointer to integer, number of event handlers
5917 *
5918 * Returns sum of event handlers return values.
5919 */
5920static int
5921ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5922{
5923 u16 evDataLen;
5924 u32 evData0 = 0;
5925// u32 evCtx;
5926 int ii;
5927 int r = 0;
5928 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06005929 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930 u8 event;
5931
5932 /*
5933 * Do platform normalization of values
5934 */
5935 event = le32_to_cpu(pEventReply->Event) & 0xFF;
5936// evCtx = le32_to_cpu(pEventReply->EventContext);
5937 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
5938 if (evDataLen) {
5939 evData0 = le32_to_cpu(pEventReply->Data[0]);
5940 }
5941
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005942 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07005943 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07005945 event,
5946 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947
Moore, Eric3a892be2006-03-14 09:14:03 -07005948#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
5950 for (ii = 0; ii < evDataLen; ii++)
5951 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
5952 printk("\n");
5953#endif
5954
5955 /*
5956 * Do general / base driver event processing
5957 */
5958 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 case MPI_EVENT_EVENT_CHANGE: /* 0A */
5960 if (evDataLen) {
5961 u8 evState = evData0 & 0xFF;
5962
5963 /* CHECKME! What if evState unexpectedly says OFF (0)? */
5964
5965 /* Update EventState field in cached IocFacts */
5966 if (ioc->facts.Function) {
5967 ioc->facts.EventState = evState;
5968 }
5969 }
5970 break;
Moore, Ericece50912006-01-16 18:53:19 -07005971 case MPI_EVENT_INTEGRATED_RAID:
5972 mptbase_raid_process_event_data(ioc,
5973 (MpiEventDataRaid_t *)pEventReply->Data);
5974 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005975 default:
5976 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 }
5978
5979 /*
5980 * Should this event be logged? Events are written sequentially.
5981 * When buffer is full, start again at the top.
5982 */
5983 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
5984 int idx;
5985
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07005986 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987
5988 ioc->events[idx].event = event;
5989 ioc->events[idx].eventContext = ioc->eventContext;
5990
5991 for (ii = 0; ii < 2; ii++) {
5992 if (ii < evDataLen)
5993 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
5994 else
5995 ioc->events[idx].data[ii] = 0;
5996 }
5997
5998 ioc->eventContext++;
5999 }
6000
6001
6002 /*
6003 * Call each currently registered protocol event handler.
6004 */
6005 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6006 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006007 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008 ioc->name, ii));
6009 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6010 handlers++;
6011 }
6012 }
6013 /* FIXME? Examine results here? */
6014
6015 /*
6016 * If needed, send (a single) EventAck.
6017 */
6018 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006019 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006020 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006022 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 ioc->name, ii));
6024 }
6025 }
6026
6027 *evHandlers = handlers;
6028 return r;
6029}
6030
6031/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6032/*
6033 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6034 * @ioc: Pointer to MPT_ADAPTER structure
6035 * @log_info: U32 LogInfo reply word from the IOC
6036 *
6037 * Refer to lsi/fc_log.h.
6038 */
6039static void
6040mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6041{
6042 static char *subcl_str[8] = {
6043 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6044 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6045 };
6046 u8 subcl = (log_info >> 24) & 0x7;
6047
6048 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6049 ioc->name, log_info, subcl_str[subcl]);
6050}
6051
6052/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6053/*
Moore, Eric335a9412006-01-17 17:06:23 -07006054 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 * @ioc: Pointer to MPT_ADAPTER structure
6056 * @mr: Pointer to MPT reply frame
6057 * @log_info: U32 LogInfo word from the IOC
6058 *
6059 * Refer to lsi/sp_log.h.
6060 */
6061static void
Moore, Eric335a9412006-01-17 17:06:23 -07006062mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063{
6064 u32 info = log_info & 0x00FF0000;
6065 char *desc = "unknown";
6066
6067 switch (info) {
6068 case 0x00010000:
6069 desc = "bug! MID not found";
6070 if (ioc->reload_fw == 0)
6071 ioc->reload_fw++;
6072 break;
6073
6074 case 0x00020000:
6075 desc = "Parity Error";
6076 break;
6077
6078 case 0x00030000:
6079 desc = "ASYNC Outbound Overrun";
6080 break;
6081
6082 case 0x00040000:
6083 desc = "SYNC Offset Error";
6084 break;
6085
6086 case 0x00050000:
6087 desc = "BM Change";
6088 break;
6089
6090 case 0x00060000:
6091 desc = "Msg In Overflow";
6092 break;
6093
6094 case 0x00070000:
6095 desc = "DMA Error";
6096 break;
6097
6098 case 0x00080000:
6099 desc = "Outbound DMA Overrun";
6100 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006101
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 case 0x00090000:
6103 desc = "Task Management";
6104 break;
6105
6106 case 0x000A0000:
6107 desc = "Device Problem";
6108 break;
6109
6110 case 0x000B0000:
6111 desc = "Invalid Phase Change";
6112 break;
6113
6114 case 0x000C0000:
6115 desc = "Untagged Table Size";
6116 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006117
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 }
6119
6120 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6121}
6122
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006123/* strings for sas loginfo */
6124 static char *originator_str[] = {
6125 "IOP", /* 00h */
6126 "PL", /* 01h */
6127 "IR" /* 02h */
6128 };
6129 static char *iop_code_str[] = {
6130 NULL, /* 00h */
6131 "Invalid SAS Address", /* 01h */
6132 NULL, /* 02h */
6133 "Invalid Page", /* 03h */
6134 NULL, /* 04h */
6135 "Task Terminated" /* 05h */
6136 };
6137 static char *pl_code_str[] = {
6138 NULL, /* 00h */
6139 "Open Failure", /* 01h */
6140 "Invalid Scatter Gather List", /* 02h */
6141 "Wrong Relative Offset or Frame Length", /* 03h */
6142 "Frame Transfer Error", /* 04h */
6143 "Transmit Frame Connected Low", /* 05h */
6144 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6145 "SATA Read Log Receive Data Error", /* 07h */
6146 "SATA NCQ Fail All Commands After Error", /* 08h */
6147 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6148 "Receive Frame Invalid Message", /* 0Ah */
6149 "Receive Context Message Valid Error", /* 0Bh */
6150 "Receive Frame Current Frame Error", /* 0Ch */
6151 "SATA Link Down", /* 0Dh */
6152 "Discovery SATA Init W IOS", /* 0Eh */
6153 "Config Invalid Page", /* 0Fh */
6154 "Discovery SATA Init Timeout", /* 10h */
6155 "Reset", /* 11h */
6156 "Abort", /* 12h */
6157 "IO Not Yet Executed", /* 13h */
6158 "IO Executed", /* 14h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006159 "Persistant Reservation Out Not Affiliation Owner", /* 15h */
6160 "Open Transmit DMA Abort", /* 16h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006161 NULL, /* 17h */
6162 NULL, /* 18h */
6163 NULL, /* 19h */
6164 NULL, /* 1Ah */
6165 NULL, /* 1Bh */
6166 NULL, /* 1Ch */
6167 NULL, /* 1Dh */
6168 NULL, /* 1Eh */
6169 NULL, /* 1Fh */
6170 "Enclosure Management" /* 20h */
6171 };
6172
6173/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6174/*
6175 * mpt_sas_log_info - Log information returned from SAS IOC.
6176 * @ioc: Pointer to MPT_ADAPTER structure
6177 * @log_info: U32 LogInfo reply word from the IOC
6178 *
6179 * Refer to lsi/mpi_log_sas.h.
6180 */
6181static void
6182mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6183{
6184union loginfo_type {
6185 u32 loginfo;
6186 struct {
6187 u32 subcode:16;
6188 u32 code:8;
6189 u32 originator:4;
6190 u32 bus_type:4;
6191 }dw;
6192};
6193 union loginfo_type sas_loginfo;
6194 char *code_desc = NULL;
6195
6196 sas_loginfo.loginfo = log_info;
6197 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6198 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6199 return;
6200 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6201 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6202 code_desc = iop_code_str[sas_loginfo.dw.code];
6203 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6204 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6205 code_desc = pl_code_str[sas_loginfo.dw.code];
6206 }
6207
6208 if (code_desc != NULL)
6209 printk(MYIOC_s_INFO_FMT
6210 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6211 " SubCode(0x%04x)\n",
6212 ioc->name,
6213 log_info,
6214 originator_str[sas_loginfo.dw.originator],
6215 code_desc,
6216 sas_loginfo.dw.subcode);
6217 else
6218 printk(MYIOC_s_INFO_FMT
6219 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6220 " SubCode(0x%04x)\n",
6221 ioc->name,
6222 log_info,
6223 originator_str[sas_loginfo.dw.originator],
6224 sas_loginfo.dw.code,
6225 sas_loginfo.dw.subcode);
6226}
6227
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6229/*
6230 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6231 * @ioc: Pointer to MPT_ADAPTER structure
6232 * @ioc_status: U32 IOCStatus word from IOC
6233 * @mf: Pointer to MPT request frame
6234 *
6235 * Refer to lsi/mpi.h.
6236 */
6237static void
6238mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6239{
6240 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
6241 char *desc = "";
6242
6243 switch (status) {
6244 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6245 desc = "Invalid Function";
6246 break;
6247
6248 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6249 desc = "Busy";
6250 break;
6251
6252 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6253 desc = "Invalid SGL";
6254 break;
6255
6256 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6257 desc = "Internal Error";
6258 break;
6259
6260 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6261 desc = "Reserved";
6262 break;
6263
6264 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6265 desc = "Insufficient Resources";
6266 break;
6267
6268 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6269 desc = "Invalid Field";
6270 break;
6271
6272 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6273 desc = "Invalid State";
6274 break;
6275
6276 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6277 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6278 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6279 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6280 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6281 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6282 /* No message for Config IOCStatus values */
6283 break;
6284
6285 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6286 /* No message for recovered error
6287 desc = "SCSI Recovered Error";
6288 */
6289 break;
6290
6291 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6292 desc = "SCSI Invalid Bus";
6293 break;
6294
6295 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6296 desc = "SCSI Invalid TargetID";
6297 break;
6298
6299 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6300 {
6301 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6302 U8 cdb = pScsiReq->CDB[0];
6303 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6304 desc = "SCSI Device Not There";
6305 }
6306 break;
6307 }
6308
6309 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6310 desc = "SCSI Data Overrun";
6311 break;
6312
6313 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006314 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315 desc = "SCSI Data Underrun";
6316 */
6317 break;
6318
6319 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6320 desc = "SCSI I/O Data Error";
6321 break;
6322
6323 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6324 desc = "SCSI Protocol Error";
6325 break;
6326
6327 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6328 desc = "SCSI Task Terminated";
6329 break;
6330
6331 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6332 desc = "SCSI Residual Mismatch";
6333 break;
6334
6335 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6336 desc = "SCSI Task Management Failed";
6337 break;
6338
6339 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6340 desc = "SCSI IOC Terminated";
6341 break;
6342
6343 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6344 desc = "SCSI Ext Terminated";
6345 break;
6346
6347 default:
6348 desc = "Others";
6349 break;
6350 }
6351 if (desc != "")
6352 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6353}
6354
6355/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006356EXPORT_SYMBOL(mpt_attach);
6357EXPORT_SYMBOL(mpt_detach);
6358#ifdef CONFIG_PM
6359EXPORT_SYMBOL(mpt_resume);
6360EXPORT_SYMBOL(mpt_suspend);
6361#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006363EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364EXPORT_SYMBOL(mpt_register);
6365EXPORT_SYMBOL(mpt_deregister);
6366EXPORT_SYMBOL(mpt_event_register);
6367EXPORT_SYMBOL(mpt_event_deregister);
6368EXPORT_SYMBOL(mpt_reset_register);
6369EXPORT_SYMBOL(mpt_reset_deregister);
6370EXPORT_SYMBOL(mpt_device_driver_register);
6371EXPORT_SYMBOL(mpt_device_driver_deregister);
6372EXPORT_SYMBOL(mpt_get_msg_frame);
6373EXPORT_SYMBOL(mpt_put_msg_frame);
6374EXPORT_SYMBOL(mpt_free_msg_frame);
6375EXPORT_SYMBOL(mpt_add_sge);
6376EXPORT_SYMBOL(mpt_send_handshake_request);
6377EXPORT_SYMBOL(mpt_verify_adapter);
6378EXPORT_SYMBOL(mpt_GetIocState);
6379EXPORT_SYMBOL(mpt_print_ioc_summary);
6380EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006381EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382EXPORT_SYMBOL(mpt_HardResetHandler);
6383EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385EXPORT_SYMBOL(mpt_alloc_fw_memory);
6386EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006387EXPORT_SYMBOL(mptbase_sas_persist_operation);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389
6390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6391/*
6392 * fusion_init - Fusion MPT base driver initialization routine.
6393 *
6394 * Returns 0 for success, non-zero for failure.
6395 */
6396static int __init
6397fusion_init(void)
6398{
6399 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400
6401 show_mptmod_ver(my_NAME, my_VERSION);
6402 printk(KERN_INFO COPYRIGHT "\n");
6403
6404 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6405 MptCallbacks[i] = NULL;
6406 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6407 MptEvHandlers[i] = NULL;
6408 MptResetHandlers[i] = NULL;
6409 }
6410
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006411 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006412 * EventNotification handling.
6413 */
6414 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6415
6416 /* Register for hard reset handling callbacks.
6417 */
6418 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6419 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6420 } else {
6421 /* FIXME! */
6422 }
6423
6424#ifdef CONFIG_PROC_FS
6425 (void) procmpt_create();
6426#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006427 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428}
6429
6430/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6431/*
6432 * fusion_exit - Perform driver unload cleanup.
6433 *
6434 * This routine frees all resources associated with each MPT adapter
6435 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6436 */
6437static void __exit
6438fusion_exit(void)
6439{
6440
6441 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6442
Linus Torvalds1da177e2005-04-16 15:20:36 -07006443 mpt_reset_deregister(mpt_base_index);
6444
6445#ifdef CONFIG_PROC_FS
6446 procmpt_destroy();
6447#endif
6448}
6449
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450module_init(fusion_init);
6451module_exit(fusion_exit);