blob: 20609966c2a95ac81e69750059721760abad2d9d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
7 *
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * (mailto:mpt_linux_developer@lsil.com)
10 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
49#include <linux/config.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/kernel.h>
51#include <linux/module.h>
52#include <linux/errno.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/types.h>
56#include <linux/pci.h>
57#include <linux/kdev_t.h>
58#include <linux/blkdev.h>
59#include <linux/delay.h>
60#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040061#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/io.h>
63#ifdef CONFIG_MTRR
64#include <asm/mtrr.h>
65#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
68
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
77
78/*
79 * cmd line parameters
80 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000081static int mpt_msi_enable;
82module_param(mpt_msi_enable, int, 0);
83MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#ifdef MFCNT
86static int mfcounter = 0;
87#define PRINT_MF_COUNT 20000
88#endif
89
90/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
91/*
92 * Public data...
93 */
94int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080095int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Linus Torvaldsf7473072005-11-29 14:21:57 -080097struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99#define WHOINIT_UNKNOWN 0xAA
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Private data...
104 */
105 /* Adapter link list */
106LIST_HEAD(ioc_list);
107 /* Callback lookup table */
108static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
109 /* Protocol driver class lookup table */
110static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
111 /* Event handler lookup table */
112static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
113 /* Reset handler lookup table */
114static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
115static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
116
117static int mpt_base_index = -1;
118static int last_drv_idx = -1;
119
120static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
121
122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
123/*
124 * Forward protos...
125 */
126static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
127static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
128static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
129 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
130 int sleepFlag);
131static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
132static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
133static void mpt_adapter_disable(MPT_ADAPTER *ioc);
134static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
135
136static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
137static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
139static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
140static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
141static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
142static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200143static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
145static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
146static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
147static int PrimeIocFifos(MPT_ADAPTER *ioc);
148static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
149static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
150static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
151static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200153int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
155static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
156static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
157static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
158static void mpt_timer_expired(unsigned long data);
159static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
160static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200161static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
162static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164#ifdef CONFIG_PROC_FS
165static int procmpt_summary_read(char *buf, char **start, off_t offset,
166 int request, int *eof, void *data);
167static int procmpt_version_read(char *buf, char **start, off_t offset,
168 int request, int *eof, void *data);
169static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
170 int request, int *eof, void *data);
171#endif
172static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
173
174//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
175static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
176static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
177static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700178static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600179static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700180static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183static int __init fusion_init (void);
184static void __exit fusion_exit (void);
185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186#define CHIPREG_READ32(addr) readl_relaxed(addr)
187#define CHIPREG_READ32_dmasync(addr) readl(addr)
188#define CHIPREG_WRITE32(addr,val) writel(val, addr)
189#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
190#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
191
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600192static void
193pci_disable_io_access(struct pci_dev *pdev)
194{
195 u16 command_reg;
196
197 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
198 command_reg &= ~1;
199 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
200}
201
202static void
203pci_enable_io_access(struct pci_dev *pdev)
204{
205 u16 command_reg;
206
207 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
208 command_reg |= 1;
209 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
210}
211
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600212/*
213 * Process turbo (context) reply...
214 */
215static void
216mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
217{
218 MPT_FRAME_HDR *mf = NULL;
219 MPT_FRAME_HDR *mr = NULL;
220 int req_idx = 0;
221 int cb_idx;
222
223 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
224 ioc->name, pa));
225
226 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
227 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
228 req_idx = pa & 0x0000FFFF;
229 cb_idx = (pa & 0x00FF0000) >> 16;
230 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
231 break;
232 case MPI_CONTEXT_REPLY_TYPE_LAN:
233 cb_idx = mpt_lan_index;
234 /*
235 * Blind set of mf to NULL here was fatal
236 * after lan_reply says "freeme"
237 * Fix sort of combined with an optimization here;
238 * added explicit check for case where lan_reply
239 * was just returning 1 and doing nothing else.
240 * For this case skip the callback, but set up
241 * proper mf value first here:-)
242 */
243 if ((pa & 0x58000000) == 0x58000000) {
244 req_idx = pa & 0x0000FFFF;
245 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
246 mpt_free_msg_frame(ioc, mf);
247 mb();
248 return;
249 break;
250 }
251 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
252 break;
253 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
254 cb_idx = mpt_stm_index;
255 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
256 break;
257 default:
258 cb_idx = 0;
259 BUG();
260 }
261
262 /* Check for (valid) IO callback! */
263 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
264 MptCallbacks[cb_idx] == NULL) {
265 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
266 __FUNCTION__, ioc->name, cb_idx);
267 goto out;
268 }
269
270 if (MptCallbacks[cb_idx](ioc, mf, mr))
271 mpt_free_msg_frame(ioc, mf);
272 out:
273 mb();
274}
275
276static void
277mpt_reply(MPT_ADAPTER *ioc, u32 pa)
278{
279 MPT_FRAME_HDR *mf;
280 MPT_FRAME_HDR *mr;
281 int req_idx;
282 int cb_idx;
283 int freeme;
284
285 u32 reply_dma_low;
286 u16 ioc_stat;
287
288 /* non-TURBO reply! Hmmm, something may be up...
289 * Newest turbo reply mechanism; get address
290 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
291 */
292
293 /* Map DMA address of reply header to cpu address.
294 * pa is 32 bits - but the dma address may be 32 or 64 bits
295 * get offset based only only the low addresses
296 */
297
298 reply_dma_low = (pa <<= 1);
299 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
300 (reply_dma_low - ioc->reply_frames_low_dma));
301
302 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
303 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
304 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
305
306 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
307 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
308 DBG_DUMP_REPLY_FRAME(mr)
309
310 /* Check/log IOC log info
311 */
312 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
313 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
314 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
315 if (ioc->bus_type == FC)
316 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700317 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700318 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600319 else if (ioc->bus_type == SAS)
320 mpt_sas_log_info(ioc, log_info);
321 }
322 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700323 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600324 cb_idx != mpt_stm_index &&
325 cb_idx != mpt_lan_index)
326 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
327 }
328
329
330 /* Check for (valid) IO callback! */
331 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
332 MptCallbacks[cb_idx] == NULL) {
333 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
334 __FUNCTION__, ioc->name, cb_idx);
335 freeme = 0;
336 goto out;
337 }
338
339 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
340
341 out:
342 /* Flush (non-TURBO) reply with a WRITE! */
343 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
344
345 if (freeme)
346 mpt_free_msg_frame(ioc, mf);
347 mb();
348}
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
351/*
352 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
353 * @irq: irq number (not used)
354 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
355 * @r: pt_regs pointer (not used)
356 *
357 * This routine is registered via the request_irq() kernel API call,
358 * and handles all interrupts generated from a specific MPT adapter
359 * (also referred to as a IO Controller or IOC).
360 * This routine must clear the interrupt from the adapter and does
361 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200362 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 *
364 * This routine handles register-level access of the adapter but
365 * dispatches (calls) a protocol-specific callback routine to handle
366 * the protocol-specific details of the MPT request completion.
367 */
368static irqreturn_t
369mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
370{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600371 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600372 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
373
374 if (pa == 0xFFFFFFFF)
375 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 /*
378 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600380 do {
381 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600382 mpt_reply(ioc, pa);
383 else
384 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600385 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
386 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 return IRQ_HANDLED;
389}
390
391/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
392/*
393 * mpt_base_reply - MPT base driver's callback routine; all base driver
394 * "internal" request/reply processing is routed here.
395 * Currently used for EventNotification and EventAck handling.
396 * @ioc: Pointer to MPT_ADAPTER structure
397 * @mf: Pointer to original MPT request frame
398 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
399 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200400 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 * should be freed, or 0 if it shouldn't.
402 */
403static int
404mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
405{
406 int freereq = 1;
407 u8 func;
408
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200409 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200411#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
413 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
414 DBG_DUMP_REQUEST_FRAME_HDR(mf)
415 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200416#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200419 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 ioc->name, func));
421
422 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
423 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
424 int evHandlers = 0;
425 int results;
426
427 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
428 if (results != evHandlers) {
429 /* CHECKME! Any special handling needed here? */
Moore, Eric3a892be2006-03-14 09:14:03 -0700430 devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 ioc->name, evHandlers, results));
432 }
433
434 /*
435 * Hmmm... It seems that EventNotificationReply is an exception
436 * to the rule of one reply per request.
437 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200438 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 freereq = 0;
Moore, Eric3a892be2006-03-14 09:14:03 -0700440 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200441 ioc->name, pEvReply));
442 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700443 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200444 ioc->name, pEvReply));
445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447#ifdef CONFIG_PROC_FS
448// LogEvent(ioc, pEvReply);
449#endif
450
451 } else if (func == MPI_FUNCTION_EVENT_ACK) {
452 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
453 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700454 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 CONFIGPARMS *pCfg;
456 unsigned long flags;
457
458 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
459 ioc->name, mf, reply));
460
461 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
462
463 if (pCfg) {
464 /* disable timer and remove from linked list */
465 del_timer(&pCfg->timer);
466
467 spin_lock_irqsave(&ioc->FreeQlock, flags);
468 list_del(&pCfg->linkage);
469 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
470
471 /*
472 * If IOC Status is SUCCESS, save the header
473 * and set the status code to GOOD.
474 */
475 pCfg->status = MPT_CONFIG_ERROR;
476 if (reply) {
477 ConfigReply_t *pReply = (ConfigReply_t *)reply;
478 u16 status;
479
480 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
481 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
482 status, le32_to_cpu(pReply->IOCLogInfo)));
483
484 pCfg->status = status;
485 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200486 if ((pReply->Header.PageType &
487 MPI_CONFIG_PAGETYPE_MASK) ==
488 MPI_CONFIG_PAGETYPE_EXTENDED) {
489 pCfg->cfghdr.ehdr->ExtPageLength =
490 le16_to_cpu(pReply->ExtPageLength);
491 pCfg->cfghdr.ehdr->ExtPageType =
492 pReply->ExtPageType;
493 }
494 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
495
496 /* If this is a regular header, save PageLength. */
497 /* LMP Do this better so not using a reserved field! */
498 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
499 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
500 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
502 }
503
504 /*
505 * Wake up the original calling thread
506 */
507 pCfg->wait_done = 1;
508 wake_up(&mpt_waitq);
509 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200510 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
511 /* we should be always getting a reply frame */
512 memcpy(ioc->persist_reply_frame, reply,
513 min(MPT_DEFAULT_FRAME_SIZE,
514 4*reply->u.reply.MsgLength));
515 del_timer(&ioc->persist_timer);
516 ioc->persist_wait_done = 1;
517 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 } else {
519 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
520 ioc->name, func);
521 }
522
523 /*
524 * Conditionally tell caller to free the original
525 * EventNotification/EventAck/unexpected request frame!
526 */
527 return freereq;
528}
529
530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
531/**
532 * mpt_register - Register protocol-specific main callback handler.
533 * @cbfunc: callback function pointer
534 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
535 *
536 * This routine is called by a protocol-specific driver (SCSI host,
537 * LAN, SCSI target) to register it's reply callback routine. Each
538 * protocol-specific driver must do this before it will be able to
539 * use any IOC resources, such as obtaining request frames.
540 *
541 * NOTES: The SCSI protocol driver currently calls this routine thrice
542 * in order to register separate callbacks; one for "normal" SCSI IO;
543 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
544 *
545 * Returns a positive integer valued "handle" in the
546 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
547 * Any non-positive return value (including zero!) should be considered
548 * an error by the caller.
549 */
550int
551mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
552{
553 int i;
554
555 last_drv_idx = -1;
556
557 /*
558 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
559 * (slot/handle 0 is reserved!)
560 */
561 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
562 if (MptCallbacks[i] == NULL) {
563 MptCallbacks[i] = cbfunc;
564 MptDriverClass[i] = dclass;
565 MptEvHandlers[i] = NULL;
566 last_drv_idx = i;
567 break;
568 }
569 }
570
571 return last_drv_idx;
572}
573
574/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
575/**
576 * mpt_deregister - Deregister a protocol drivers resources.
577 * @cb_idx: previously registered callback handle
578 *
579 * Each protocol-specific driver should call this routine when it's
580 * module is unloaded.
581 */
582void
583mpt_deregister(int cb_idx)
584{
585 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
586 MptCallbacks[cb_idx] = NULL;
587 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
588 MptEvHandlers[cb_idx] = NULL;
589
590 last_drv_idx++;
591 }
592}
593
594/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
595/**
596 * mpt_event_register - Register protocol-specific event callback
597 * handler.
598 * @cb_idx: previously registered (via mpt_register) callback handle
599 * @ev_cbfunc: callback function
600 *
601 * This routine can be called by one or more protocol-specific drivers
602 * if/when they choose to be notified of MPT events.
603 *
604 * Returns 0 for success.
605 */
606int
607mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
608{
609 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
610 return -1;
611
612 MptEvHandlers[cb_idx] = ev_cbfunc;
613 return 0;
614}
615
616/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
617/**
618 * mpt_event_deregister - Deregister protocol-specific event callback
619 * handler.
620 * @cb_idx: previously registered callback handle
621 *
622 * Each protocol-specific driver should call this routine
623 * when it does not (or can no longer) handle events,
624 * or when it's module is unloaded.
625 */
626void
627mpt_event_deregister(int cb_idx)
628{
629 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
630 return;
631
632 MptEvHandlers[cb_idx] = NULL;
633}
634
635/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
636/**
637 * mpt_reset_register - Register protocol-specific IOC reset handler.
638 * @cb_idx: previously registered (via mpt_register) callback handle
639 * @reset_func: reset function
640 *
641 * This routine can be called by one or more protocol-specific drivers
642 * if/when they choose to be notified of IOC resets.
643 *
644 * Returns 0 for success.
645 */
646int
647mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
648{
649 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
650 return -1;
651
652 MptResetHandlers[cb_idx] = reset_func;
653 return 0;
654}
655
656/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
657/**
658 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
659 * @cb_idx: previously registered callback handle
660 *
661 * Each protocol-specific driver should call this routine
662 * when it does not (or can no longer) handle IOC reset handling,
663 * or when it's module is unloaded.
664 */
665void
666mpt_reset_deregister(int cb_idx)
667{
668 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
669 return;
670
671 MptResetHandlers[cb_idx] = NULL;
672}
673
674/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
675/**
676 * mpt_device_driver_register - Register device driver hooks
677 */
678int
679mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
680{
681 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
683 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400684 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 }
686
687 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
688
689 /* call per pci device probe entry point */
690 list_for_each_entry(ioc, &ioc_list, list) {
691 if(dd_cbfunc->probe) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400692 dd_cbfunc->probe(ioc->pcidev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 ioc->pcidev->driver->id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
695 }
696
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400697 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698}
699
700/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
701/**
702 * mpt_device_driver_deregister - DeRegister device driver hooks
703 */
704void
705mpt_device_driver_deregister(int cb_idx)
706{
707 struct mpt_pci_driver *dd_cbfunc;
708 MPT_ADAPTER *ioc;
709
710 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
711 return;
712
713 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
714
715 list_for_each_entry(ioc, &ioc_list, list) {
716 if (dd_cbfunc->remove)
717 dd_cbfunc->remove(ioc->pcidev);
718 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 MptDeviceDriverHandlers[cb_idx] = NULL;
721}
722
723
724/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
725/**
726 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
727 * allocated per MPT adapter.
728 * @handle: Handle of registered MPT protocol driver
729 * @ioc: Pointer to MPT adapter structure
730 *
731 * Returns pointer to a MPT request frame or %NULL if none are available
732 * or IOC is not active.
733 */
734MPT_FRAME_HDR*
735mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
736{
737 MPT_FRAME_HDR *mf;
738 unsigned long flags;
739 u16 req_idx; /* Request index */
740
741 /* validate handle and ioc identifier */
742
743#ifdef MFCNT
744 if (!ioc->active)
745 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
746#endif
747
748 /* If interrupts are not attached, do not return a request frame */
749 if (!ioc->active)
750 return NULL;
751
752 spin_lock_irqsave(&ioc->FreeQlock, flags);
753 if (!list_empty(&ioc->FreeQ)) {
754 int req_offset;
755
756 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
757 u.frame.linkage.list);
758 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200759 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
761 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
762 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500763 req_idx = req_offset / ioc->req_sz;
764 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
766 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
767#ifdef MFCNT
768 ioc->mfcnt++;
769#endif
770 }
771 else
772 mf = NULL;
773 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
774
775#ifdef MFCNT
776 if (mf == NULL)
777 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
778 mfcounter++;
779 if (mfcounter == PRINT_MF_COUNT)
780 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
781#endif
782
783 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
784 ioc->name, handle, ioc->id, mf));
785 return mf;
786}
787
788/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
789/**
790 * mpt_put_msg_frame - Send a protocol specific MPT request frame
791 * to a IOC.
792 * @handle: Handle of registered MPT protocol driver
793 * @ioc: Pointer to MPT adapter structure
794 * @mf: Pointer to MPT request frame
795 *
796 * This routine posts a MPT request frame to the request post FIFO of a
797 * specific MPT adapter.
798 */
799void
800mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
801{
802 u32 mf_dma_addr;
803 int req_offset;
804 u16 req_idx; /* Request index */
805
806 /* ensure values are reset properly! */
807 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
808 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
809 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500810 req_idx = req_offset / ioc->req_sz;
811 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
813
814#ifdef MPT_DEBUG_MSG_FRAME
815 {
816 u32 *m = mf->u.frame.hwhdr.__hdr;
817 int ii, n;
818
819 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
820 ioc->name, m);
821 n = ioc->req_sz/4 - 1;
822 while (m[n] == 0)
823 n--;
824 for (ii=0; ii<=n; ii++) {
825 if (ii && ((ii%8)==0))
826 printk("\n" KERN_INFO " ");
827 printk(" %08x", le32_to_cpu(m[ii]));
828 }
829 printk("\n");
830 }
831#endif
832
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200833 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 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]));
835 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
836}
837
838/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
839/**
840 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
841 * @handle: Handle of registered MPT protocol driver
842 * @ioc: Pointer to MPT adapter structure
843 * @mf: Pointer to MPT request frame
844 *
845 * This routine places a MPT request frame back on the MPT adapter's
846 * FreeQ.
847 */
848void
849mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
850{
851 unsigned long flags;
852
853 /* Put Request back on FreeQ! */
854 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200855 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
857#ifdef MFCNT
858 ioc->mfcnt--;
859#endif
860 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
861}
862
863/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
864/**
865 * mpt_add_sge - Place a simple SGE at address pAddr.
866 * @pAddr: virtual address for SGE
867 * @flagslength: SGE flags and data transfer length
868 * @dma_addr: Physical address
869 *
870 * This routine places a MPT request frame back on the MPT adapter's
871 * FreeQ.
872 */
873void
874mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
875{
876 if (sizeof(dma_addr_t) == sizeof(u64)) {
877 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
878 u32 tmp = dma_addr & 0xFFFFFFFF;
879
880 pSge->FlagsLength = cpu_to_le32(flagslength);
881 pSge->Address.Low = cpu_to_le32(tmp);
882 tmp = (u32) ((u64)dma_addr >> 32);
883 pSge->Address.High = cpu_to_le32(tmp);
884
885 } else {
886 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
887 pSge->FlagsLength = cpu_to_le32(flagslength);
888 pSge->Address = cpu_to_le32(dma_addr);
889 }
890}
891
892/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
893/**
894 * mpt_send_handshake_request - Send MPT request via doorbell
895 * handshake method.
896 * @handle: Handle of registered MPT protocol driver
897 * @ioc: Pointer to MPT adapter structure
898 * @reqBytes: Size of the request in bytes
899 * @req: Pointer to MPT request frame
900 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
901 *
902 * This routine is used exclusively to send MptScsiTaskMgmt
903 * requests since they are required to be sent via doorbell handshake.
904 *
905 * NOTE: It is the callers responsibility to byte-swap fields in the
906 * request which are greater than 1 byte in size.
907 *
908 * Returns 0 for success, non-zero for failure.
909 */
910int
911mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
912{
913 int r = 0;
914 u8 *req_as_bytes;
915 int ii;
916
917 /* State is known to be good upon entering
918 * this function so issue the bus reset
919 * request.
920 */
921
922 /*
923 * Emulate what mpt_put_msg_frame() does /wrt to sanity
924 * setting cb_idx/req_idx. But ONLY if this request
925 * is in proper (pre-alloc'd) request buffer range...
926 */
927 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
928 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
929 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
930 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
931 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
932 }
933
934 /* Make sure there are no doorbells */
935 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200936
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 CHIPREG_WRITE32(&ioc->chip->Doorbell,
938 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
939 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
940
941 /* Wait for IOC doorbell int */
942 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
943 return ii;
944 }
945
946 /* Read doorbell and check for active bit */
947 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
948 return -5;
949
950 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200951 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
954
955 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
956 return -2;
957 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 /* Send request via doorbell handshake */
960 req_as_bytes = (u8 *) req;
961 for (ii = 0; ii < reqBytes/4; ii++) {
962 u32 word;
963
964 word = ((req_as_bytes[(ii*4) + 0] << 0) |
965 (req_as_bytes[(ii*4) + 1] << 8) |
966 (req_as_bytes[(ii*4) + 2] << 16) |
967 (req_as_bytes[(ii*4) + 3] << 24));
968 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
969 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
970 r = -3;
971 break;
972 }
973 }
974
975 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
976 r = 0;
977 else
978 r = -4;
979
980 /* Make sure there are no doorbells */
981 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200982
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 return r;
984}
985
986/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
987/**
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200988 * mpt_host_page_access_control - provides mechanism for the host
989 * driver to control the IOC's Host Page Buffer access.
990 * @ioc: Pointer to MPT adapter structure
991 * @access_control_value: define bits below
992 *
993 * Access Control Value - bits[15:12]
994 * 0h Reserved
995 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
996 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
997 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
998 *
999 * Returns 0 for success, non-zero for failure.
1000 */
1001
1002static int
1003mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1004{
1005 int r = 0;
1006
1007 /* return if in use */
1008 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1009 & MPI_DOORBELL_ACTIVE)
1010 return -1;
1011
1012 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1013
1014 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1015 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1016 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1017 (access_control_value<<12)));
1018
1019 /* Wait for IOC to clear Doorbell Status bit */
1020 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1021 return -2;
1022 }else
1023 return 0;
1024}
1025
1026/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1027/**
1028 * mpt_host_page_alloc - allocate system memory for the fw
1029 * If we already allocated memory in past, then resend the same pointer.
1030 * ioc@: Pointer to pointer to IOC adapter
1031 * ioc_init@: Pointer to ioc init config page
1032 *
1033 * Returns 0 for success, non-zero for failure.
1034 */
1035static int
1036mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1037{
1038 char *psge;
1039 int flags_length;
1040 u32 host_page_buffer_sz=0;
1041
1042 if(!ioc->HostPageBuffer) {
1043
1044 host_page_buffer_sz =
1045 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1046
1047 if(!host_page_buffer_sz)
1048 return 0; /* fw doesn't need any host buffers */
1049
1050 /* spin till we get enough memory */
1051 while(host_page_buffer_sz > 0) {
1052
1053 if((ioc->HostPageBuffer = pci_alloc_consistent(
1054 ioc->pcidev,
1055 host_page_buffer_sz,
1056 &ioc->HostPageBuffer_dma)) != NULL) {
1057
1058 dinitprintk((MYIOC_s_INFO_FMT
1059 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
1060 ioc->name,
1061 ioc->HostPageBuffer,
1062 ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001063 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001064 ioc->alloc_total += host_page_buffer_sz;
1065 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1066 break;
1067 }
1068
1069 host_page_buffer_sz -= (4*1024);
1070 }
1071 }
1072
1073 if(!ioc->HostPageBuffer) {
1074 printk(MYIOC_s_ERR_FMT
1075 "Failed to alloc memory for host_page_buffer!\n",
1076 ioc->name);
1077 return -999;
1078 }
1079
1080 psge = (char *)&ioc_init->HostPageBufferSGE;
1081 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1082 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1083 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1084 MPI_SGE_FLAGS_HOST_TO_IOC |
1085 MPI_SGE_FLAGS_END_OF_BUFFER;
1086 if (sizeof(dma_addr_t) == sizeof(u64)) {
1087 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1088 }
1089 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1090 flags_length |= ioc->HostPageBuffer_sz;
1091 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1092 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1093
1094return 0;
1095}
1096
1097/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1098/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
1100 * the associated MPT adapter structure.
1101 * @iocid: IOC unique identifier (integer)
1102 * @iocpp: Pointer to pointer to IOC adapter
1103 *
1104 * Returns iocid and sets iocpp.
1105 */
1106int
1107mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1108{
1109 MPT_ADAPTER *ioc;
1110
1111 list_for_each_entry(ioc,&ioc_list,list) {
1112 if (ioc->id == iocid) {
1113 *iocpp =ioc;
1114 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 *iocpp = NULL;
1119 return -1;
1120}
1121
1122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1123/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001124 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 * @pdev: Pointer to pci_dev structure
1126 *
1127 * This routine performs all the steps necessary to bring the IOC of
1128 * a MPT adapter to a OPERATIONAL state. This includes registering
1129 * memory regions, registering the interrupt, and allocating request
1130 * and reply memory pools.
1131 *
1132 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1133 * MPT adapter.
1134 *
1135 * Returns 0 for success, non-zero for failure.
1136 *
1137 * TODO: Add support for polled controllers
1138 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001139int
1140mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
1142 MPT_ADAPTER *ioc;
1143 u8 __iomem *mem;
1144 unsigned long mem_phys;
1145 unsigned long port;
1146 u32 msize;
1147 u32 psize;
1148 int ii;
1149 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 u8 revision;
1151 u8 pcixcmd;
1152 static int mpt_ids = 0;
1153#ifdef CONFIG_PROC_FS
1154 struct proc_dir_entry *dent, *ent;
1155#endif
1156
1157 if (pci_enable_device(pdev))
1158 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001161
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001162 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 dprintk((KERN_INFO MYNAM
1164 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001165 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1167 return r;
1168 }
1169
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001170 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 dprintk((KERN_INFO MYNAM
1172 ": Using 64 bit consistent mask\n"));
1173 else
1174 dprintk((KERN_INFO MYNAM
1175 ": Not using 64 bit consistent mask\n"));
1176
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001177 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 if (ioc == NULL) {
1179 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1180 return -ENOMEM;
1181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 ioc->alloc_total = sizeof(MPT_ADAPTER);
1183 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1184 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 ioc->pcidev = pdev;
1187 ioc->diagPending = 0;
1188 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001189 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
1191 /* Initialize the event logging.
1192 */
1193 ioc->eventTypes = 0; /* None */
1194 ioc->eventContext = 0;
1195 ioc->eventLogSize = 0;
1196 ioc->events = NULL;
1197
1198#ifdef MFCNT
1199 ioc->mfcnt = 0;
1200#endif
1201
1202 ioc->cached_fw = NULL;
1203
1204 /* Initilize SCSI Config Data structure
1205 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001206 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
1208 /* Initialize the running configQ head.
1209 */
1210 INIT_LIST_HEAD(&ioc->configQ);
1211
Michael Reed05e8ec12006-01-13 14:31:54 -06001212 /* Initialize the fc rport list head.
1213 */
1214 INIT_LIST_HEAD(&ioc->fc_rports);
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 /* Find lookup slot. */
1217 INIT_LIST_HEAD(&ioc->list);
1218 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 mem_phys = msize = 0;
1221 port = psize = 0;
1222 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1223 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001224 if (psize)
1225 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 /* Get I/O space! */
1227 port = pci_resource_start(pdev, ii);
1228 psize = pci_resource_len(pdev,ii);
1229 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001230 if (msize)
1231 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 /* Get memmap */
1233 mem_phys = pci_resource_start(pdev, ii);
1234 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 }
1236 }
1237 ioc->mem_size = msize;
1238
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 mem = NULL;
1240 /* Get logical ptr for PciMem0 space */
1241 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001242 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if (mem == NULL) {
1244 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1245 kfree(ioc);
1246 return -EINVAL;
1247 }
1248 ioc->memmap = mem;
1249 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1250
1251 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1252 &ioc->facts, &ioc->pfacts[0]));
1253
1254 ioc->mem_phys = mem_phys;
1255 ioc->chip = (SYSIF_REGS __iomem *)mem;
1256
1257 /* Save Port IO values in case we need to do downloadboot */
1258 {
1259 u8 *pmem = (u8*)port;
1260 ioc->pio_mem_phys = port;
1261 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1262 }
1263
1264 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1265 ioc->prod_name = "LSIFC909";
1266 ioc->bus_type = FC;
1267 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001268 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 ioc->prod_name = "LSIFC929";
1270 ioc->bus_type = FC;
1271 }
1272 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1273 ioc->prod_name = "LSIFC919";
1274 ioc->bus_type = FC;
1275 }
1276 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1277 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1278 ioc->bus_type = FC;
1279 if (revision < XL_929) {
1280 ioc->prod_name = "LSIFC929X";
1281 /* 929X Chip Fix. Set Split transactions level
1282 * for PCIX. Set MOST bits to zero.
1283 */
1284 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1285 pcixcmd &= 0x8F;
1286 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1287 } else {
1288 ioc->prod_name = "LSIFC929XL";
1289 /* 929XL Chip Fix. Set MMRBC to 0x08.
1290 */
1291 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1292 pcixcmd |= 0x08;
1293 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1294 }
1295 }
1296 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1297 ioc->prod_name = "LSIFC919X";
1298 ioc->bus_type = FC;
1299 /* 919X Chip Fix. Set Split transactions level
1300 * for PCIX. Set MOST bits to zero.
1301 */
1302 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1303 pcixcmd &= 0x8F;
1304 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1305 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001306 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1307 ioc->prod_name = "LSIFC939X";
1308 ioc->bus_type = FC;
1309 ioc->errata_flag_1064 = 1;
1310 }
1311 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1312 ioc->prod_name = "LSIFC949X";
1313 ioc->bus_type = FC;
1314 ioc->errata_flag_1064 = 1;
1315 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001316 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1317 ioc->prod_name = "LSIFC949E";
1318 ioc->bus_type = FC;
1319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1321 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001322 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 /* 1030 Chip Fix. Disable Split transactions
1324 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1325 */
1326 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1327 if (revision < C0_1030) {
1328 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1329 pcixcmd &= 0x8F;
1330 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1331 }
1332 }
1333 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1334 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001335 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001337 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1338 ioc->prod_name = "LSISAS1064";
1339 ioc->bus_type = SAS;
1340 ioc->errata_flag_1064 = 1;
1341 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001342 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1343 ioc->prod_name = "LSISAS1068";
1344 ioc->bus_type = SAS;
1345 ioc->errata_flag_1064 = 1;
1346 }
1347 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1348 ioc->prod_name = "LSISAS1064E";
1349 ioc->bus_type = SAS;
1350 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001351 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1352 ioc->prod_name = "LSISAS1068E";
1353 ioc->bus_type = SAS;
1354 }
Eric Moore87cf8982006-06-27 16:09:26 -06001355 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
1356 ioc->prod_name = "LSISAS1078";
1357 ioc->bus_type = SAS;
1358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001360 if (ioc->errata_flag_1064)
1361 pci_disable_io_access(pdev);
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 sprintf(ioc->name, "ioc%d", ioc->id);
1364
1365 spin_lock_init(&ioc->FreeQlock);
1366
1367 /* Disable all! */
1368 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1369 ioc->active = 0;
1370 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1371
1372 /* Set lookup ptr. */
1373 list_add_tail(&ioc->list, &ioc_list);
1374
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001375 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 */
1377 mpt_detect_bound_ports(ioc, pdev);
1378
James Bottomleyc92f2222006-03-01 09:02:49 -06001379 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1380 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 printk(KERN_WARNING MYNAM
1382 ": WARNING - %s did not initialize properly! (%d)\n",
1383 ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001385 if (ioc->alt_ioc)
1386 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 iounmap(mem);
1388 kfree(ioc);
1389 pci_set_drvdata(pdev, NULL);
1390 return r;
1391 }
1392
1393 /* call per device driver probe entry point */
1394 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1395 if(MptDeviceDriverHandlers[ii] &&
1396 MptDeviceDriverHandlers[ii]->probe) {
1397 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1398 }
1399 }
1400
1401#ifdef CONFIG_PROC_FS
1402 /*
1403 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1404 */
1405 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1406 if (dent) {
1407 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1408 if (ent) {
1409 ent->read_proc = procmpt_iocinfo_read;
1410 ent->data = ioc;
1411 }
1412 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1413 if (ent) {
1414 ent->read_proc = procmpt_summary_read;
1415 ent->data = ioc;
1416 }
1417 }
1418#endif
1419
1420 return 0;
1421}
1422
1423/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1424/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001425 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 * @pdev: Pointer to pci_dev structure
1427 *
1428 */
1429
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001430void
1431mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432{
1433 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1434 char pname[32];
1435 int ii;
1436
1437 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1438 remove_proc_entry(pname, NULL);
1439 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1440 remove_proc_entry(pname, NULL);
1441 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1442 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001443
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 /* call per device driver remove entry point */
1445 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1446 if(MptDeviceDriverHandlers[ii] &&
1447 MptDeviceDriverHandlers[ii]->remove) {
1448 MptDeviceDriverHandlers[ii]->remove(pdev);
1449 }
1450 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 /* Disable interrupts! */
1453 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1454
1455 ioc->active = 0;
1456 synchronize_irq(pdev->irq);
1457
1458 /* Clear any lingering interrupt */
1459 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1460
1461 CHIPREG_READ32(&ioc->chip->IntStatus);
1462
1463 mpt_adapter_dispose(ioc);
1464
1465 pci_set_drvdata(pdev, NULL);
1466}
1467
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468/**************************************************************************
1469 * Power Management
1470 */
1471#ifdef CONFIG_PM
1472/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1473/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001474 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 *
1476 *
1477 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001478int
1479mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480{
1481 u32 device_state;
1482 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Pavel Machek2a569572005-07-07 17:56:40 -07001484 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
1486 printk(MYIOC_s_INFO_FMT
1487 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1488 ioc->name, pdev, pci_name(pdev), device_state);
1489
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 pci_save_state(pdev);
1491
1492 /* put ioc into READY_STATE */
1493 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1494 printk(MYIOC_s_ERR_FMT
1495 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1496 }
1497
1498 /* disable interrupts */
1499 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1500 ioc->active = 0;
1501
1502 /* Clear any lingering interrupt */
1503 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1504
1505 pci_disable_device(pdev);
1506 pci_set_power_state(pdev, device_state);
1507
1508 return 0;
1509}
1510
1511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1512/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001513 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 *
1515 *
1516 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001517int
1518mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519{
1520 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1521 u32 device_state = pdev->current_state;
1522 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 printk(MYIOC_s_INFO_FMT
1525 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1526 ioc->name, pdev, pci_name(pdev), device_state);
1527
1528 pci_set_power_state(pdev, 0);
1529 pci_restore_state(pdev);
1530 pci_enable_device(pdev);
1531
1532 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001533 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 ioc->active = 1;
1535
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 printk(MYIOC_s_INFO_FMT
1537 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1538 ioc->name,
1539 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1540 CHIPREG_READ32(&ioc->chip->Doorbell));
1541
1542 /* bring ioc to operational state */
1543 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1544 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1545 printk(MYIOC_s_INFO_FMT
1546 "pci-resume: Cannot recover, error:[%x]\n",
1547 ioc->name, recovery_state);
1548 } else {
1549 printk(MYIOC_s_INFO_FMT
1550 "pci-resume: success\n", ioc->name);
1551 }
1552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 return 0;
1554}
1555#endif
1556
James Bottomley4ff42a62006-05-17 18:06:52 -05001557static int
1558mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1559{
1560 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1561 ioc->bus_type != SPI) ||
1562 (MptDriverClass[index] == MPTFC_DRIVER &&
1563 ioc->bus_type != FC) ||
1564 (MptDriverClass[index] == MPTSAS_DRIVER &&
1565 ioc->bus_type != SAS))
1566 /* make sure we only call the relevant reset handler
1567 * for the bus */
1568 return 0;
1569 return (MptResetHandlers[index])(ioc, reset_phase);
1570}
1571
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1573/*
1574 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1575 * @ioc: Pointer to MPT adapter structure
1576 * @reason: Event word / reason
1577 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1578 *
1579 * This routine performs all the steps necessary to bring the IOC
1580 * to a OPERATIONAL state.
1581 *
1582 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1583 * MPT adapter.
1584 *
1585 * Returns:
1586 * 0 for success
1587 * -1 if failed to get board READY
1588 * -2 if READY but IOCFacts Failed
1589 * -3 if READY but PrimeIOCFifos Failed
1590 * -4 if READY but IOCInit Failed
1591 */
1592static int
1593mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1594{
1595 int hard_reset_done = 0;
1596 int alt_ioc_ready = 0;
1597 int hard;
1598 int rc=0;
1599 int ii;
1600 int handlers;
1601 int ret = 0;
1602 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001603 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
1605 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1606 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1607
1608 /* Disable reply interrupts (also blocks FreeQ) */
1609 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1610 ioc->active = 0;
1611
1612 if (ioc->alt_ioc) {
1613 if (ioc->alt_ioc->active)
1614 reset_alt_ioc_active = 1;
1615
1616 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1617 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1618 ioc->alt_ioc->active = 0;
1619 }
1620
1621 hard = 1;
1622 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1623 hard = 0;
1624
1625 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1626 if (hard_reset_done == -4) {
1627 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1628 ioc->name);
1629
1630 if (reset_alt_ioc_active && ioc->alt_ioc) {
1631 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1632 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1633 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001634 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 ioc->alt_ioc->active = 1;
1636 }
1637
1638 } else {
1639 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1640 ioc->name);
1641 }
1642 return -1;
1643 }
1644
1645 /* hard_reset_done = 0 if a soft reset was performed
1646 * and 1 if a hard reset was performed.
1647 */
1648 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1649 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1650 alt_ioc_ready = 1;
1651 else
1652 printk(KERN_WARNING MYNAM
1653 ": alt-%s: Not ready WARNING!\n",
1654 ioc->alt_ioc->name);
1655 }
1656
1657 for (ii=0; ii<5; ii++) {
1658 /* Get IOC facts! Allow 5 retries */
1659 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1660 break;
1661 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
1664 if (ii == 5) {
1665 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1666 ret = -2;
1667 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1668 MptDisplayIocCapabilities(ioc);
1669 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001670
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 if (alt_ioc_ready) {
1672 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1673 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1674 /* Retry - alt IOC was initialized once
1675 */
1676 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1677 }
1678 if (rc) {
1679 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1680 alt_ioc_ready = 0;
1681 reset_alt_ioc_active = 0;
1682 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1683 MptDisplayIocCapabilities(ioc->alt_ioc);
1684 }
1685 }
1686
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001687 /*
1688 * Device is reset now. It must have de-asserted the interrupt line
1689 * (if it was asserted) and it should be safe to register for the
1690 * interrupt now.
1691 */
1692 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1693 ioc->pci_irq = -1;
1694 if (ioc->pcidev->irq) {
1695 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1696 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1697 ioc->name);
1698 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
1699 SA_SHIRQ, ioc->name, ioc);
1700 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001701 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1702 "interrupt %d!\n", ioc->name,
1703 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001704 if (mpt_msi_enable)
1705 pci_disable_msi(ioc->pcidev);
1706 return -EBUSY;
1707 }
1708 irq_allocated = 1;
1709 ioc->pci_irq = ioc->pcidev->irq;
1710 pci_set_master(ioc->pcidev); /* ?? */
1711 pci_set_drvdata(ioc->pcidev, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001712 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1713 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001714 }
1715 }
1716
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 /* Prime reply & request queues!
1718 * (mucho alloc's) Must be done prior to
1719 * init as upper addresses are needed for init.
1720 * If fails, continue with alt-ioc processing
1721 */
1722 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1723 ret = -3;
1724
1725 /* May need to check/upload firmware & data here!
1726 * If fails, continue with alt-ioc processing
1727 */
1728 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1729 ret = -4;
1730// NEW!
1731 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1732 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1733 ioc->alt_ioc->name, rc);
1734 alt_ioc_ready = 0;
1735 reset_alt_ioc_active = 0;
1736 }
1737
1738 if (alt_ioc_ready) {
1739 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1740 alt_ioc_ready = 0;
1741 reset_alt_ioc_active = 0;
1742 printk(KERN_WARNING MYNAM
1743 ": alt-%s: (%d) init failure WARNING!\n",
1744 ioc->alt_ioc->name, rc);
1745 }
1746 }
1747
1748 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1749 if (ioc->upload_fw) {
1750 ddlprintk((MYIOC_s_INFO_FMT
1751 "firmware upload required!\n", ioc->name));
1752
1753 /* Controller is not operational, cannot do upload
1754 */
1755 if (ret == 0) {
1756 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001757 if (rc == 0) {
1758 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1759 /*
1760 * Maintain only one pointer to FW memory
1761 * so there will not be two attempt to
1762 * downloadboot onboard dual function
1763 * chips (mpt_adapter_disable,
1764 * mpt_diag_reset)
1765 */
1766 ioc->cached_fw = NULL;
1767 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1768 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1769 }
1770 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001772 ret = -5;
1773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 }
1775 }
1776 }
1777
1778 if (ret == 0) {
1779 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001780 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 ioc->active = 1;
1782 }
1783
1784 if (reset_alt_ioc_active && ioc->alt_ioc) {
1785 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001786 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001788 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 ioc->alt_ioc->active = 1;
1790 }
1791
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001792 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 * and EventAck handling.
1794 */
1795 if ((ret == 0) && (!ioc->facts.EventState))
1796 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1797
1798 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1799 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1800
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001801 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1803 * recursive scenario; GetLanConfigPages times out, timer expired
1804 * routine calls HardResetHandler, which calls into here again,
1805 * and we try GetLanConfigPages again...
1806 */
1807 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001808 if (ioc->bus_type == SAS) {
1809
1810 /* clear persistency table */
1811 if(ioc->facts.IOCExceptions &
1812 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1813 ret = mptbase_sas_persist_operation(ioc,
1814 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1815 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001816 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001817 }
1818
1819 /* Find IM volumes
1820 */
1821 mpt_findImVolumes(ioc);
1822
1823 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1825 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1826 /*
1827 * Pre-fetch the ports LAN MAC address!
1828 * (LANPage1_t stuff)
1829 */
1830 (void) GetLanConfigPages(ioc);
1831#ifdef MPT_DEBUG
1832 {
1833 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1834 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1835 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1836 }
1837#endif
1838 }
1839 } else {
1840 /* Get NVRAM and adapter maximums from SPP 0 and 2
1841 */
1842 mpt_GetScsiPortSettings(ioc, 0);
1843
1844 /* Get version and length of SDP 1
1845 */
1846 mpt_readScsiDevicePageHeaders(ioc, 0);
1847
1848 /* Find IM volumes
1849 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001850 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 mpt_findImVolumes(ioc);
1852
1853 /* Check, and possibly reset, the coalescing value
1854 */
1855 mpt_read_ioc_pg_1(ioc);
1856
1857 mpt_read_ioc_pg_4(ioc);
1858 }
1859
1860 GetIoUnitPage2(ioc);
1861 }
1862
1863 /*
1864 * Call each currently registered protocol IOC reset handler
1865 * with post-reset indication.
1866 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1867 * MptResetHandlers[] registered yet.
1868 */
1869 if (hard_reset_done) {
1870 rc = handlers = 0;
1871 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1872 if ((ret == 0) && MptResetHandlers[ii]) {
1873 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1874 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001875 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 handlers++;
1877 }
1878
1879 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001880 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001882 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 handlers++;
1884 }
1885 }
1886 /* FIXME? Examine results here? */
1887 }
1888
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001889out:
1890 if ((ret != 0) && irq_allocated) {
1891 free_irq(ioc->pci_irq, ioc);
1892 if (mpt_msi_enable)
1893 pci_disable_msi(ioc->pcidev);
1894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 return ret;
1896}
1897
1898/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1899/*
1900 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1901 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1902 * 929X, 1030 or 1035.
1903 * @ioc: Pointer to MPT adapter structure
1904 * @pdev: Pointer to (struct pci_dev) structure
1905 *
1906 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1907 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1908 */
1909static void
1910mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1911{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001912 struct pci_dev *peer=NULL;
1913 unsigned int slot = PCI_SLOT(pdev->devfn);
1914 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 MPT_ADAPTER *ioc_srch;
1916
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001917 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1918 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001919 ioc->name, pci_name(pdev), pdev->bus->number,
1920 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001921
1922 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1923 if (!peer) {
1924 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1925 if (!peer)
1926 return;
1927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928
1929 list_for_each_entry(ioc_srch, &ioc_list, list) {
1930 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001931 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /* Paranoia checks */
1933 if (ioc->alt_ioc != NULL) {
1934 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001935 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 break;
1937 } else if (ioc_srch->alt_ioc != NULL) {
1938 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001939 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 break;
1941 }
1942 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001943 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 ioc_srch->alt_ioc = ioc;
1945 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 }
1947 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001948 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949}
1950
1951/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1952/*
1953 * mpt_adapter_disable - Disable misbehaving MPT adapter.
1954 * @this: Pointer to MPT adapter structure
1955 */
1956static void
1957mpt_adapter_disable(MPT_ADAPTER *ioc)
1958{
1959 int sz;
1960 int ret;
1961
1962 if (ioc->cached_fw != NULL) {
1963 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001964 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 printk(KERN_WARNING MYNAM
1966 ": firmware downloadboot failure (%d)!\n", ret);
1967 }
1968 }
1969
1970 /* Disable adapter interrupts! */
1971 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1972 ioc->active = 0;
1973 /* Clear any lingering interrupt */
1974 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1975
1976 if (ioc->alloc != NULL) {
1977 sz = ioc->alloc_sz;
1978 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1979 ioc->name, ioc->alloc, ioc->alloc_sz));
1980 pci_free_consistent(ioc->pcidev, sz,
1981 ioc->alloc, ioc->alloc_dma);
1982 ioc->reply_frames = NULL;
1983 ioc->req_frames = NULL;
1984 ioc->alloc = NULL;
1985 ioc->alloc_total -= sz;
1986 }
1987
1988 if (ioc->sense_buf_pool != NULL) {
1989 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
1990 pci_free_consistent(ioc->pcidev, sz,
1991 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
1992 ioc->sense_buf_pool = NULL;
1993 ioc->alloc_total -= sz;
1994 }
1995
1996 if (ioc->events != NULL){
1997 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
1998 kfree(ioc->events);
1999 ioc->events = NULL;
2000 ioc->alloc_total -= sz;
2001 }
2002
2003 if (ioc->cached_fw != NULL) {
2004 sz = ioc->facts.FWImageSize;
2005 pci_free_consistent(ioc->pcidev, sz,
2006 ioc->cached_fw, ioc->cached_fw_dma);
2007 ioc->cached_fw = NULL;
2008 ioc->alloc_total -= sz;
2009 }
2010
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002011 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002012 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002013 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002014 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
2016 if (ioc->spi_data.pIocPg4 != NULL) {
2017 sz = ioc->spi_data.IocPg4Sz;
2018 pci_free_consistent(ioc->pcidev, sz,
2019 ioc->spi_data.pIocPg4,
2020 ioc->spi_data.IocPg4_dma);
2021 ioc->spi_data.pIocPg4 = NULL;
2022 ioc->alloc_total -= sz;
2023 }
2024
2025 if (ioc->ReqToChain != NULL) {
2026 kfree(ioc->ReqToChain);
2027 kfree(ioc->RequestNB);
2028 ioc->ReqToChain = NULL;
2029 }
2030
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002031 kfree(ioc->ChainToChain);
2032 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002033
2034 if (ioc->HostPageBuffer != NULL) {
2035 if((ret = mpt_host_page_access_control(ioc,
2036 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2037 printk(KERN_ERR MYNAM
2038 ": %s: host page buffers free failed (%d)!\n",
2039 __FUNCTION__, ret);
2040 }
2041 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2042 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2043 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2044 ioc->HostPageBuffer,
2045 ioc->HostPageBuffer_dma);
2046 ioc->HostPageBuffer = NULL;
2047 ioc->HostPageBuffer_sz = 0;
2048 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050}
2051
2052/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2053/*
2054 * mpt_adapter_dispose - Free all resources associated with a MPT
2055 * adapter.
2056 * @ioc: Pointer to MPT adapter structure
2057 *
2058 * This routine unregisters h/w resources and frees all alloc'd memory
2059 * associated with a MPT adapter structure.
2060 */
2061static void
2062mpt_adapter_dispose(MPT_ADAPTER *ioc)
2063{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002064 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002066 if (ioc == NULL)
2067 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002069 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002071 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002073 if (ioc->pci_irq != -1) {
2074 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002075 if (mpt_msi_enable)
2076 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002077 ioc->pci_irq = -1;
2078 }
2079
2080 if (ioc->memmap != NULL) {
2081 iounmap(ioc->memmap);
2082 ioc->memmap = NULL;
2083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
2085#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002086 if (ioc->mtrr_reg > 0) {
2087 mtrr_del(ioc->mtrr_reg, 0, 0);
2088 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090#endif
2091
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002092 /* Zap the adapter lookup ptr! */
2093 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002095 sz_last = ioc->alloc_total;
2096 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2097 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002098
2099 if (ioc->alt_ioc)
2100 ioc->alt_ioc->alt_ioc = NULL;
2101
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002102 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103}
2104
2105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2106/*
2107 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2108 * @ioc: Pointer to MPT adapter structure
2109 */
2110static void
2111MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2112{
2113 int i = 0;
2114
2115 printk(KERN_INFO "%s: ", ioc->name);
2116 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2117 printk("%s: ", ioc->prod_name+3);
2118 printk("Capabilities={");
2119
2120 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2121 printk("Initiator");
2122 i++;
2123 }
2124
2125 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2126 printk("%sTarget", i ? "," : "");
2127 i++;
2128 }
2129
2130 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2131 printk("%sLAN", i ? "," : "");
2132 i++;
2133 }
2134
2135#if 0
2136 /*
2137 * This would probably evoke more questions than it's worth
2138 */
2139 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2140 printk("%sLogBusAddr", i ? "," : "");
2141 i++;
2142 }
2143#endif
2144
2145 printk("}\n");
2146}
2147
2148/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2149/*
2150 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2151 * @ioc: Pointer to MPT_ADAPTER structure
2152 * @force: Force hard KickStart of IOC
2153 * @sleepFlag: Specifies whether the process can sleep
2154 *
2155 * Returns:
2156 * 1 - DIAG reset and READY
2157 * 0 - READY initially OR soft reset and READY
2158 * -1 - Any failure on KickStart
2159 * -2 - Msg Unit Reset Failed
2160 * -3 - IO Unit Reset Failed
2161 * -4 - IOC owned by a PEER
2162 */
2163static int
2164MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2165{
2166 u32 ioc_state;
2167 int statefault = 0;
2168 int cntdn;
2169 int hard_reset_done = 0;
2170 int r;
2171 int ii;
2172 int whoinit;
2173
2174 /* Get current [raw] IOC state */
2175 ioc_state = mpt_GetIocState(ioc, 0);
2176 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2177
2178 /*
2179 * Check to see if IOC got left/stuck in doorbell handshake
2180 * grip of death. If so, hard reset the IOC.
2181 */
2182 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2183 statefault = 1;
2184 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2185 ioc->name);
2186 }
2187
2188 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002189 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 return 0;
2191
2192 /*
2193 * Check to see if IOC is in FAULT state.
2194 */
2195 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2196 statefault = 2;
2197 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2198 ioc->name);
2199 printk(KERN_WARNING " FAULT code = %04xh\n",
2200 ioc_state & MPI_DOORBELL_DATA_MASK);
2201 }
2202
2203 /*
2204 * Hmmm... Did it get left operational?
2205 */
2206 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002207 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 ioc->name));
2209
2210 /* Check WhoInit.
2211 * If PCI Peer, exit.
2212 * Else, if no fault conditions are present, issue a MessageUnitReset
2213 * Else, fall through to KickStart case
2214 */
2215 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002216 dinitprintk((KERN_INFO MYNAM
2217 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 whoinit, statefault, force));
2219 if (whoinit == MPI_WHOINIT_PCI_PEER)
2220 return -4;
2221 else {
2222 if ((statefault == 0 ) && (force == 0)) {
2223 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2224 return 0;
2225 }
2226 statefault = 3;
2227 }
2228 }
2229
2230 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2231 if (hard_reset_done < 0)
2232 return -1;
2233
2234 /*
2235 * Loop here waiting for IOC to come READY.
2236 */
2237 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002238 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
2240 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2241 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2242 /*
2243 * BIOS or previous driver load left IOC in OP state.
2244 * Reset messaging FIFOs.
2245 */
2246 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2247 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2248 return -2;
2249 }
2250 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2251 /*
2252 * Something is wrong. Try to get IOC back
2253 * to a known state.
2254 */
2255 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2256 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2257 return -3;
2258 }
2259 }
2260
2261 ii++; cntdn--;
2262 if (!cntdn) {
2263 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2264 ioc->name, (int)((ii+5)/HZ));
2265 return -ETIME;
2266 }
2267
2268 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002269 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 } else {
2271 mdelay (1); /* 1 msec delay */
2272 }
2273
2274 }
2275
2276 if (statefault < 3) {
2277 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2278 ioc->name,
2279 statefault==1 ? "stuck handshake" : "IOC FAULT");
2280 }
2281
2282 return hard_reset_done;
2283}
2284
2285/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2286/*
2287 * mpt_GetIocState - Get the current state of a MPT adapter.
2288 * @ioc: Pointer to MPT_ADAPTER structure
2289 * @cooked: Request raw or cooked IOC state
2290 *
2291 * Returns all IOC Doorbell register bits if cooked==0, else just the
2292 * Doorbell bits in MPI_IOC_STATE_MASK.
2293 */
2294u32
2295mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2296{
2297 u32 s, sc;
2298
2299 /* Get! */
2300 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2301// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2302 sc = s & MPI_IOC_STATE_MASK;
2303
2304 /* Save! */
2305 ioc->last_state = sc;
2306
2307 return cooked ? sc : s;
2308}
2309
2310/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2311/*
2312 * GetIocFacts - Send IOCFacts request to MPT adapter.
2313 * @ioc: Pointer to MPT_ADAPTER structure
2314 * @sleepFlag: Specifies whether the process can sleep
2315 * @reason: If recovery, only update facts.
2316 *
2317 * Returns 0 for success, non-zero for failure.
2318 */
2319static int
2320GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2321{
2322 IOCFacts_t get_facts;
2323 IOCFactsReply_t *facts;
2324 int r;
2325 int req_sz;
2326 int reply_sz;
2327 int sz;
2328 u32 status, vv;
2329 u8 shiftFactor=1;
2330
2331 /* IOC *must* NOT be in RESET state! */
2332 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2333 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2334 ioc->name,
2335 ioc->last_state );
2336 return -44;
2337 }
2338
2339 facts = &ioc->facts;
2340
2341 /* Destination (reply area)... */
2342 reply_sz = sizeof(*facts);
2343 memset(facts, 0, reply_sz);
2344
2345 /* Request area (get_facts on the stack right now!) */
2346 req_sz = sizeof(get_facts);
2347 memset(&get_facts, 0, req_sz);
2348
2349 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2350 /* Assert: All other get_facts fields are zero! */
2351
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002352 dinitprintk((MYIOC_s_INFO_FMT
2353 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 ioc->name, req_sz, reply_sz));
2355
2356 /* No non-zero fields in the get_facts request are greater than
2357 * 1 byte in size, so we can just fire it off as is.
2358 */
2359 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2360 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2361 if (r != 0)
2362 return r;
2363
2364 /*
2365 * Now byte swap (GRRR) the necessary fields before any further
2366 * inspection of reply contents.
2367 *
2368 * But need to do some sanity checks on MsgLength (byte) field
2369 * to make sure we don't zero IOC's req_sz!
2370 */
2371 /* Did we get a valid reply? */
2372 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2373 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2374 /*
2375 * If not been here, done that, save off first WhoInit value
2376 */
2377 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2378 ioc->FirstWhoInit = facts->WhoInit;
2379 }
2380
2381 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2382 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2383 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2384 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2385 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002386 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 /* CHECKME! IOCStatus, IOCLogInfo */
2388
2389 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2390 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2391
2392 /*
2393 * FC f/w version changed between 1.1 and 1.2
2394 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2395 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2396 */
2397 if (facts->MsgVersion < 0x0102) {
2398 /*
2399 * Handle old FC f/w style, convert to new...
2400 */
2401 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2402 facts->FWVersion.Word =
2403 ((oldv<<12) & 0xFF000000) |
2404 ((oldv<<8) & 0x000FFF00);
2405 } else
2406 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2407
2408 facts->ProductID = le16_to_cpu(facts->ProductID);
2409 facts->CurrentHostMfaHighAddr =
2410 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2411 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2412 facts->CurrentSenseBufferHighAddr =
2413 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2414 facts->CurReplyFrameSize =
2415 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002416 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
2418 /*
2419 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2420 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2421 * to 14 in MPI-1.01.0x.
2422 */
2423 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2424 facts->MsgVersion > 0x0100) {
2425 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2426 }
2427
2428 sz = facts->FWImageSize;
2429 if ( sz & 0x01 )
2430 sz += 1;
2431 if ( sz & 0x02 )
2432 sz += 2;
2433 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002434
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 if (!facts->RequestFrameSize) {
2436 /* Something is wrong! */
2437 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2438 ioc->name);
2439 return -55;
2440 }
2441
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002442 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 vv = ((63 / (sz * 4)) + 1) & 0x03;
2444 ioc->NB_for_64_byte_frame = vv;
2445 while ( sz )
2446 {
2447 shiftFactor++;
2448 sz = sz >> 1;
2449 }
2450 ioc->NBShiftFactor = shiftFactor;
2451 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2452 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2455 /*
2456 * Set values for this IOC's request & reply frame sizes,
2457 * and request & reply queue depths...
2458 */
2459 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2460 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2461 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2462 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2463
2464 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2465 ioc->name, ioc->reply_sz, ioc->reply_depth));
2466 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2467 ioc->name, ioc->req_sz, ioc->req_depth));
2468
2469 /* Get port facts! */
2470 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2471 return r;
2472 }
2473 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002474 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2476 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2477 RequestFrameSize)/sizeof(u32)));
2478 return -66;
2479 }
2480
2481 return 0;
2482}
2483
2484/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2485/*
2486 * GetPortFacts - Send PortFacts request to MPT adapter.
2487 * @ioc: Pointer to MPT_ADAPTER structure
2488 * @portnum: Port number
2489 * @sleepFlag: Specifies whether the process can sleep
2490 *
2491 * Returns 0 for success, non-zero for failure.
2492 */
2493static int
2494GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2495{
2496 PortFacts_t get_pfacts;
2497 PortFactsReply_t *pfacts;
2498 int ii;
2499 int req_sz;
2500 int reply_sz;
2501
2502 /* IOC *must* NOT be in RESET state! */
2503 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2504 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2505 ioc->name,
2506 ioc->last_state );
2507 return -4;
2508 }
2509
2510 pfacts = &ioc->pfacts[portnum];
2511
2512 /* Destination (reply area)... */
2513 reply_sz = sizeof(*pfacts);
2514 memset(pfacts, 0, reply_sz);
2515
2516 /* Request area (get_pfacts on the stack right now!) */
2517 req_sz = sizeof(get_pfacts);
2518 memset(&get_pfacts, 0, req_sz);
2519
2520 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2521 get_pfacts.PortNumber = portnum;
2522 /* Assert: All other get_pfacts fields are zero! */
2523
2524 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2525 ioc->name, portnum));
2526
2527 /* No non-zero fields in the get_pfacts request are greater than
2528 * 1 byte in size, so we can just fire it off as is.
2529 */
2530 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2531 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2532 if (ii != 0)
2533 return ii;
2534
2535 /* Did we get a valid reply? */
2536
2537 /* Now byte swap the necessary fields in the response. */
2538 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2539 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2540 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2541 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2542 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2543 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2544 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2545 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2546 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2547
2548 return 0;
2549}
2550
2551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2552/*
2553 * SendIocInit - Send IOCInit request to MPT adapter.
2554 * @ioc: Pointer to MPT_ADAPTER structure
2555 * @sleepFlag: Specifies whether the process can sleep
2556 *
2557 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2558 *
2559 * Returns 0 for success, non-zero for failure.
2560 */
2561static int
2562SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2563{
2564 IOCInit_t ioc_init;
2565 MPIDefaultReply_t init_reply;
2566 u32 state;
2567 int r;
2568 int count;
2569 int cntdn;
2570
2571 memset(&ioc_init, 0, sizeof(ioc_init));
2572 memset(&init_reply, 0, sizeof(init_reply));
2573
2574 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2575 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2576
2577 /* If we are in a recovery mode and we uploaded the FW image,
2578 * then this pointer is not NULL. Skip the upload a second time.
2579 * Set this flag if cached_fw set for either IOC.
2580 */
2581 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2582 ioc->upload_fw = 1;
2583 else
2584 ioc->upload_fw = 0;
2585 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2586 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2587
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002588 if(ioc->bus_type == SAS)
2589 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2590 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2592 else
2593 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002595 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2596 ioc->name, ioc->facts.MsgVersion));
2597 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2598 // set MsgVersion and HeaderVersion host driver was built with
2599 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2600 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002602 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2603 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2604 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2605 return -99;
2606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2608
2609 if (sizeof(dma_addr_t) == sizeof(u64)) {
2610 /* Save the upper 32-bits of the request
2611 * (reply) and sense buffers.
2612 */
2613 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2614 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2615 } else {
2616 /* Force 32-bit addressing */
2617 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2618 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2619 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002620
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2622 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002623 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2624 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
2626 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2627 ioc->name, &ioc_init));
2628
2629 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2630 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002631 if (r != 0) {
2632 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
2636 /* No need to byte swap the multibyte fields in the reply
2637 * since we don't even look at it's contents.
2638 */
2639
2640 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2641 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002642
2643 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2644 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647
2648 /* YIKES! SUPER IMPORTANT!!!
2649 * Poll IocState until _OPERATIONAL while IOC is doing
2650 * LoopInit and TargetDiscovery!
2651 */
2652 count = 0;
2653 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2654 state = mpt_GetIocState(ioc, 1);
2655 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2656 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002657 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 } else {
2659 mdelay(1);
2660 }
2661
2662 if (!cntdn) {
2663 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2664 ioc->name, (int)((count+5)/HZ));
2665 return -9;
2666 }
2667
2668 state = mpt_GetIocState(ioc, 1);
2669 count++;
2670 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002671 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 ioc->name, count));
2673
2674 return r;
2675}
2676
2677/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2678/*
2679 * SendPortEnable - Send PortEnable request to MPT adapter port.
2680 * @ioc: Pointer to MPT_ADAPTER structure
2681 * @portnum: Port number to enable
2682 * @sleepFlag: Specifies whether the process can sleep
2683 *
2684 * Send PortEnable to bring IOC to OPERATIONAL state.
2685 *
2686 * Returns 0 for success, non-zero for failure.
2687 */
2688static int
2689SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2690{
2691 PortEnable_t port_enable;
2692 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002693 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 int req_sz;
2695 int reply_sz;
2696
2697 /* Destination... */
2698 reply_sz = sizeof(MPIDefaultReply_t);
2699 memset(&reply_buf, 0, reply_sz);
2700
2701 req_sz = sizeof(PortEnable_t);
2702 memset(&port_enable, 0, req_sz);
2703
2704 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2705 port_enable.PortNumber = portnum;
2706/* port_enable.ChainOffset = 0; */
2707/* port_enable.MsgFlags = 0; */
2708/* port_enable.MsgContext = 0; */
2709
2710 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2711 ioc->name, portnum, &port_enable));
2712
2713 /* RAID FW may take a long time to enable
2714 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002715 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2716 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2717 (ioc->bus_type == SAS)) {
2718 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2719 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2720 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002721 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002722 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2723 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2724 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002726 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727}
2728
2729/*
2730 * ioc: Pointer to MPT_ADAPTER structure
2731 * size - total FW bytes
2732 */
2733void
2734mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2735{
2736 if (ioc->cached_fw)
2737 return; /* use already allocated memory */
2738 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2739 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2740 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2741 } 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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-09-09 16:25:54 +02002928 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 }
2930 }
2931
2932 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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{
3170 u32 diag0val;
3171 u32 doorbell;
3172 int hard_reset_done = 0;
3173 int count = 0;
3174#ifdef MPT_DEBUG
3175 u32 diag1val = 0;
3176#endif
3177
Eric Moore87cf8982006-06-27 16:09:26 -06003178 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
3179 drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
3180 "address=%p\n", ioc->name, __FUNCTION__,
3181 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3182 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3183 if (sleepFlag == CAN_SLEEP)
3184 msleep(1);
3185 else
3186 mdelay(1);
3187
3188 for (count = 0; count < 60; count ++) {
3189 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3190 doorbell &= MPI_IOC_STATE_MASK;
3191
3192 drsprintk((MYIOC_s_INFO_FMT
3193 "looking for READY STATE: doorbell=%x"
3194 " count=%d\n",
3195 ioc->name, doorbell, count));
3196 if (doorbell == MPI_IOC_STATE_READY) {
3197 return 0;
3198 }
3199
3200 /* wait 1 sec */
3201 if (sleepFlag == CAN_SLEEP)
3202 msleep(1000);
3203 else
3204 mdelay(1000);
3205 }
3206 return -1;
3207 }
3208
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 /* Clear any existing interrupts */
3210 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3211
3212 /* Use "Diagnostic reset" method! (only thing available!) */
3213 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3214
3215#ifdef MPT_DEBUG
3216 if (ioc->alt_ioc)
3217 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3218 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3219 ioc->name, diag0val, diag1val));
3220#endif
3221
3222 /* Do the reset if we are told to ignore the reset history
3223 * or if the reset history is 0
3224 */
3225 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3226 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3227 /* Write magic sequence to WriteSequence register
3228 * Loop until in diagnostic mode
3229 */
3230 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3231 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3232 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3233 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3234 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3235 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3236
3237 /* wait 100 msec */
3238 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003239 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 } else {
3241 mdelay (100);
3242 }
3243
3244 count++;
3245 if (count > 20) {
3246 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3247 ioc->name, diag0val);
3248 return -2;
3249
3250 }
3251
3252 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3253
3254 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3255 ioc->name, diag0val));
3256 }
3257
3258#ifdef MPT_DEBUG
3259 if (ioc->alt_ioc)
3260 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3261 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3262 ioc->name, diag0val, diag1val));
3263#endif
3264 /*
3265 * Disable the ARM (Bug fix)
3266 *
3267 */
3268 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003269 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270
3271 /*
3272 * Now hit the reset bit in the Diagnostic register
3273 * (THE BIG HAMMER!) (Clears DRWE bit).
3274 */
3275 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3276 hard_reset_done = 1;
3277 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3278 ioc->name));
3279
3280 /*
3281 * Call each currently registered protocol IOC reset handler
3282 * with pre-reset indication.
3283 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3284 * MptResetHandlers[] registered yet.
3285 */
3286 {
3287 int ii;
3288 int r = 0;
3289
3290 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3291 if (MptResetHandlers[ii]) {
3292 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3293 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003294 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 if (ioc->alt_ioc) {
3296 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3297 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003298 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 }
3300 }
3301 }
3302 /* FIXME? Examine results here? */
3303 }
3304
3305 if (ioc->cached_fw) {
3306 /* If the DownloadBoot operation fails, the
3307 * IOC will be left unusable. This is a fatal error
3308 * case. _diag_reset will return < 0
3309 */
3310 for (count = 0; count < 30; count ++) {
3311 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3312 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3313 break;
3314 }
3315
3316 /* wait 1 sec */
3317 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003318 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 } else {
3320 mdelay (1000);
3321 }
3322 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003323 if ((count = mpt_downloadboot(ioc,
3324 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 printk(KERN_WARNING MYNAM
3326 ": firmware downloadboot failure (%d)!\n", count);
3327 }
3328
3329 } else {
3330 /* Wait for FW to reload and for board
3331 * to go to the READY state.
3332 * Maximum wait is 60 seconds.
3333 * If fail, no error will check again
3334 * with calling program.
3335 */
3336 for (count = 0; count < 60; count ++) {
3337 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3338 doorbell &= MPI_IOC_STATE_MASK;
3339
3340 if (doorbell == MPI_IOC_STATE_READY) {
3341 break;
3342 }
3343
3344 /* wait 1 sec */
3345 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003346 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 } else {
3348 mdelay (1000);
3349 }
3350 }
3351 }
3352 }
3353
3354 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3355#ifdef MPT_DEBUG
3356 if (ioc->alt_ioc)
3357 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3358 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3359 ioc->name, diag0val, diag1val));
3360#endif
3361
3362 /* Clear RESET_HISTORY bit! Place board in the
3363 * diagnostic mode to update the diag register.
3364 */
3365 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3366 count = 0;
3367 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3368 /* Write magic sequence to WriteSequence register
3369 * Loop until in diagnostic mode
3370 */
3371 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3372 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3373 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3374 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3375 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3376 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3377
3378 /* wait 100 msec */
3379 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003380 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 } else {
3382 mdelay (100);
3383 }
3384
3385 count++;
3386 if (count > 20) {
3387 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3388 ioc->name, diag0val);
3389 break;
3390 }
3391 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3392 }
3393 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3394 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3395 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3396 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3397 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3398 ioc->name);
3399 }
3400
3401 /* Disable Diagnostic Mode
3402 */
3403 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3404
3405 /* Check FW reload status flags.
3406 */
3407 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3408 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3409 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3410 ioc->name, diag0val);
3411 return -3;
3412 }
3413
3414#ifdef MPT_DEBUG
3415 if (ioc->alt_ioc)
3416 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3417 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3418 ioc->name, diag0val, diag1val));
3419#endif
3420
3421 /*
3422 * Reset flag that says we've enabled event notification
3423 */
3424 ioc->facts.EventState = 0;
3425
3426 if (ioc->alt_ioc)
3427 ioc->alt_ioc->facts.EventState = 0;
3428
3429 return hard_reset_done;
3430}
3431
3432/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3433/*
3434 * SendIocReset - Send IOCReset request to MPT adapter.
3435 * @ioc: Pointer to MPT_ADAPTER structure
3436 * @reset_type: reset type, expected values are
3437 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3438 *
3439 * Send IOCReset request to the MPT adapter.
3440 *
3441 * Returns 0 for success, non-zero for failure.
3442 */
3443static int
3444SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3445{
3446 int r;
3447 u32 state;
3448 int cntdn, count;
3449
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003450 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 ioc->name, reset_type));
3452 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3453 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3454 return r;
3455
3456 /* FW ACK'd request, wait for READY state
3457 */
3458 count = 0;
3459 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3460
3461 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3462 cntdn--;
3463 count++;
3464 if (!cntdn) {
3465 if (sleepFlag != CAN_SLEEP)
3466 count *= 10;
3467
3468 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3469 ioc->name, (int)((count+5)/HZ));
3470 return -ETIME;
3471 }
3472
3473 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003474 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 } else {
3476 mdelay (1); /* 1 msec delay */
3477 }
3478 }
3479
3480 /* TODO!
3481 * Cleanup all event stuff for this IOC; re-issue EventNotification
3482 * request if needed.
3483 */
3484 if (ioc->facts.Function)
3485 ioc->facts.EventState = 0;
3486
3487 return 0;
3488}
3489
3490/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3491/*
3492 * initChainBuffers - Allocate memory for and initialize
3493 * chain buffers, chain buffer control arrays and spinlock.
3494 * @hd: Pointer to MPT_SCSI_HOST structure
3495 * @init: If set, initialize the spin lock.
3496 */
3497static int
3498initChainBuffers(MPT_ADAPTER *ioc)
3499{
3500 u8 *mem;
3501 int sz, ii, num_chain;
3502 int scale, num_sge, numSGE;
3503
3504 /* ReqToChain size must equal the req_depth
3505 * index = req_idx
3506 */
3507 if (ioc->ReqToChain == NULL) {
3508 sz = ioc->req_depth * sizeof(int);
3509 mem = kmalloc(sz, GFP_ATOMIC);
3510 if (mem == NULL)
3511 return -1;
3512
3513 ioc->ReqToChain = (int *) mem;
3514 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3515 ioc->name, mem, sz));
3516 mem = kmalloc(sz, GFP_ATOMIC);
3517 if (mem == NULL)
3518 return -1;
3519
3520 ioc->RequestNB = (int *) mem;
3521 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3522 ioc->name, mem, sz));
3523 }
3524 for (ii = 0; ii < ioc->req_depth; ii++) {
3525 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3526 }
3527
3528 /* ChainToChain size must equal the total number
3529 * of chain buffers to be allocated.
3530 * index = chain_idx
3531 *
3532 * Calculate the number of chain buffers needed(plus 1) per I/O
3533 * then multiply the the maximum number of simultaneous cmds
3534 *
3535 * num_sge = num sge in request frame + last chain buffer
3536 * scale = num sge per chain buffer if no chain element
3537 */
3538 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3539 if (sizeof(dma_addr_t) == sizeof(u64))
3540 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3541 else
3542 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3543
3544 if (sizeof(dma_addr_t) == sizeof(u64)) {
3545 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3546 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3547 } else {
3548 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3549 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3550 }
3551 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3552 ioc->name, num_sge, numSGE));
3553
3554 if ( numSGE > MPT_SCSI_SG_DEPTH )
3555 numSGE = MPT_SCSI_SG_DEPTH;
3556
3557 num_chain = 1;
3558 while (numSGE - num_sge > 0) {
3559 num_chain++;
3560 num_sge += (scale - 1);
3561 }
3562 num_chain++;
3563
3564 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3565 ioc->name, numSGE, num_sge, num_chain));
3566
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003567 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 num_chain *= MPT_SCSI_CAN_QUEUE;
3569 else
3570 num_chain *= MPT_FC_CAN_QUEUE;
3571
3572 ioc->num_chain = num_chain;
3573
3574 sz = num_chain * sizeof(int);
3575 if (ioc->ChainToChain == NULL) {
3576 mem = kmalloc(sz, GFP_ATOMIC);
3577 if (mem == NULL)
3578 return -1;
3579
3580 ioc->ChainToChain = (int *) mem;
3581 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3582 ioc->name, mem, sz));
3583 } else {
3584 mem = (u8 *) ioc->ChainToChain;
3585 }
3586 memset(mem, 0xFF, sz);
3587 return num_chain;
3588}
3589
3590/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3591/*
3592 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3593 * @ioc: Pointer to MPT_ADAPTER structure
3594 *
3595 * This routine allocates memory for the MPT reply and request frame
3596 * pools (if necessary), and primes the IOC reply FIFO with
3597 * reply frames.
3598 *
3599 * Returns 0 for success, non-zero for failure.
3600 */
3601static int
3602PrimeIocFifos(MPT_ADAPTER *ioc)
3603{
3604 MPT_FRAME_HDR *mf;
3605 unsigned long flags;
3606 dma_addr_t alloc_dma;
3607 u8 *mem;
3608 int i, reply_sz, sz, total_size, num_chain;
3609
3610 /* Prime reply FIFO... */
3611
3612 if (ioc->reply_frames == NULL) {
3613 if ( (num_chain = initChainBuffers(ioc)) < 0)
3614 return -1;
3615
3616 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3617 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3618 ioc->name, ioc->reply_sz, ioc->reply_depth));
3619 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3620 ioc->name, reply_sz, reply_sz));
3621
3622 sz = (ioc->req_sz * ioc->req_depth);
3623 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3624 ioc->name, ioc->req_sz, ioc->req_depth));
3625 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3626 ioc->name, sz, sz));
3627 total_size += sz;
3628
3629 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3630 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3631 ioc->name, ioc->req_sz, num_chain));
3632 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3633 ioc->name, sz, sz, num_chain));
3634
3635 total_size += sz;
3636 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3637 if (mem == NULL) {
3638 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3639 ioc->name);
3640 goto out_fail;
3641 }
3642
3643 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3644 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3645
3646 memset(mem, 0, total_size);
3647 ioc->alloc_total += total_size;
3648 ioc->alloc = mem;
3649 ioc->alloc_dma = alloc_dma;
3650 ioc->alloc_sz = total_size;
3651 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3652 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3653
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003654 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3655 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3656
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 alloc_dma += reply_sz;
3658 mem += reply_sz;
3659
3660 /* Request FIFO - WE manage this! */
3661
3662 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3663 ioc->req_frames_dma = alloc_dma;
3664
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003665 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 ioc->name, mem, (void *)(ulong)alloc_dma));
3667
3668 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3669
3670#if defined(CONFIG_MTRR) && 0
3671 /*
3672 * Enable Write Combining MTRR for IOC's memory region.
3673 * (at least as much as we can; "size and base must be
3674 * multiples of 4 kiB"
3675 */
3676 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3677 sz,
3678 MTRR_TYPE_WRCOMB, 1);
3679 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3680 ioc->name, ioc->req_frames_dma, sz));
3681#endif
3682
3683 for (i = 0; i < ioc->req_depth; i++) {
3684 alloc_dma += ioc->req_sz;
3685 mem += ioc->req_sz;
3686 }
3687
3688 ioc->ChainBuffer = mem;
3689 ioc->ChainBufferDMA = alloc_dma;
3690
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003691 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3693
3694 /* Initialize the free chain Q.
3695 */
3696
3697 INIT_LIST_HEAD(&ioc->FreeChainQ);
3698
3699 /* Post the chain buffers to the FreeChainQ.
3700 */
3701 mem = (u8 *)ioc->ChainBuffer;
3702 for (i=0; i < num_chain; i++) {
3703 mf = (MPT_FRAME_HDR *) mem;
3704 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3705 mem += ioc->req_sz;
3706 }
3707
3708 /* Initialize Request frames linked list
3709 */
3710 alloc_dma = ioc->req_frames_dma;
3711 mem = (u8 *) ioc->req_frames;
3712
3713 spin_lock_irqsave(&ioc->FreeQlock, flags);
3714 INIT_LIST_HEAD(&ioc->FreeQ);
3715 for (i = 0; i < ioc->req_depth; i++) {
3716 mf = (MPT_FRAME_HDR *) mem;
3717
3718 /* Queue REQUESTs *internally*! */
3719 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3720
3721 mem += ioc->req_sz;
3722 }
3723 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3724
3725 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3726 ioc->sense_buf_pool =
3727 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3728 if (ioc->sense_buf_pool == NULL) {
3729 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3730 ioc->name);
3731 goto out_fail;
3732 }
3733
3734 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3735 ioc->alloc_total += sz;
3736 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3737 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3738
3739 }
3740
3741 /* Post Reply frames to FIFO
3742 */
3743 alloc_dma = ioc->alloc_dma;
3744 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3745 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3746
3747 for (i = 0; i < ioc->reply_depth; i++) {
3748 /* Write each address to the IOC! */
3749 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3750 alloc_dma += ioc->reply_sz;
3751 }
3752
3753 return 0;
3754
3755out_fail:
3756 if (ioc->alloc != NULL) {
3757 sz = ioc->alloc_sz;
3758 pci_free_consistent(ioc->pcidev,
3759 sz,
3760 ioc->alloc, ioc->alloc_dma);
3761 ioc->reply_frames = NULL;
3762 ioc->req_frames = NULL;
3763 ioc->alloc_total -= sz;
3764 }
3765 if (ioc->sense_buf_pool != NULL) {
3766 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3767 pci_free_consistent(ioc->pcidev,
3768 sz,
3769 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3770 ioc->sense_buf_pool = NULL;
3771 }
3772 return -1;
3773}
3774
3775/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3776/**
3777 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3778 * from IOC via doorbell handshake method.
3779 * @ioc: Pointer to MPT_ADAPTER structure
3780 * @reqBytes: Size of the request in bytes
3781 * @req: Pointer to MPT request frame
3782 * @replyBytes: Expected size of the reply in bytes
3783 * @u16reply: Pointer to area where reply should be written
3784 * @maxwait: Max wait time for a reply (in seconds)
3785 * @sleepFlag: Specifies whether the process can sleep
3786 *
3787 * NOTES: It is the callers responsibility to byte-swap fields in the
3788 * request which are greater than 1 byte in size. It is also the
3789 * callers responsibility to byte-swap response fields which are
3790 * greater than 1 byte in size.
3791 *
3792 * Returns 0 for success, non-zero for failure.
3793 */
3794static int
3795mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003796 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797{
3798 MPIDefaultReply_t *mptReply;
3799 int failcnt = 0;
3800 int t;
3801
3802 /*
3803 * Get ready to cache a handshake reply
3804 */
3805 ioc->hs_reply_idx = 0;
3806 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3807 mptReply->MsgLength = 0;
3808
3809 /*
3810 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3811 * then tell IOC that we want to handshake a request of N words.
3812 * (WRITE u32val to Doorbell reg).
3813 */
3814 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3815 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3816 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3817 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3818
3819 /*
3820 * Wait for IOC's doorbell handshake int
3821 */
3822 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3823 failcnt++;
3824
3825 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3826 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3827
3828 /* Read doorbell and check for active bit */
3829 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3830 return -1;
3831
3832 /*
3833 * Clear doorbell int (WRITE 0 to IntStatus reg),
3834 * then wait for IOC to ACKnowledge that it's ready for
3835 * our handshake request.
3836 */
3837 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3838 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3839 failcnt++;
3840
3841 if (!failcnt) {
3842 int ii;
3843 u8 *req_as_bytes = (u8 *) req;
3844
3845 /*
3846 * Stuff request words via doorbell handshake,
3847 * with ACK from IOC for each.
3848 */
3849 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3850 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3851 (req_as_bytes[(ii*4) + 1] << 8) |
3852 (req_as_bytes[(ii*4) + 2] << 16) |
3853 (req_as_bytes[(ii*4) + 3] << 24));
3854
3855 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3856 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3857 failcnt++;
3858 }
3859
3860 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3861 DBG_DUMP_REQUEST_FRAME_HDR(req)
3862
3863 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3864 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3865
3866 /*
3867 * Wait for completion of doorbell handshake reply from the IOC
3868 */
3869 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3870 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003871
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3873 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3874
3875 /*
3876 * Copy out the cached reply...
3877 */
3878 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3879 u16reply[ii] = ioc->hs_reply[ii];
3880 } else {
3881 return -99;
3882 }
3883
3884 return -failcnt;
3885}
3886
3887/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3888/*
3889 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3890 * in it's IntStatus register.
3891 * @ioc: Pointer to MPT_ADAPTER structure
3892 * @howlong: How long to wait (in seconds)
3893 * @sleepFlag: Specifies whether the process can sleep
3894 *
3895 * This routine waits (up to ~2 seconds max) for IOC doorbell
3896 * handshake ACKnowledge.
3897 *
3898 * Returns a negative value on failure, else wait loop count.
3899 */
3900static int
3901WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3902{
3903 int cntdn;
3904 int count = 0;
3905 u32 intstat=0;
3906
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003907 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
3909 if (sleepFlag == CAN_SLEEP) {
3910 while (--cntdn) {
3911 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3912 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3913 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05003914 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 count++;
3916 }
3917 } else {
3918 while (--cntdn) {
3919 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3920 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3921 break;
3922 mdelay (1);
3923 count++;
3924 }
3925 }
3926
3927 if (cntdn) {
3928 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3929 ioc->name, count));
3930 return count;
3931 }
3932
3933 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3934 ioc->name, count, intstat);
3935 return -1;
3936}
3937
3938/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3939/*
3940 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3941 * in it's IntStatus register.
3942 * @ioc: Pointer to MPT_ADAPTER structure
3943 * @howlong: How long to wait (in seconds)
3944 * @sleepFlag: Specifies whether the process can sleep
3945 *
3946 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3947 *
3948 * Returns a negative value on failure, else wait loop count.
3949 */
3950static int
3951WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3952{
3953 int cntdn;
3954 int count = 0;
3955 u32 intstat=0;
3956
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003957 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 if (sleepFlag == CAN_SLEEP) {
3959 while (--cntdn) {
3960 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3961 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3962 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05003963 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 count++;
3965 }
3966 } else {
3967 while (--cntdn) {
3968 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3969 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3970 break;
3971 mdelay(1);
3972 count++;
3973 }
3974 }
3975
3976 if (cntdn) {
3977 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3978 ioc->name, count, howlong));
3979 return count;
3980 }
3981
3982 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3983 ioc->name, count, intstat);
3984 return -1;
3985}
3986
3987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3988/*
3989 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3990 * @ioc: Pointer to MPT_ADAPTER structure
3991 * @howlong: How long to wait (in seconds)
3992 * @sleepFlag: Specifies whether the process can sleep
3993 *
3994 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3995 * Reply is cached to IOC private area large enough to hold a maximum
3996 * of 128 bytes of reply data.
3997 *
3998 * Returns a negative value on failure, else size of reply in WORDS.
3999 */
4000static int
4001WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4002{
4003 int u16cnt = 0;
4004 int failcnt = 0;
4005 int t;
4006 u16 *hs_reply = ioc->hs_reply;
4007 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4008 u16 hword;
4009
4010 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4011
4012 /*
4013 * Get first two u16's so we can look at IOC's intended reply MsgLength
4014 */
4015 u16cnt=0;
4016 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4017 failcnt++;
4018 } else {
4019 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4020 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4021 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4022 failcnt++;
4023 else {
4024 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4025 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4026 }
4027 }
4028
4029 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004030 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4032
4033 /*
4034 * If no error (and IOC said MsgLength is > 0), piece together
4035 * reply 16 bits at a time.
4036 */
4037 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4038 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4039 failcnt++;
4040 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4041 /* don't overflow our IOC hs_reply[] buffer! */
4042 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4043 hs_reply[u16cnt] = hword;
4044 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4045 }
4046
4047 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4048 failcnt++;
4049 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4050
4051 if (failcnt) {
4052 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4053 ioc->name);
4054 return -failcnt;
4055 }
4056#if 0
4057 else if (u16cnt != (2 * mptReply->MsgLength)) {
4058 return -101;
4059 }
4060 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4061 return -102;
4062 }
4063#endif
4064
4065 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4066 DBG_DUMP_REPLY_FRAME(mptReply)
4067
4068 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4069 ioc->name, t, u16cnt/2));
4070 return u16cnt/2;
4071}
4072
4073/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4074/*
4075 * GetLanConfigPages - Fetch LANConfig pages.
4076 * @ioc: Pointer to MPT_ADAPTER structure
4077 *
4078 * Return: 0 for success
4079 * -ENOMEM if no memory available
4080 * -EPERM if not allowed due to ISR context
4081 * -EAGAIN if no msg frames currently available
4082 * -EFAULT for non-successful reply or no reply (timeout)
4083 */
4084static int
4085GetLanConfigPages(MPT_ADAPTER *ioc)
4086{
4087 ConfigPageHeader_t hdr;
4088 CONFIGPARMS cfg;
4089 LANPage0_t *ppage0_alloc;
4090 dma_addr_t page0_dma;
4091 LANPage1_t *ppage1_alloc;
4092 dma_addr_t page1_dma;
4093 int rc = 0;
4094 int data_sz;
4095 int copy_sz;
4096
4097 /* Get LAN Page 0 header */
4098 hdr.PageVersion = 0;
4099 hdr.PageLength = 0;
4100 hdr.PageNumber = 0;
4101 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004102 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 cfg.physAddr = -1;
4104 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4105 cfg.dir = 0;
4106 cfg.pageAddr = 0;
4107 cfg.timeout = 0;
4108
4109 if ((rc = mpt_config(ioc, &cfg)) != 0)
4110 return rc;
4111
4112 if (hdr.PageLength > 0) {
4113 data_sz = hdr.PageLength * 4;
4114 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4115 rc = -ENOMEM;
4116 if (ppage0_alloc) {
4117 memset((u8 *)ppage0_alloc, 0, data_sz);
4118 cfg.physAddr = page0_dma;
4119 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4120
4121 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4122 /* save the data */
4123 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4124 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4125
4126 }
4127
4128 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4129
4130 /* FIXME!
4131 * Normalize endianness of structure data,
4132 * by byte-swapping all > 1 byte fields!
4133 */
4134
4135 }
4136
4137 if (rc)
4138 return rc;
4139 }
4140
4141 /* Get LAN Page 1 header */
4142 hdr.PageVersion = 0;
4143 hdr.PageLength = 0;
4144 hdr.PageNumber = 1;
4145 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004146 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 cfg.physAddr = -1;
4148 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4149 cfg.dir = 0;
4150 cfg.pageAddr = 0;
4151
4152 if ((rc = mpt_config(ioc, &cfg)) != 0)
4153 return rc;
4154
4155 if (hdr.PageLength == 0)
4156 return 0;
4157
4158 data_sz = hdr.PageLength * 4;
4159 rc = -ENOMEM;
4160 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4161 if (ppage1_alloc) {
4162 memset((u8 *)ppage1_alloc, 0, data_sz);
4163 cfg.physAddr = page1_dma;
4164 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4165
4166 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4167 /* save the data */
4168 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4169 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4170 }
4171
4172 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4173
4174 /* FIXME!
4175 * Normalize endianness of structure data,
4176 * by byte-swapping all > 1 byte fields!
4177 */
4178
4179 }
4180
4181 return rc;
4182}
4183
4184/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4185/*
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004186 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4187 * @ioc: Pointer to MPT_ADAPTER structure
4188 * @sas_address: 64bit SAS Address for operation.
4189 * @target_id: specified target for operation
4190 * @bus: specified bus for operation
4191 * @persist_opcode: see below
4192 *
4193 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4194 * devices not currently present.
4195 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4196 *
4197 * NOTE: Don't use not this function during interrupt time.
4198 *
4199 * Returns: 0 for success, non-zero error
4200 */
4201
4202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4203int
4204mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4205{
4206 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4207 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4208 MPT_FRAME_HDR *mf = NULL;
4209 MPIHeader_t *mpi_hdr;
4210
4211
4212 /* insure garbage is not sent to fw */
4213 switch(persist_opcode) {
4214
4215 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4216 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4217 break;
4218
4219 default:
4220 return -1;
4221 break;
4222 }
4223
4224 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4225
4226 /* Get a MF for this command.
4227 */
4228 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4229 printk("%s: no msg frames!\n",__FUNCTION__);
4230 return -1;
4231 }
4232
4233 mpi_hdr = (MPIHeader_t *) mf;
4234 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4235 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4236 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4237 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4238 sasIoUnitCntrReq->Operation = persist_opcode;
4239
4240 init_timer(&ioc->persist_timer);
4241 ioc->persist_timer.data = (unsigned long) ioc;
4242 ioc->persist_timer.function = mpt_timer_expired;
4243 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4244 ioc->persist_wait_done=0;
4245 add_timer(&ioc->persist_timer);
4246 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4247 wait_event(mpt_waitq, ioc->persist_wait_done);
4248
4249 sasIoUnitCntrReply =
4250 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4251 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4252 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4253 __FUNCTION__,
4254 sasIoUnitCntrReply->IOCStatus,
4255 sasIoUnitCntrReply->IOCLogInfo);
4256 return -1;
4257 }
4258
4259 printk("%s: success\n",__FUNCTION__);
4260 return 0;
4261}
4262
4263/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004264
4265static void
4266mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4267 MpiEventDataRaid_t * pRaidEventData)
4268{
4269 int volume;
4270 int reason;
4271 int disk;
4272 int status;
4273 int flags;
4274 int state;
4275
4276 volume = pRaidEventData->VolumeID;
4277 reason = pRaidEventData->ReasonCode;
4278 disk = pRaidEventData->PhysDiskNum;
4279 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4280 flags = (status >> 0) & 0xff;
4281 state = (status >> 8) & 0xff;
4282
4283 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4284 return;
4285 }
4286
4287 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4288 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4289 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4290 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4291 ioc->name, disk);
4292 } else {
4293 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4294 ioc->name, volume);
4295 }
4296
4297 switch(reason) {
4298 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4299 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4300 ioc->name);
4301 break;
4302
4303 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4304
4305 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4306 ioc->name);
4307 break;
4308
4309 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4310 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4311 ioc->name);
4312 break;
4313
4314 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4315 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4316 ioc->name,
4317 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4318 ? "optimal"
4319 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4320 ? "degraded"
4321 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4322 ? "failed"
4323 : "state unknown",
4324 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4325 ? ", enabled" : "",
4326 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4327 ? ", quiesced" : "",
4328 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4329 ? ", resync in progress" : "" );
4330 break;
4331
4332 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4333 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4334 ioc->name, disk);
4335 break;
4336
4337 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4338 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4339 ioc->name);
4340 break;
4341
4342 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4343 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4344 ioc->name);
4345 break;
4346
4347 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4348 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4349 ioc->name);
4350 break;
4351
4352 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4353 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4354 ioc->name,
4355 state == MPI_PHYSDISK0_STATUS_ONLINE
4356 ? "online"
4357 : state == MPI_PHYSDISK0_STATUS_MISSING
4358 ? "missing"
4359 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4360 ? "not compatible"
4361 : state == MPI_PHYSDISK0_STATUS_FAILED
4362 ? "failed"
4363 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4364 ? "initializing"
4365 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4366 ? "offline requested"
4367 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4368 ? "failed requested"
4369 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4370 ? "offline"
4371 : "state unknown",
4372 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4373 ? ", out of sync" : "",
4374 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4375 ? ", quiesced" : "" );
4376 break;
4377
4378 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4379 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4380 ioc->name, disk);
4381 break;
4382
4383 case MPI_EVENT_RAID_RC_SMART_DATA:
4384 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4385 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4386 break;
4387
4388 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4389 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4390 ioc->name, disk);
4391 break;
4392 }
4393}
4394
4395/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004396/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4398 * @ioc: Pointer to MPT_ADAPTER structure
4399 *
4400 * Returns: 0 for success
4401 * -ENOMEM if no memory available
4402 * -EPERM if not allowed due to ISR context
4403 * -EAGAIN if no msg frames currently available
4404 * -EFAULT for non-successful reply or no reply (timeout)
4405 */
4406static int
4407GetIoUnitPage2(MPT_ADAPTER *ioc)
4408{
4409 ConfigPageHeader_t hdr;
4410 CONFIGPARMS cfg;
4411 IOUnitPage2_t *ppage_alloc;
4412 dma_addr_t page_dma;
4413 int data_sz;
4414 int rc;
4415
4416 /* Get the page header */
4417 hdr.PageVersion = 0;
4418 hdr.PageLength = 0;
4419 hdr.PageNumber = 2;
4420 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004421 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 cfg.physAddr = -1;
4423 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4424 cfg.dir = 0;
4425 cfg.pageAddr = 0;
4426 cfg.timeout = 0;
4427
4428 if ((rc = mpt_config(ioc, &cfg)) != 0)
4429 return rc;
4430
4431 if (hdr.PageLength == 0)
4432 return 0;
4433
4434 /* Read the config page */
4435 data_sz = hdr.PageLength * 4;
4436 rc = -ENOMEM;
4437 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4438 if (ppage_alloc) {
4439 memset((u8 *)ppage_alloc, 0, data_sz);
4440 cfg.physAddr = page_dma;
4441 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4442
4443 /* If Good, save data */
4444 if ((rc = mpt_config(ioc, &cfg)) == 0)
4445 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4446
4447 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4448 }
4449
4450 return rc;
4451}
4452
4453/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4454/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4455 * @ioc: Pointer to a Adapter Strucutre
4456 * @portnum: IOC port number
4457 *
4458 * Return: -EFAULT if read of config page header fails
4459 * or if no nvram
4460 * If read of SCSI Port Page 0 fails,
4461 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4462 * Adapter settings: async, narrow
4463 * Return 1
4464 * If read of SCSI Port Page 2 fails,
4465 * Adapter settings valid
4466 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4467 * Return 1
4468 * Else
4469 * Both valid
4470 * Return 0
4471 * CHECK - what type of locking mechanisms should be used????
4472 */
4473static int
4474mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4475{
4476 u8 *pbuf;
4477 dma_addr_t buf_dma;
4478 CONFIGPARMS cfg;
4479 ConfigPageHeader_t header;
4480 int ii;
4481 int data, rc = 0;
4482
4483 /* Allocate memory
4484 */
4485 if (!ioc->spi_data.nvram) {
4486 int sz;
4487 u8 *mem;
4488 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4489 mem = kmalloc(sz, GFP_ATOMIC);
4490 if (mem == NULL)
4491 return -EFAULT;
4492
4493 ioc->spi_data.nvram = (int *) mem;
4494
4495 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4496 ioc->name, ioc->spi_data.nvram, sz));
4497 }
4498
4499 /* Invalidate NVRAM information
4500 */
4501 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4502 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4503 }
4504
4505 /* Read SPP0 header, allocate memory, then read page.
4506 */
4507 header.PageVersion = 0;
4508 header.PageLength = 0;
4509 header.PageNumber = 0;
4510 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004511 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 cfg.physAddr = -1;
4513 cfg.pageAddr = portnum;
4514 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4515 cfg.dir = 0;
4516 cfg.timeout = 0; /* use default */
4517 if (mpt_config(ioc, &cfg) != 0)
4518 return -EFAULT;
4519
4520 if (header.PageLength > 0) {
4521 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4522 if (pbuf) {
4523 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4524 cfg.physAddr = buf_dma;
4525 if (mpt_config(ioc, &cfg) != 0) {
4526 ioc->spi_data.maxBusWidth = MPT_NARROW;
4527 ioc->spi_data.maxSyncOffset = 0;
4528 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4529 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4530 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004531 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4532 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 } else {
4534 /* Save the Port Page 0 data
4535 */
4536 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4537 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4538 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4539
4540 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4541 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004542 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 ioc->name, pPP0->Capabilities));
4544 }
4545 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4546 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4547 if (data) {
4548 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4549 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4550 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004551 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4552 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 } else {
4554 ioc->spi_data.maxSyncOffset = 0;
4555 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4556 }
4557
4558 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4559
4560 /* Update the minSyncFactor based on bus type.
4561 */
4562 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4563 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4564
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004565 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004567 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4568 ioc->name, ioc->spi_data.minSyncFactor));
4569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 }
4571 }
4572 if (pbuf) {
4573 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4574 }
4575 }
4576 }
4577
4578 /* SCSI Port Page 2 - Read the header then the page.
4579 */
4580 header.PageVersion = 0;
4581 header.PageLength = 0;
4582 header.PageNumber = 2;
4583 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004584 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 cfg.physAddr = -1;
4586 cfg.pageAddr = portnum;
4587 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4588 cfg.dir = 0;
4589 if (mpt_config(ioc, &cfg) != 0)
4590 return -EFAULT;
4591
4592 if (header.PageLength > 0) {
4593 /* Allocate memory and read SCSI Port Page 2
4594 */
4595 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4596 if (pbuf) {
4597 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4598 cfg.physAddr = buf_dma;
4599 if (mpt_config(ioc, &cfg) != 0) {
4600 /* Nvram data is left with INVALID mark
4601 */
4602 rc = 1;
4603 } else {
4604 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4605 MpiDeviceInfo_t *pdevice = NULL;
4606
Moore, Ericd8e925d2006-01-16 18:53:06 -07004607 /*
4608 * Save "Set to Avoid SCSI Bus Resets" flag
4609 */
4610 ioc->spi_data.bus_reset =
4611 (le32_to_cpu(pPP2->PortFlags) &
4612 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4613 0 : 1 ;
4614
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 /* Save the Port Page 2 data
4616 * (reformat into a 32bit quantity)
4617 */
4618 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4619 ioc->spi_data.PortFlags = data;
4620 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4621 pdevice = &pPP2->DeviceSettings[ii];
4622 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4623 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4624 ioc->spi_data.nvram[ii] = data;
4625 }
4626 }
4627
4628 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4629 }
4630 }
4631
4632 /* Update Adapter limits with those from NVRAM
4633 * Comment: Don't need to do this. Target performance
4634 * parameters will never exceed the adapters limits.
4635 */
4636
4637 return rc;
4638}
4639
4640/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4641/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4642 * @ioc: Pointer to a Adapter Strucutre
4643 * @portnum: IOC port number
4644 *
4645 * Return: -EFAULT if read of config page header fails
4646 * or 0 if success.
4647 */
4648static int
4649mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4650{
4651 CONFIGPARMS cfg;
4652 ConfigPageHeader_t header;
4653
4654 /* Read the SCSI Device Page 1 header
4655 */
4656 header.PageVersion = 0;
4657 header.PageLength = 0;
4658 header.PageNumber = 1;
4659 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004660 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 cfg.physAddr = -1;
4662 cfg.pageAddr = portnum;
4663 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4664 cfg.dir = 0;
4665 cfg.timeout = 0;
4666 if (mpt_config(ioc, &cfg) != 0)
4667 return -EFAULT;
4668
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004669 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4670 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671
4672 header.PageVersion = 0;
4673 header.PageLength = 0;
4674 header.PageNumber = 0;
4675 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4676 if (mpt_config(ioc, &cfg) != 0)
4677 return -EFAULT;
4678
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004679 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4680 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681
4682 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4683 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4684
4685 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4686 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4687 return 0;
4688}
4689
4690/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4691/**
4692 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4693 * @ioc: Pointer to a Adapter Strucutre
4694 * @portnum: IOC port number
4695 *
4696 * Return:
4697 * 0 on success
4698 * -EFAULT if read of config page header fails or data pointer not NULL
4699 * -ENOMEM if pci_alloc failed
4700 */
4701int
4702mpt_findImVolumes(MPT_ADAPTER *ioc)
4703{
4704 IOCPage2_t *pIoc2;
4705 u8 *mem;
4706 ConfigPageIoc2RaidVol_t *pIocRv;
4707 dma_addr_t ioc2_dma;
4708 CONFIGPARMS cfg;
4709 ConfigPageHeader_t header;
4710 int jj;
4711 int rc = 0;
4712 int iocpage2sz;
4713 u8 nVols, nPhys;
4714 u8 vid, vbus, vioc;
4715
4716 /* Read IOCP2 header then the page.
4717 */
4718 header.PageVersion = 0;
4719 header.PageLength = 0;
4720 header.PageNumber = 2;
4721 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004722 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 cfg.physAddr = -1;
4724 cfg.pageAddr = 0;
4725 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4726 cfg.dir = 0;
4727 cfg.timeout = 0;
4728 if (mpt_config(ioc, &cfg) != 0)
4729 return -EFAULT;
4730
4731 if (header.PageLength == 0)
4732 return -EFAULT;
4733
4734 iocpage2sz = header.PageLength * 4;
4735 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4736 if (!pIoc2)
4737 return -ENOMEM;
4738
4739 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4740 cfg.physAddr = ioc2_dma;
4741 if (mpt_config(ioc, &cfg) != 0)
4742 goto done_and_free;
4743
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004744 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4746 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004747 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 } else {
4749 goto done_and_free;
4750 }
4751 }
4752 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4753
4754 /* Identify RAID Volume Id's */
4755 nVols = pIoc2->NumActiveVolumes;
4756 if ( nVols == 0) {
4757 /* No RAID Volume.
4758 */
4759 goto done_and_free;
4760 } else {
4761 /* At least 1 RAID Volume
4762 */
4763 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004764 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4766 vid = pIocRv->VolumeID;
4767 vbus = pIocRv->VolumeBus;
4768 vioc = pIocRv->VolumeIOC;
4769
4770 /* find the match
4771 */
4772 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004773 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 } else {
4775 /* Error! Always bus 0
4776 */
4777 }
4778 }
4779 }
4780
4781 /* Identify Hidden Physical Disk Id's */
4782 nPhys = pIoc2->NumActivePhysDisks;
4783 if (nPhys == 0) {
4784 /* No physical disks.
4785 */
4786 } else {
4787 mpt_read_ioc_pg_3(ioc);
4788 }
4789
4790done_and_free:
4791 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4792
4793 return rc;
4794}
4795
Moore, Ericc972c702006-03-14 09:14:06 -07004796static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4798{
4799 IOCPage3_t *pIoc3;
4800 u8 *mem;
4801 CONFIGPARMS cfg;
4802 ConfigPageHeader_t header;
4803 dma_addr_t ioc3_dma;
4804 int iocpage3sz = 0;
4805
4806 /* Free the old page
4807 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004808 kfree(ioc->raid_data.pIocPg3);
4809 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810
4811 /* There is at least one physical disk.
4812 * Read and save IOC Page 3
4813 */
4814 header.PageVersion = 0;
4815 header.PageLength = 0;
4816 header.PageNumber = 3;
4817 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004818 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 cfg.physAddr = -1;
4820 cfg.pageAddr = 0;
4821 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4822 cfg.dir = 0;
4823 cfg.timeout = 0;
4824 if (mpt_config(ioc, &cfg) != 0)
4825 return 0;
4826
4827 if (header.PageLength == 0)
4828 return 0;
4829
4830 /* Read Header good, alloc memory
4831 */
4832 iocpage3sz = header.PageLength * 4;
4833 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4834 if (!pIoc3)
4835 return 0;
4836
4837 /* Read the Page and save the data
4838 * into malloc'd memory.
4839 */
4840 cfg.physAddr = ioc3_dma;
4841 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4842 if (mpt_config(ioc, &cfg) == 0) {
4843 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4844 if (mem) {
4845 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004846 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 }
4848 }
4849
4850 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4851
4852 return 0;
4853}
4854
4855static void
4856mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4857{
4858 IOCPage4_t *pIoc4;
4859 CONFIGPARMS cfg;
4860 ConfigPageHeader_t header;
4861 dma_addr_t ioc4_dma;
4862 int iocpage4sz;
4863
4864 /* Read and save IOC Page 4
4865 */
4866 header.PageVersion = 0;
4867 header.PageLength = 0;
4868 header.PageNumber = 4;
4869 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004870 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 cfg.physAddr = -1;
4872 cfg.pageAddr = 0;
4873 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4874 cfg.dir = 0;
4875 cfg.timeout = 0;
4876 if (mpt_config(ioc, &cfg) != 0)
4877 return;
4878
4879 if (header.PageLength == 0)
4880 return;
4881
4882 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4883 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4884 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4885 if (!pIoc4)
4886 return;
4887 } else {
4888 ioc4_dma = ioc->spi_data.IocPg4_dma;
4889 iocpage4sz = ioc->spi_data.IocPg4Sz;
4890 }
4891
4892 /* Read the Page into dma memory.
4893 */
4894 cfg.physAddr = ioc4_dma;
4895 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4896 if (mpt_config(ioc, &cfg) == 0) {
4897 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4898 ioc->spi_data.IocPg4_dma = ioc4_dma;
4899 ioc->spi_data.IocPg4Sz = iocpage4sz;
4900 } else {
4901 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4902 ioc->spi_data.pIocPg4 = NULL;
4903 }
4904}
4905
4906static void
4907mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4908{
4909 IOCPage1_t *pIoc1;
4910 CONFIGPARMS cfg;
4911 ConfigPageHeader_t header;
4912 dma_addr_t ioc1_dma;
4913 int iocpage1sz = 0;
4914 u32 tmp;
4915
4916 /* Check the Coalescing Timeout in IOC Page 1
4917 */
4918 header.PageVersion = 0;
4919 header.PageLength = 0;
4920 header.PageNumber = 1;
4921 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004922 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 cfg.physAddr = -1;
4924 cfg.pageAddr = 0;
4925 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4926 cfg.dir = 0;
4927 cfg.timeout = 0;
4928 if (mpt_config(ioc, &cfg) != 0)
4929 return;
4930
4931 if (header.PageLength == 0)
4932 return;
4933
4934 /* Read Header good, alloc memory
4935 */
4936 iocpage1sz = header.PageLength * 4;
4937 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
4938 if (!pIoc1)
4939 return;
4940
4941 /* Read the Page and check coalescing timeout
4942 */
4943 cfg.physAddr = ioc1_dma;
4944 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4945 if (mpt_config(ioc, &cfg) == 0) {
4946
4947 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
4948 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
4949 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
4950
4951 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
4952 ioc->name, tmp));
4953
4954 if (tmp > MPT_COALESCING_TIMEOUT) {
4955 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
4956
4957 /* Write NVRAM and current
4958 */
4959 cfg.dir = 1;
4960 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4961 if (mpt_config(ioc, &cfg) == 0) {
4962 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
4963 ioc->name, MPT_COALESCING_TIMEOUT));
4964
4965 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
4966 if (mpt_config(ioc, &cfg) == 0) {
4967 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
4968 ioc->name, MPT_COALESCING_TIMEOUT));
4969 } else {
4970 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
4971 ioc->name));
4972 }
4973
4974 } else {
4975 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
4976 ioc->name));
4977 }
4978 }
4979
4980 } else {
4981 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
4982 }
4983 }
4984
4985 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
4986
4987 return;
4988}
4989
4990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4991/*
4992 * SendEventNotification - Send EventNotification (on or off) request
4993 * to MPT adapter.
4994 * @ioc: Pointer to MPT_ADAPTER structure
4995 * @EvSwitch: Event switch flags
4996 */
4997static int
4998SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
4999{
5000 EventNotification_t *evnp;
5001
5002 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5003 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005004 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005 ioc->name));
5006 return 0;
5007 }
5008 memset(evnp, 0, sizeof(*evnp));
5009
Moore, Eric3a892be2006-03-14 09:14:03 -07005010 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011
5012 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5013 evnp->ChainOffset = 0;
5014 evnp->MsgFlags = 0;
5015 evnp->Switch = EvSwitch;
5016
5017 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5018
5019 return 0;
5020}
5021
5022/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5023/**
5024 * SendEventAck - Send EventAck request to MPT adapter.
5025 * @ioc: Pointer to MPT_ADAPTER structure
5026 * @evnp: Pointer to original EventNotification request
5027 */
5028static int
5029SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5030{
5031 EventAck_t *pAck;
5032
5033 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005034 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5035 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5036 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5037 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 return -1;
5039 }
5040 memset(pAck, 0, sizeof(*pAck));
5041
5042 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5043
5044 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5045 pAck->ChainOffset = 0;
5046 pAck->MsgFlags = 0;
5047 pAck->Event = evnp->Event;
5048 pAck->EventContext = evnp->EventContext;
5049
5050 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5051
5052 return 0;
5053}
5054
5055/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5056/**
5057 * mpt_config - Generic function to issue config message
5058 * @ioc - Pointer to an adapter structure
5059 * @cfg - Pointer to a configuration structure. Struct contains
5060 * action, page address, direction, physical address
5061 * and pointer to a configuration page header
5062 * Page header is updated.
5063 *
5064 * Returns 0 for success
5065 * -EPERM if not allowed due to ISR context
5066 * -EAGAIN if no msg frames currently available
5067 * -EFAULT for non-successful reply or no reply (timeout)
5068 */
5069int
5070mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5071{
5072 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005073 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 MPT_FRAME_HDR *mf;
5075 unsigned long flags;
5076 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005077 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 int in_isr;
5079
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005080 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 * to be in ISR context, because that is fatal!
5082 */
5083 in_isr = in_interrupt();
5084 if (in_isr) {
5085 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5086 ioc->name));
5087 return -EPERM;
5088 }
5089
5090 /* Get and Populate a free Frame
5091 */
5092 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5093 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5094 ioc->name));
5095 return -EAGAIN;
5096 }
5097 pReq = (Config_t *)mf;
5098 pReq->Action = pCfg->action;
5099 pReq->Reserved = 0;
5100 pReq->ChainOffset = 0;
5101 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005102
5103 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 pReq->ExtPageLength = 0;
5105 pReq->ExtPageType = 0;
5106 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005107
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 for (ii=0; ii < 8; ii++)
5109 pReq->Reserved2[ii] = 0;
5110
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005111 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5112 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5113 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5114 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5115
5116 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5117 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5118 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5119 pReq->ExtPageType = pExtHdr->ExtPageType;
5120 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5121
5122 /* Page Length must be treated as a reserved field for the extended header. */
5123 pReq->Header.PageLength = 0;
5124 }
5125
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5127
5128 /* Add a SGE to the config request.
5129 */
5130 if (pCfg->dir)
5131 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5132 else
5133 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5134
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005135 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5136 flagsLength |= pExtHdr->ExtPageLength * 4;
5137
5138 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5139 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5140 }
5141 else {
5142 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5143
5144 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5145 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147
5148 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5149
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 /* Append pCfg pointer to end of mf
5151 */
5152 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5153
5154 /* Initalize the timer
5155 */
5156 init_timer(&pCfg->timer);
5157 pCfg->timer.data = (unsigned long) ioc;
5158 pCfg->timer.function = mpt_timer_expired;
5159 pCfg->wait_done = 0;
5160
5161 /* Set the timer; ensure 10 second minimum */
5162 if (pCfg->timeout < 10)
5163 pCfg->timer.expires = jiffies + HZ*10;
5164 else
5165 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5166
5167 /* Add to end of Q, set timer and then issue this command */
5168 spin_lock_irqsave(&ioc->FreeQlock, flags);
5169 list_add_tail(&pCfg->linkage, &ioc->configQ);
5170 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5171
5172 add_timer(&pCfg->timer);
5173 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5174 wait_event(mpt_waitq, pCfg->wait_done);
5175
5176 /* mf has been freed - do not access */
5177
5178 rc = pCfg->status;
5179
5180 return rc;
5181}
5182
5183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184/*
5185 * mpt_timer_expired - Call back for timer process.
5186 * Used only internal config functionality.
5187 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5188 */
5189static void
5190mpt_timer_expired(unsigned long data)
5191{
5192 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5193
5194 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5195
5196 /* Perform a FW reload */
5197 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5198 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5199
5200 /* No more processing.
5201 * Hard reset clean-up will wake up
5202 * process and free all resources.
5203 */
5204 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5205
5206 return;
5207}
5208
5209/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5210/*
5211 * mpt_ioc_reset - Base cleanup for hard reset
5212 * @ioc: Pointer to the adapter structure
5213 * @reset_phase: Indicates pre- or post-reset functionality
5214 *
5215 * Remark: Free's resources with internally generated commands.
5216 */
5217static int
5218mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5219{
5220 CONFIGPARMS *pCfg;
5221 unsigned long flags;
5222
5223 dprintk((KERN_WARNING MYNAM
5224 ": IOC %s_reset routed to MPT base driver!\n",
5225 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5226 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5227
5228 if (reset_phase == MPT_IOC_SETUP_RESET) {
5229 ;
5230 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5231 /* If the internal config Q is not empty -
5232 * delete timer. MF resources will be freed when
5233 * the FIFO's are primed.
5234 */
5235 spin_lock_irqsave(&ioc->FreeQlock, flags);
5236 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5237 del_timer(&pCfg->timer);
5238 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5239
5240 } else {
5241 CONFIGPARMS *pNext;
5242
5243 /* Search the configQ for internal commands.
5244 * Flush the Q, and wake up all suspended threads.
5245 */
5246 spin_lock_irqsave(&ioc->FreeQlock, flags);
5247 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5248 list_del(&pCfg->linkage);
5249
5250 pCfg->status = MPT_CONFIG_ERROR;
5251 pCfg->wait_done = 1;
5252 wake_up(&mpt_waitq);
5253 }
5254 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5255 }
5256
5257 return 1; /* currently means nothing really */
5258}
5259
5260
5261#ifdef CONFIG_PROC_FS /* { */
5262/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5263/*
5264 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5265 */
5266/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5267/*
5268 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5269 *
5270 * Returns 0 for success, non-zero for failure.
5271 */
5272static int
5273procmpt_create(void)
5274{
5275 struct proc_dir_entry *ent;
5276
5277 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5278 if (mpt_proc_root_dir == NULL)
5279 return -ENOTDIR;
5280
5281 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5282 if (ent)
5283 ent->read_proc = procmpt_summary_read;
5284
5285 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5286 if (ent)
5287 ent->read_proc = procmpt_version_read;
5288
5289 return 0;
5290}
5291
5292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5293/*
5294 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5295 *
5296 * Returns 0 for success, non-zero for failure.
5297 */
5298static void
5299procmpt_destroy(void)
5300{
5301 remove_proc_entry("version", mpt_proc_root_dir);
5302 remove_proc_entry("summary", mpt_proc_root_dir);
5303 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5304}
5305
5306/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5307/*
5308 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5309 * or from /proc/mpt/iocN/summary.
5310 * @buf: Pointer to area to write information
5311 * @start: Pointer to start pointer
5312 * @offset: Offset to start writing
5313 * @request:
5314 * @eof: Pointer to EOF integer
5315 * @data: Pointer
5316 *
5317 * Returns number of characters written to process performing the read.
5318 */
5319static int
5320procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5321{
5322 MPT_ADAPTER *ioc;
5323 char *out = buf;
5324 int len;
5325
5326 if (data) {
5327 int more = 0;
5328
5329 ioc = data;
5330 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5331
5332 out += more;
5333 } else {
5334 list_for_each_entry(ioc, &ioc_list, list) {
5335 int more = 0;
5336
5337 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5338
5339 out += more;
5340 if ((out-buf) >= request)
5341 break;
5342 }
5343 }
5344
5345 len = out - buf;
5346
5347 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5348}
5349
5350/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5351/*
5352 * procmpt_version_read - Handle read request from /proc/mpt/version.
5353 * @buf: Pointer to area to write information
5354 * @start: Pointer to start pointer
5355 * @offset: Offset to start writing
5356 * @request:
5357 * @eof: Pointer to EOF integer
5358 * @data: Pointer
5359 *
5360 * Returns number of characters written to process performing the read.
5361 */
5362static int
5363procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5364{
5365 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005366 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 char *drvname;
5368 int len;
5369
5370 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5371 len += sprintf(buf+len, " Fusion MPT base driver\n");
5372
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005373 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5375 drvname = NULL;
5376 if (MptCallbacks[ii]) {
5377 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005378 case MPTSPI_DRIVER:
5379 if (!scsi++) drvname = "SPI host";
5380 break;
5381 case MPTFC_DRIVER:
5382 if (!fc++) drvname = "FC host";
5383 break;
5384 case MPTSAS_DRIVER:
5385 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 break;
5387 case MPTLAN_DRIVER:
5388 if (!lan++) drvname = "LAN";
5389 break;
5390 case MPTSTM_DRIVER:
5391 if (!targ++) drvname = "SCSI target";
5392 break;
5393 case MPTCTL_DRIVER:
5394 if (!ctl++) drvname = "ioctl";
5395 break;
5396 }
5397
5398 if (drvname)
5399 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5400 }
5401 }
5402
5403 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5404}
5405
5406/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5407/*
5408 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5409 * @buf: Pointer to area to write information
5410 * @start: Pointer to start pointer
5411 * @offset: Offset to start writing
5412 * @request:
5413 * @eof: Pointer to EOF integer
5414 * @data: Pointer
5415 *
5416 * Returns number of characters written to process performing the read.
5417 */
5418static int
5419procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5420{
5421 MPT_ADAPTER *ioc = data;
5422 int len;
5423 char expVer[32];
5424 int sz;
5425 int p;
5426
5427 mpt_get_fw_exp_ver(expVer, ioc);
5428
5429 len = sprintf(buf, "%s:", ioc->name);
5430 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5431 len += sprintf(buf+len, " (f/w download boot flag set)");
5432// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5433// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5434
5435 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5436 ioc->facts.ProductID,
5437 ioc->prod_name);
5438 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5439 if (ioc->facts.FWImageSize)
5440 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5441 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5442 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5443 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5444
5445 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5446 ioc->facts.CurrentHostMfaHighAddr);
5447 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5448 ioc->facts.CurrentSenseBufferHighAddr);
5449
5450 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5451 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5452
5453 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5454 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5455 /*
5456 * Rounding UP to nearest 4-kB boundary here...
5457 */
5458 sz = (ioc->req_sz * ioc->req_depth) + 128;
5459 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5460 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5461 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5462 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5463 4*ioc->facts.RequestFrameSize,
5464 ioc->facts.GlobalCredits);
5465
5466 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5467 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5468 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5469 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5470 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5471 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5472 ioc->facts.CurReplyFrameSize,
5473 ioc->facts.ReplyQueueDepth);
5474
5475 len += sprintf(buf+len, " MaxDevices = %d\n",
5476 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5477 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5478
5479 /* per-port info */
5480 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5481 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5482 p+1,
5483 ioc->facts.NumberOfPorts);
5484 if (ioc->bus_type == FC) {
5485 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5486 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5487 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5488 a[5], a[4], a[3], a[2], a[1], a[0]);
5489 }
5490 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5491 ioc->fc_port_page0[p].WWNN.High,
5492 ioc->fc_port_page0[p].WWNN.Low,
5493 ioc->fc_port_page0[p].WWPN.High,
5494 ioc->fc_port_page0[p].WWPN.Low);
5495 }
5496 }
5497
5498 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5499}
5500
5501#endif /* CONFIG_PROC_FS } */
5502
5503/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5504static void
5505mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5506{
5507 buf[0] ='\0';
5508 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5509 sprintf(buf, " (Exp %02d%02d)",
5510 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5511 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5512
5513 /* insider hack! */
5514 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5515 strcat(buf, " [MDBG]");
5516 }
5517}
5518
5519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5520/**
5521 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5522 * @ioc: Pointer to MPT_ADAPTER structure
5523 * @buffer: Pointer to buffer where IOC summary info should be written
5524 * @size: Pointer to number of bytes we wrote (set by this routine)
5525 * @len: Offset at which to start writing in buffer
5526 * @showlan: Display LAN stuff?
5527 *
5528 * This routine writes (english readable) ASCII text, which represents
5529 * a summary of IOC information, to a buffer.
5530 */
5531void
5532mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5533{
5534 char expVer[32];
5535 int y;
5536
5537 mpt_get_fw_exp_ver(expVer, ioc);
5538
5539 /*
5540 * Shorter summary of attached ioc's...
5541 */
5542 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5543 ioc->name,
5544 ioc->prod_name,
5545 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5546 ioc->facts.FWVersion.Word,
5547 expVer,
5548 ioc->facts.NumberOfPorts,
5549 ioc->req_depth);
5550
5551 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5552 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5553 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5554 a[5], a[4], a[3], a[2], a[1], a[0]);
5555 }
5556
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558
5559 if (!ioc->active)
5560 y += sprintf(buffer+len+y, " (disabled)");
5561
5562 y += sprintf(buffer+len+y, "\n");
5563
5564 *size = y;
5565}
5566
5567/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5568/*
5569 * Reset Handling
5570 */
5571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5572/**
5573 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5574 * Management call based on input arg values. If TaskMgmt fails,
5575 * return associated SCSI request.
5576 * @ioc: Pointer to MPT_ADAPTER structure
5577 * @sleepFlag: Indicates if sleep or schedule must be called.
5578 *
5579 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5580 * or a non-interrupt thread. In the former, must not call schedule().
5581 *
5582 * Remark: A return of -1 is a FATAL error case, as it means a
5583 * FW reload/initialization failed.
5584 *
5585 * Returns 0 for SUCCESS or -1 if FAILED.
5586 */
5587int
5588mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5589{
5590 int rc;
5591 unsigned long flags;
5592
5593 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5594#ifdef MFCNT
5595 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5596 printk("MF count 0x%x !\n", ioc->mfcnt);
5597#endif
5598
5599 /* Reset the adapter. Prevent more than 1 call to
5600 * mpt_do_ioc_recovery at any instant in time.
5601 */
5602 spin_lock_irqsave(&ioc->diagLock, flags);
5603 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5604 spin_unlock_irqrestore(&ioc->diagLock, flags);
5605 return 0;
5606 } else {
5607 ioc->diagPending = 1;
5608 }
5609 spin_unlock_irqrestore(&ioc->diagLock, flags);
5610
5611 /* FIXME: If do_ioc_recovery fails, repeat....
5612 */
5613
5614 /* The SCSI driver needs to adjust timeouts on all current
5615 * commands prior to the diagnostic reset being issued.
5616 * Prevents timeouts occuring during a diagnostic reset...very bad.
5617 * For all other protocol drivers, this is a no-op.
5618 */
5619 {
5620 int ii;
5621 int r = 0;
5622
5623 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5624 if (MptResetHandlers[ii]) {
5625 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5626 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005627 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 if (ioc->alt_ioc) {
5629 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5630 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005631 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 }
5633 }
5634 }
5635 }
5636
5637 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5638 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5639 rc, ioc->name);
5640 }
5641 ioc->reload_fw = 0;
5642 if (ioc->alt_ioc)
5643 ioc->alt_ioc->reload_fw = 0;
5644
5645 spin_lock_irqsave(&ioc->diagLock, flags);
5646 ioc->diagPending = 0;
5647 if (ioc->alt_ioc)
5648 ioc->alt_ioc->diagPending = 0;
5649 spin_unlock_irqrestore(&ioc->diagLock, flags);
5650
5651 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5652
5653 return rc;
5654}
5655
Eric Moore509e5e52006-04-26 13:22:37 -06005656# define EVENT_DESCR_STR_SZ 100
5657
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005659static void
5660EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661{
Eric Moore509e5e52006-04-26 13:22:37 -06005662 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663
5664 switch(event) {
5665 case MPI_EVENT_NONE:
5666 ds = "None";
5667 break;
5668 case MPI_EVENT_LOG_DATA:
5669 ds = "Log Data";
5670 break;
5671 case MPI_EVENT_STATE_CHANGE:
5672 ds = "State Change";
5673 break;
5674 case MPI_EVENT_UNIT_ATTENTION:
5675 ds = "Unit Attention";
5676 break;
5677 case MPI_EVENT_IOC_BUS_RESET:
5678 ds = "IOC Bus Reset";
5679 break;
5680 case MPI_EVENT_EXT_BUS_RESET:
5681 ds = "External Bus Reset";
5682 break;
5683 case MPI_EVENT_RESCAN:
5684 ds = "Bus Rescan Event";
5685 /* Ok, do we need to do anything here? As far as
5686 I can tell, this is when a new device gets added
5687 to the loop. */
5688 break;
5689 case MPI_EVENT_LINK_STATUS_CHANGE:
5690 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5691 ds = "Link Status(FAILURE) Change";
5692 else
5693 ds = "Link Status(ACTIVE) Change";
5694 break;
5695 case MPI_EVENT_LOOP_STATE_CHANGE:
5696 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5697 ds = "Loop State(LIP) Change";
5698 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005699 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 else
Eric Moore509e5e52006-04-26 13:22:37 -06005701 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702 break;
5703 case MPI_EVENT_LOGOUT:
5704 ds = "Logout";
5705 break;
5706 case MPI_EVENT_EVENT_CHANGE:
5707 if (evData0)
5708 ds = "Events(ON) Change";
5709 else
5710 ds = "Events(OFF) Change";
5711 break;
5712 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005713 {
5714 u8 ReasonCode = (u8)(evData0 >> 16);
5715 switch (ReasonCode) {
5716 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5717 ds = "Integrated Raid: Volume Created";
5718 break;
5719 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5720 ds = "Integrated Raid: Volume Deleted";
5721 break;
5722 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5723 ds = "Integrated Raid: Volume Settings Changed";
5724 break;
5725 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5726 ds = "Integrated Raid: Volume Status Changed";
5727 break;
5728 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5729 ds = "Integrated Raid: Volume Physdisk Changed";
5730 break;
5731 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5732 ds = "Integrated Raid: Physdisk Created";
5733 break;
5734 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5735 ds = "Integrated Raid: Physdisk Deleted";
5736 break;
5737 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5738 ds = "Integrated Raid: Physdisk Settings Changed";
5739 break;
5740 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5741 ds = "Integrated Raid: Physdisk Status Changed";
5742 break;
5743 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5744 ds = "Integrated Raid: Domain Validation Needed";
5745 break;
5746 case MPI_EVENT_RAID_RC_SMART_DATA :
5747 ds = "Integrated Raid; Smart Data";
5748 break;
5749 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5750 ds = "Integrated Raid: Replace Action Started";
5751 break;
5752 default:
5753 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005755 }
5756 break;
5757 }
5758 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5759 ds = "SCSI Device Status Change";
5760 break;
5761 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5762 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005763 u8 id = (u8)(evData0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005764 u8 ReasonCode = (u8)(evData0 >> 16);
5765 switch (ReasonCode) {
5766 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005767 snprintf(evStr, EVENT_DESCR_STR_SZ,
5768 "SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005769 break;
5770 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005771 snprintf(evStr, EVENT_DESCR_STR_SZ,
5772 "SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005773 break;
5774 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005775 snprintf(evStr, EVENT_DESCR_STR_SZ,
5776 "SAS Device Status Change: SMART Data: id=%d",
5777 id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005778 break;
5779 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005780 snprintf(evStr, EVENT_DESCR_STR_SZ,
5781 "SAS Device Status Change: No Persistancy "
5782 "Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005783 break;
5784 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005785 snprintf(evStr, EVENT_DESCR_STR_SZ,
5786 "SAS Device Status Change: Unknown: id=%d", id);
5787 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005788 }
5789 break;
5790 }
5791 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5792 ds = "Bus Timer Expired";
5793 break;
5794 case MPI_EVENT_QUEUE_FULL:
5795 ds = "Queue Full";
5796 break;
5797 case MPI_EVENT_SAS_SES:
5798 ds = "SAS SES Event";
5799 break;
5800 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5801 ds = "Persistent Table Full";
5802 break;
5803 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005804 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005805 u8 LinkRates = (u8)(evData0 >> 8);
5806 u8 PhyNumber = (u8)(evData0);
5807 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5808 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5809 switch (LinkRates) {
5810 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06005811 snprintf(evStr, EVENT_DESCR_STR_SZ,
5812 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005813 " Rate Unknown",PhyNumber);
5814 break;
5815 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06005816 snprintf(evStr, EVENT_DESCR_STR_SZ,
5817 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005818 " Phy Disabled",PhyNumber);
5819 break;
5820 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06005821 snprintf(evStr, EVENT_DESCR_STR_SZ,
5822 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005823 " Failed Speed Nego",PhyNumber);
5824 break;
5825 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06005826 snprintf(evStr, EVENT_DESCR_STR_SZ,
5827 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005828 " Sata OOB Completed",PhyNumber);
5829 break;
5830 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06005831 snprintf(evStr, EVENT_DESCR_STR_SZ,
5832 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005833 " Rate 1.5 Gbps",PhyNumber);
5834 break;
5835 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06005836 snprintf(evStr, EVENT_DESCR_STR_SZ,
5837 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005838 " Rate 3.0 Gpbs",PhyNumber);
5839 break;
5840 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005841 snprintf(evStr, EVENT_DESCR_STR_SZ,
5842 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07005843 break;
5844 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005845 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005846 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005847 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5848 ds = "SAS Discovery Error";
5849 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005850 case MPI_EVENT_IR_RESYNC_UPDATE:
5851 {
5852 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06005853 snprintf(evStr, EVENT_DESCR_STR_SZ,
5854 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07005855 break;
5856 }
5857 case MPI_EVENT_IR2:
5858 {
5859 u8 ReasonCode = (u8)(evData0 >> 16);
5860 switch (ReasonCode) {
5861 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5862 ds = "IR2: LD State Changed";
5863 break;
5864 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5865 ds = "IR2: PD State Changed";
5866 break;
5867 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5868 ds = "IR2: Bad Block Table Full";
5869 break;
5870 case MPI_EVENT_IR2_RC_PD_INSERTED:
5871 ds = "IR2: PD Inserted";
5872 break;
5873 case MPI_EVENT_IR2_RC_PD_REMOVED:
5874 ds = "IR2: PD Removed";
5875 break;
5876 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5877 ds = "IR2: Foreign CFG Detected";
5878 break;
5879 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5880 ds = "IR2: Rebuild Medium Error";
5881 break;
5882 default:
5883 ds = "IR2";
5884 break;
5885 }
5886 break;
5887 }
5888 case MPI_EVENT_SAS_DISCOVERY:
5889 {
5890 if (evData0)
5891 ds = "SAS Discovery: Start";
5892 else
5893 ds = "SAS Discovery: Stop";
5894 break;
5895 }
5896 case MPI_EVENT_LOG_ENTRY_ADDED:
5897 ds = "SAS Log Entry Added";
5898 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005899
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900 /*
5901 * MPT base "custom" events may be added here...
5902 */
5903 default:
5904 ds = "Unknown";
5905 break;
5906 }
Eric Moore509e5e52006-04-26 13:22:37 -06005907 if (ds)
5908 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909}
5910
5911/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5912/*
5913 * ProcessEventNotification - Route a received EventNotificationReply to
5914 * all currently regeistered event handlers.
5915 * @ioc: Pointer to MPT_ADAPTER structure
5916 * @pEventReply: Pointer to EventNotification reply frame
5917 * @evHandlers: Pointer to integer, number of event handlers
5918 *
5919 * Returns sum of event handlers return values.
5920 */
5921static int
5922ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5923{
5924 u16 evDataLen;
5925 u32 evData0 = 0;
5926// u32 evCtx;
5927 int ii;
5928 int r = 0;
5929 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06005930 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 u8 event;
5932
5933 /*
5934 * Do platform normalization of values
5935 */
5936 event = le32_to_cpu(pEventReply->Event) & 0xFF;
5937// evCtx = le32_to_cpu(pEventReply->EventContext);
5938 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
5939 if (evDataLen) {
5940 evData0 = le32_to_cpu(pEventReply->Data[0]);
5941 }
5942
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005943 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07005944 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07005946 event,
5947 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948
Moore, Eric3a892be2006-03-14 09:14:03 -07005949#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
5951 for (ii = 0; ii < evDataLen; ii++)
5952 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
5953 printk("\n");
5954#endif
5955
5956 /*
5957 * Do general / base driver event processing
5958 */
5959 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 case MPI_EVENT_EVENT_CHANGE: /* 0A */
5961 if (evDataLen) {
5962 u8 evState = evData0 & 0xFF;
5963
5964 /* CHECKME! What if evState unexpectedly says OFF (0)? */
5965
5966 /* Update EventState field in cached IocFacts */
5967 if (ioc->facts.Function) {
5968 ioc->facts.EventState = evState;
5969 }
5970 }
5971 break;
Moore, Ericece50912006-01-16 18:53:19 -07005972 case MPI_EVENT_INTEGRATED_RAID:
5973 mptbase_raid_process_event_data(ioc,
5974 (MpiEventDataRaid_t *)pEventReply->Data);
5975 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005976 default:
5977 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978 }
5979
5980 /*
5981 * Should this event be logged? Events are written sequentially.
5982 * When buffer is full, start again at the top.
5983 */
5984 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
5985 int idx;
5986
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07005987 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988
5989 ioc->events[idx].event = event;
5990 ioc->events[idx].eventContext = ioc->eventContext;
5991
5992 for (ii = 0; ii < 2; ii++) {
5993 if (ii < evDataLen)
5994 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
5995 else
5996 ioc->events[idx].data[ii] = 0;
5997 }
5998
5999 ioc->eventContext++;
6000 }
6001
6002
6003 /*
6004 * Call each currently registered protocol event handler.
6005 */
6006 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6007 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006008 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009 ioc->name, ii));
6010 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6011 handlers++;
6012 }
6013 }
6014 /* FIXME? Examine results here? */
6015
6016 /*
6017 * If needed, send (a single) EventAck.
6018 */
6019 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006020 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006021 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006023 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024 ioc->name, ii));
6025 }
6026 }
6027
6028 *evHandlers = handlers;
6029 return r;
6030}
6031
6032/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6033/*
6034 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6035 * @ioc: Pointer to MPT_ADAPTER structure
6036 * @log_info: U32 LogInfo reply word from the IOC
6037 *
6038 * Refer to lsi/fc_log.h.
6039 */
6040static void
6041mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6042{
6043 static char *subcl_str[8] = {
6044 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6045 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6046 };
6047 u8 subcl = (log_info >> 24) & 0x7;
6048
6049 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6050 ioc->name, log_info, subcl_str[subcl]);
6051}
6052
6053/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6054/*
Moore, Eric335a9412006-01-17 17:06:23 -07006055 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056 * @ioc: Pointer to MPT_ADAPTER structure
6057 * @mr: Pointer to MPT reply frame
6058 * @log_info: U32 LogInfo word from the IOC
6059 *
6060 * Refer to lsi/sp_log.h.
6061 */
6062static void
Moore, Eric335a9412006-01-17 17:06:23 -07006063mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064{
6065 u32 info = log_info & 0x00FF0000;
6066 char *desc = "unknown";
6067
6068 switch (info) {
6069 case 0x00010000:
6070 desc = "bug! MID not found";
6071 if (ioc->reload_fw == 0)
6072 ioc->reload_fw++;
6073 break;
6074
6075 case 0x00020000:
6076 desc = "Parity Error";
6077 break;
6078
6079 case 0x00030000:
6080 desc = "ASYNC Outbound Overrun";
6081 break;
6082
6083 case 0x00040000:
6084 desc = "SYNC Offset Error";
6085 break;
6086
6087 case 0x00050000:
6088 desc = "BM Change";
6089 break;
6090
6091 case 0x00060000:
6092 desc = "Msg In Overflow";
6093 break;
6094
6095 case 0x00070000:
6096 desc = "DMA Error";
6097 break;
6098
6099 case 0x00080000:
6100 desc = "Outbound DMA Overrun";
6101 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006102
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 case 0x00090000:
6104 desc = "Task Management";
6105 break;
6106
6107 case 0x000A0000:
6108 desc = "Device Problem";
6109 break;
6110
6111 case 0x000B0000:
6112 desc = "Invalid Phase Change";
6113 break;
6114
6115 case 0x000C0000:
6116 desc = "Untagged Table Size";
6117 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006118
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 }
6120
6121 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6122}
6123
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006124/* strings for sas loginfo */
6125 static char *originator_str[] = {
6126 "IOP", /* 00h */
6127 "PL", /* 01h */
6128 "IR" /* 02h */
6129 };
6130 static char *iop_code_str[] = {
6131 NULL, /* 00h */
6132 "Invalid SAS Address", /* 01h */
6133 NULL, /* 02h */
6134 "Invalid Page", /* 03h */
6135 NULL, /* 04h */
6136 "Task Terminated" /* 05h */
6137 };
6138 static char *pl_code_str[] = {
6139 NULL, /* 00h */
6140 "Open Failure", /* 01h */
6141 "Invalid Scatter Gather List", /* 02h */
6142 "Wrong Relative Offset or Frame Length", /* 03h */
6143 "Frame Transfer Error", /* 04h */
6144 "Transmit Frame Connected Low", /* 05h */
6145 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6146 "SATA Read Log Receive Data Error", /* 07h */
6147 "SATA NCQ Fail All Commands After Error", /* 08h */
6148 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6149 "Receive Frame Invalid Message", /* 0Ah */
6150 "Receive Context Message Valid Error", /* 0Bh */
6151 "Receive Frame Current Frame Error", /* 0Ch */
6152 "SATA Link Down", /* 0Dh */
6153 "Discovery SATA Init W IOS", /* 0Eh */
6154 "Config Invalid Page", /* 0Fh */
6155 "Discovery SATA Init Timeout", /* 10h */
6156 "Reset", /* 11h */
6157 "Abort", /* 12h */
6158 "IO Not Yet Executed", /* 13h */
6159 "IO Executed", /* 14h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006160 "Persistant Reservation Out Not Affiliation Owner", /* 15h */
6161 "Open Transmit DMA Abort", /* 16h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006162 NULL, /* 17h */
6163 NULL, /* 18h */
6164 NULL, /* 19h */
6165 NULL, /* 1Ah */
6166 NULL, /* 1Bh */
6167 NULL, /* 1Ch */
6168 NULL, /* 1Dh */
6169 NULL, /* 1Eh */
6170 NULL, /* 1Fh */
6171 "Enclosure Management" /* 20h */
6172 };
6173
6174/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6175/*
6176 * mpt_sas_log_info - Log information returned from SAS IOC.
6177 * @ioc: Pointer to MPT_ADAPTER structure
6178 * @log_info: U32 LogInfo reply word from the IOC
6179 *
6180 * Refer to lsi/mpi_log_sas.h.
6181 */
6182static void
6183mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6184{
6185union loginfo_type {
6186 u32 loginfo;
6187 struct {
6188 u32 subcode:16;
6189 u32 code:8;
6190 u32 originator:4;
6191 u32 bus_type:4;
6192 }dw;
6193};
6194 union loginfo_type sas_loginfo;
6195 char *code_desc = NULL;
6196
6197 sas_loginfo.loginfo = log_info;
6198 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6199 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6200 return;
6201 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6202 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6203 code_desc = iop_code_str[sas_loginfo.dw.code];
6204 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6205 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6206 code_desc = pl_code_str[sas_loginfo.dw.code];
6207 }
6208
6209 if (code_desc != NULL)
6210 printk(MYIOC_s_INFO_FMT
6211 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6212 " SubCode(0x%04x)\n",
6213 ioc->name,
6214 log_info,
6215 originator_str[sas_loginfo.dw.originator],
6216 code_desc,
6217 sas_loginfo.dw.subcode);
6218 else
6219 printk(MYIOC_s_INFO_FMT
6220 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6221 " SubCode(0x%04x)\n",
6222 ioc->name,
6223 log_info,
6224 originator_str[sas_loginfo.dw.originator],
6225 sas_loginfo.dw.code,
6226 sas_loginfo.dw.subcode);
6227}
6228
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6230/*
6231 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6232 * @ioc: Pointer to MPT_ADAPTER structure
6233 * @ioc_status: U32 IOCStatus word from IOC
6234 * @mf: Pointer to MPT request frame
6235 *
6236 * Refer to lsi/mpi.h.
6237 */
6238static void
6239mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6240{
6241 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
6242 char *desc = "";
6243
6244 switch (status) {
6245 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6246 desc = "Invalid Function";
6247 break;
6248
6249 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6250 desc = "Busy";
6251 break;
6252
6253 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6254 desc = "Invalid SGL";
6255 break;
6256
6257 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6258 desc = "Internal Error";
6259 break;
6260
6261 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6262 desc = "Reserved";
6263 break;
6264
6265 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6266 desc = "Insufficient Resources";
6267 break;
6268
6269 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6270 desc = "Invalid Field";
6271 break;
6272
6273 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6274 desc = "Invalid State";
6275 break;
6276
6277 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6278 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6279 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6280 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6281 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6282 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6283 /* No message for Config IOCStatus values */
6284 break;
6285
6286 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6287 /* No message for recovered error
6288 desc = "SCSI Recovered Error";
6289 */
6290 break;
6291
6292 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6293 desc = "SCSI Invalid Bus";
6294 break;
6295
6296 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6297 desc = "SCSI Invalid TargetID";
6298 break;
6299
6300 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6301 {
6302 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6303 U8 cdb = pScsiReq->CDB[0];
6304 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6305 desc = "SCSI Device Not There";
6306 }
6307 break;
6308 }
6309
6310 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6311 desc = "SCSI Data Overrun";
6312 break;
6313
6314 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006315 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316 desc = "SCSI Data Underrun";
6317 */
6318 break;
6319
6320 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6321 desc = "SCSI I/O Data Error";
6322 break;
6323
6324 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6325 desc = "SCSI Protocol Error";
6326 break;
6327
6328 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6329 desc = "SCSI Task Terminated";
6330 break;
6331
6332 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6333 desc = "SCSI Residual Mismatch";
6334 break;
6335
6336 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6337 desc = "SCSI Task Management Failed";
6338 break;
6339
6340 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6341 desc = "SCSI IOC Terminated";
6342 break;
6343
6344 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6345 desc = "SCSI Ext Terminated";
6346 break;
6347
6348 default:
6349 desc = "Others";
6350 break;
6351 }
6352 if (desc != "")
6353 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6354}
6355
6356/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006357EXPORT_SYMBOL(mpt_attach);
6358EXPORT_SYMBOL(mpt_detach);
6359#ifdef CONFIG_PM
6360EXPORT_SYMBOL(mpt_resume);
6361EXPORT_SYMBOL(mpt_suspend);
6362#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006364EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365EXPORT_SYMBOL(mpt_register);
6366EXPORT_SYMBOL(mpt_deregister);
6367EXPORT_SYMBOL(mpt_event_register);
6368EXPORT_SYMBOL(mpt_event_deregister);
6369EXPORT_SYMBOL(mpt_reset_register);
6370EXPORT_SYMBOL(mpt_reset_deregister);
6371EXPORT_SYMBOL(mpt_device_driver_register);
6372EXPORT_SYMBOL(mpt_device_driver_deregister);
6373EXPORT_SYMBOL(mpt_get_msg_frame);
6374EXPORT_SYMBOL(mpt_put_msg_frame);
6375EXPORT_SYMBOL(mpt_free_msg_frame);
6376EXPORT_SYMBOL(mpt_add_sge);
6377EXPORT_SYMBOL(mpt_send_handshake_request);
6378EXPORT_SYMBOL(mpt_verify_adapter);
6379EXPORT_SYMBOL(mpt_GetIocState);
6380EXPORT_SYMBOL(mpt_print_ioc_summary);
6381EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006382EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383EXPORT_SYMBOL(mpt_HardResetHandler);
6384EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386EXPORT_SYMBOL(mpt_alloc_fw_memory);
6387EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006388EXPORT_SYMBOL(mptbase_sas_persist_operation);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389
Linus Torvalds1da177e2005-04-16 15:20:36 -07006390
6391/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6392/*
6393 * fusion_init - Fusion MPT base driver initialization routine.
6394 *
6395 * Returns 0 for success, non-zero for failure.
6396 */
6397static int __init
6398fusion_init(void)
6399{
6400 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401
6402 show_mptmod_ver(my_NAME, my_VERSION);
6403 printk(KERN_INFO COPYRIGHT "\n");
6404
6405 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6406 MptCallbacks[i] = NULL;
6407 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6408 MptEvHandlers[i] = NULL;
6409 MptResetHandlers[i] = NULL;
6410 }
6411
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006412 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413 * EventNotification handling.
6414 */
6415 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6416
6417 /* Register for hard reset handling callbacks.
6418 */
6419 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6420 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6421 } else {
6422 /* FIXME! */
6423 }
6424
6425#ifdef CONFIG_PROC_FS
6426 (void) procmpt_create();
6427#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006428 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006429}
6430
6431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6432/*
6433 * fusion_exit - Perform driver unload cleanup.
6434 *
6435 * This routine frees all resources associated with each MPT adapter
6436 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6437 */
6438static void __exit
6439fusion_exit(void)
6440{
6441
6442 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6443
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444 mpt_reset_deregister(mpt_base_index);
6445
6446#ifdef CONFIG_PROC_FS
6447 procmpt_destroy();
6448#endif
6449}
6450
Linus Torvalds1da177e2005-04-16 15:20:36 -07006451module_init(fusion_init);
6452module_exit(fusion_exit);