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