blob: a3751d86216eb421b4e41dc0d5b45345f317f4cc [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
66#ifdef __sparc__
67#include <asm/irq.h> /* needed for __irq_itoa() proto */
68#endif
69
70#include "mptbase.h"
71
72/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73#define my_NAME "Fusion MPT base driver"
74#define my_VERSION MPT_LINUX_VERSION_COMMON
75#define MYNAM "mptbase"
76
77MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
80
81/*
82 * cmd line parameters
83 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000084static int mpt_msi_enable;
85module_param(mpt_msi_enable, int, 0);
86MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#ifdef MFCNT
89static int mfcounter = 0;
90#define PRINT_MF_COUNT 20000
91#endif
92
93/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
94/*
95 * Public data...
96 */
97int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080098int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Linus Torvaldsf7473072005-11-29 14:21:57 -0800100struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102#define WHOINIT_UNKNOWN 0xAA
103
104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
105/*
106 * Private data...
107 */
108 /* Adapter link list */
109LIST_HEAD(ioc_list);
110 /* Callback lookup table */
111static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
112 /* Protocol driver class lookup table */
113static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
114 /* Event handler lookup table */
115static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
116 /* Reset handler lookup table */
117static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
118static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
119
120static int mpt_base_index = -1;
121static int last_drv_idx = -1;
122
123static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
124
125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
126/*
127 * Forward protos...
128 */
129static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
130static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
131static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
132 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
133 int sleepFlag);
134static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
135static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
136static void mpt_adapter_disable(MPT_ADAPTER *ioc);
137static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
138
139static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
140static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
142static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
143static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
144static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
145static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200146static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
148static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
149static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
150static int PrimeIocFifos(MPT_ADAPTER *ioc);
151static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
152static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
153static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
154static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200156int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
158static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
159static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
160static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
161static void mpt_timer_expired(unsigned long data);
162static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
163static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200164static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
165static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167#ifdef CONFIG_PROC_FS
168static int procmpt_summary_read(char *buf, char **start, off_t offset,
169 int request, int *eof, void *data);
170static int procmpt_version_read(char *buf, char **start, off_t offset,
171 int request, int *eof, void *data);
172static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
173 int request, int *eof, void *data);
174#endif
175static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
176
177//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
178static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
179static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
180static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700181static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600182static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static int __init fusion_init (void);
186static void __exit fusion_exit (void);
187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188#define CHIPREG_READ32(addr) readl_relaxed(addr)
189#define CHIPREG_READ32_dmasync(addr) readl(addr)
190#define CHIPREG_WRITE32(addr,val) writel(val, addr)
191#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
192#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
193
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600194static void
195pci_disable_io_access(struct pci_dev *pdev)
196{
197 u16 command_reg;
198
199 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
200 command_reg &= ~1;
201 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
202}
203
204static void
205pci_enable_io_access(struct pci_dev *pdev)
206{
207 u16 command_reg;
208
209 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
210 command_reg |= 1;
211 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
212}
213
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600214/*
215 * Process turbo (context) reply...
216 */
217static void
218mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
219{
220 MPT_FRAME_HDR *mf = NULL;
221 MPT_FRAME_HDR *mr = NULL;
222 int req_idx = 0;
223 int cb_idx;
224
225 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
226 ioc->name, pa));
227
228 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
229 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
230 req_idx = pa & 0x0000FFFF;
231 cb_idx = (pa & 0x00FF0000) >> 16;
232 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
233 break;
234 case MPI_CONTEXT_REPLY_TYPE_LAN:
235 cb_idx = mpt_lan_index;
236 /*
237 * Blind set of mf to NULL here was fatal
238 * after lan_reply says "freeme"
239 * Fix sort of combined with an optimization here;
240 * added explicit check for case where lan_reply
241 * was just returning 1 and doing nothing else.
242 * For this case skip the callback, but set up
243 * proper mf value first here:-)
244 */
245 if ((pa & 0x58000000) == 0x58000000) {
246 req_idx = pa & 0x0000FFFF;
247 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
248 mpt_free_msg_frame(ioc, mf);
249 mb();
250 return;
251 break;
252 }
253 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
254 break;
255 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
256 cb_idx = mpt_stm_index;
257 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
258 break;
259 default:
260 cb_idx = 0;
261 BUG();
262 }
263
264 /* Check for (valid) IO callback! */
265 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
266 MptCallbacks[cb_idx] == NULL) {
267 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
268 __FUNCTION__, ioc->name, cb_idx);
269 goto out;
270 }
271
272 if (MptCallbacks[cb_idx](ioc, mf, mr))
273 mpt_free_msg_frame(ioc, mf);
274 out:
275 mb();
276}
277
278static void
279mpt_reply(MPT_ADAPTER *ioc, u32 pa)
280{
281 MPT_FRAME_HDR *mf;
282 MPT_FRAME_HDR *mr;
283 int req_idx;
284 int cb_idx;
285 int freeme;
286
287 u32 reply_dma_low;
288 u16 ioc_stat;
289
290 /* non-TURBO reply! Hmmm, something may be up...
291 * Newest turbo reply mechanism; get address
292 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
293 */
294
295 /* Map DMA address of reply header to cpu address.
296 * pa is 32 bits - but the dma address may be 32 or 64 bits
297 * get offset based only only the low addresses
298 */
299
300 reply_dma_low = (pa <<= 1);
301 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
302 (reply_dma_low - ioc->reply_frames_low_dma));
303
304 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
305 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
306 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
307
308 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
309 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
310 DBG_DUMP_REPLY_FRAME(mr)
311
312 /* Check/log IOC log info
313 */
314 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
315 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
316 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
317 if (ioc->bus_type == FC)
318 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700319 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700320 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600321 else if (ioc->bus_type == SAS)
322 mpt_sas_log_info(ioc, log_info);
323 }
324 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700325 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600326 cb_idx != mpt_stm_index &&
327 cb_idx != mpt_lan_index)
328 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
329 }
330
331
332 /* Check for (valid) IO callback! */
333 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
334 MptCallbacks[cb_idx] == NULL) {
335 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
336 __FUNCTION__, ioc->name, cb_idx);
337 freeme = 0;
338 goto out;
339 }
340
341 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
342
343 out:
344 /* Flush (non-TURBO) reply with a WRITE! */
345 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
346
347 if (freeme)
348 mpt_free_msg_frame(ioc, mf);
349 mb();
350}
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
353/*
354 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
355 * @irq: irq number (not used)
356 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
357 * @r: pt_regs pointer (not used)
358 *
359 * This routine is registered via the request_irq() kernel API call,
360 * and handles all interrupts generated from a specific MPT adapter
361 * (also referred to as a IO Controller or IOC).
362 * This routine must clear the interrupt from the adapter and does
363 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200364 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 *
366 * This routine handles register-level access of the adapter but
367 * dispatches (calls) a protocol-specific callback routine to handle
368 * the protocol-specific details of the MPT request completion.
369 */
370static irqreturn_t
371mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
372{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600373 MPT_ADAPTER *ioc = bus_id;
374 u32 pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 /*
377 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 */
379 while (1) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600380 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
381 if (pa == 0xFFFFFFFF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 return IRQ_HANDLED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600383 else if (pa & MPI_ADDRESS_REPLY_A_BIT)
384 mpt_reply(ioc, pa);
385 else
386 mpt_turbo_reply(ioc, pa);
387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389 return IRQ_HANDLED;
390}
391
392/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
393/*
394 * mpt_base_reply - MPT base driver's callback routine; all base driver
395 * "internal" request/reply processing is routed here.
396 * Currently used for EventNotification and EventAck handling.
397 * @ioc: Pointer to MPT_ADAPTER structure
398 * @mf: Pointer to original MPT request frame
399 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
400 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200401 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 * should be freed, or 0 if it shouldn't.
403 */
404static int
405mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
406{
407 int freereq = 1;
408 u8 func;
409
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200410 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200412#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
414 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
415 DBG_DUMP_REQUEST_FRAME_HDR(mf)
416 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200417#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200420 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 ioc->name, func));
422
423 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
424 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
425 int evHandlers = 0;
426 int results;
427
428 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
429 if (results != evHandlers) {
430 /* CHECKME! Any special handling needed here? */
431 devtprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
432 ioc->name, evHandlers, results));
433 }
434
435 /*
436 * Hmmm... It seems that EventNotificationReply is an exception
437 * to the rule of one reply per request.
438 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200439 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200441 devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
442 ioc->name, pEvReply));
443 } else {
444 devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
445 ioc->name, pEvReply));
446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448#ifdef CONFIG_PROC_FS
449// LogEvent(ioc, pEvReply);
450#endif
451
452 } else if (func == MPI_FUNCTION_EVENT_ACK) {
453 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
454 ioc->name));
455 } else if (func == MPI_FUNCTION_CONFIG ||
456 func == MPI_FUNCTION_TOOLBOX) {
457 CONFIGPARMS *pCfg;
458 unsigned long flags;
459
460 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
461 ioc->name, mf, reply));
462
463 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
464
465 if (pCfg) {
466 /* disable timer and remove from linked list */
467 del_timer(&pCfg->timer);
468
469 spin_lock_irqsave(&ioc->FreeQlock, flags);
470 list_del(&pCfg->linkage);
471 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
472
473 /*
474 * If IOC Status is SUCCESS, save the header
475 * and set the status code to GOOD.
476 */
477 pCfg->status = MPT_CONFIG_ERROR;
478 if (reply) {
479 ConfigReply_t *pReply = (ConfigReply_t *)reply;
480 u16 status;
481
482 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
483 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
484 status, le32_to_cpu(pReply->IOCLogInfo)));
485
486 pCfg->status = status;
487 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200488 if ((pReply->Header.PageType &
489 MPI_CONFIG_PAGETYPE_MASK) ==
490 MPI_CONFIG_PAGETYPE_EXTENDED) {
491 pCfg->cfghdr.ehdr->ExtPageLength =
492 le16_to_cpu(pReply->ExtPageLength);
493 pCfg->cfghdr.ehdr->ExtPageType =
494 pReply->ExtPageType;
495 }
496 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
497
498 /* If this is a regular header, save PageLength. */
499 /* LMP Do this better so not using a reserved field! */
500 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
501 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
502 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 }
504 }
505
506 /*
507 * Wake up the original calling thread
508 */
509 pCfg->wait_done = 1;
510 wake_up(&mpt_waitq);
511 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200512 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
513 /* we should be always getting a reply frame */
514 memcpy(ioc->persist_reply_frame, reply,
515 min(MPT_DEFAULT_FRAME_SIZE,
516 4*reply->u.reply.MsgLength));
517 del_timer(&ioc->persist_timer);
518 ioc->persist_wait_done = 1;
519 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 } else {
521 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
522 ioc->name, func);
523 }
524
525 /*
526 * Conditionally tell caller to free the original
527 * EventNotification/EventAck/unexpected request frame!
528 */
529 return freereq;
530}
531
532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
533/**
534 * mpt_register - Register protocol-specific main callback handler.
535 * @cbfunc: callback function pointer
536 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
537 *
538 * This routine is called by a protocol-specific driver (SCSI host,
539 * LAN, SCSI target) to register it's reply callback routine. Each
540 * protocol-specific driver must do this before it will be able to
541 * use any IOC resources, such as obtaining request frames.
542 *
543 * NOTES: The SCSI protocol driver currently calls this routine thrice
544 * in order to register separate callbacks; one for "normal" SCSI IO;
545 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
546 *
547 * Returns a positive integer valued "handle" in the
548 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
549 * Any non-positive return value (including zero!) should be considered
550 * an error by the caller.
551 */
552int
553mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
554{
555 int i;
556
557 last_drv_idx = -1;
558
559 /*
560 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
561 * (slot/handle 0 is reserved!)
562 */
563 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
564 if (MptCallbacks[i] == NULL) {
565 MptCallbacks[i] = cbfunc;
566 MptDriverClass[i] = dclass;
567 MptEvHandlers[i] = NULL;
568 last_drv_idx = i;
569 break;
570 }
571 }
572
573 return last_drv_idx;
574}
575
576/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
577/**
578 * mpt_deregister - Deregister a protocol drivers resources.
579 * @cb_idx: previously registered callback handle
580 *
581 * Each protocol-specific driver should call this routine when it's
582 * module is unloaded.
583 */
584void
585mpt_deregister(int cb_idx)
586{
587 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
588 MptCallbacks[cb_idx] = NULL;
589 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
590 MptEvHandlers[cb_idx] = NULL;
591
592 last_drv_idx++;
593 }
594}
595
596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
597/**
598 * mpt_event_register - Register protocol-specific event callback
599 * handler.
600 * @cb_idx: previously registered (via mpt_register) callback handle
601 * @ev_cbfunc: callback function
602 *
603 * This routine can be called by one or more protocol-specific drivers
604 * if/when they choose to be notified of MPT events.
605 *
606 * Returns 0 for success.
607 */
608int
609mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
610{
611 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
612 return -1;
613
614 MptEvHandlers[cb_idx] = ev_cbfunc;
615 return 0;
616}
617
618/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
619/**
620 * mpt_event_deregister - Deregister protocol-specific event callback
621 * handler.
622 * @cb_idx: previously registered callback handle
623 *
624 * Each protocol-specific driver should call this routine
625 * when it does not (or can no longer) handle events,
626 * or when it's module is unloaded.
627 */
628void
629mpt_event_deregister(int cb_idx)
630{
631 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
632 return;
633
634 MptEvHandlers[cb_idx] = NULL;
635}
636
637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
638/**
639 * mpt_reset_register - Register protocol-specific IOC reset handler.
640 * @cb_idx: previously registered (via mpt_register) callback handle
641 * @reset_func: reset function
642 *
643 * This routine can be called by one or more protocol-specific drivers
644 * if/when they choose to be notified of IOC resets.
645 *
646 * Returns 0 for success.
647 */
648int
649mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
650{
651 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
652 return -1;
653
654 MptResetHandlers[cb_idx] = reset_func;
655 return 0;
656}
657
658/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
659/**
660 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
661 * @cb_idx: previously registered callback handle
662 *
663 * Each protocol-specific driver should call this routine
664 * when it does not (or can no longer) handle IOC reset handling,
665 * or when it's module is unloaded.
666 */
667void
668mpt_reset_deregister(int cb_idx)
669{
670 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
671 return;
672
673 MptResetHandlers[cb_idx] = NULL;
674}
675
676/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
677/**
678 * mpt_device_driver_register - Register device driver hooks
679 */
680int
681mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
682{
683 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400686 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688
689 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
690
691 /* call per pci device probe entry point */
692 list_for_each_entry(ioc, &ioc_list, list) {
693 if(dd_cbfunc->probe) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400694 dd_cbfunc->probe(ioc->pcidev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 ioc->pcidev->driver->id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 }
697 }
698
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400699 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
702/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
703/**
704 * mpt_device_driver_deregister - DeRegister device driver hooks
705 */
706void
707mpt_device_driver_deregister(int cb_idx)
708{
709 struct mpt_pci_driver *dd_cbfunc;
710 MPT_ADAPTER *ioc;
711
712 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
713 return;
714
715 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
716
717 list_for_each_entry(ioc, &ioc_list, list) {
718 if (dd_cbfunc->remove)
719 dd_cbfunc->remove(ioc->pcidev);
720 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 MptDeviceDriverHandlers[cb_idx] = NULL;
723}
724
725
726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
727/**
728 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
729 * allocated per MPT adapter.
730 * @handle: Handle of registered MPT protocol driver
731 * @ioc: Pointer to MPT adapter structure
732 *
733 * Returns pointer to a MPT request frame or %NULL if none are available
734 * or IOC is not active.
735 */
736MPT_FRAME_HDR*
737mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
738{
739 MPT_FRAME_HDR *mf;
740 unsigned long flags;
741 u16 req_idx; /* Request index */
742
743 /* validate handle and ioc identifier */
744
745#ifdef MFCNT
746 if (!ioc->active)
747 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
748#endif
749
750 /* If interrupts are not attached, do not return a request frame */
751 if (!ioc->active)
752 return NULL;
753
754 spin_lock_irqsave(&ioc->FreeQlock, flags);
755 if (!list_empty(&ioc->FreeQ)) {
756 int req_offset;
757
758 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
759 u.frame.linkage.list);
760 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200761 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
763 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
764 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500765 req_idx = req_offset / ioc->req_sz;
766 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
768 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
769#ifdef MFCNT
770 ioc->mfcnt++;
771#endif
772 }
773 else
774 mf = NULL;
775 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
776
777#ifdef MFCNT
778 if (mf == NULL)
779 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
780 mfcounter++;
781 if (mfcounter == PRINT_MF_COUNT)
782 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
783#endif
784
785 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
786 ioc->name, handle, ioc->id, mf));
787 return mf;
788}
789
790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
791/**
792 * mpt_put_msg_frame - Send a protocol specific MPT request frame
793 * to a IOC.
794 * @handle: Handle of registered MPT protocol driver
795 * @ioc: Pointer to MPT adapter structure
796 * @mf: Pointer to MPT request frame
797 *
798 * This routine posts a MPT request frame to the request post FIFO of a
799 * specific MPT adapter.
800 */
801void
802mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
803{
804 u32 mf_dma_addr;
805 int req_offset;
806 u16 req_idx; /* Request index */
807
808 /* ensure values are reset properly! */
809 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
810 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
811 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500812 req_idx = req_offset / ioc->req_sz;
813 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
815
816#ifdef MPT_DEBUG_MSG_FRAME
817 {
818 u32 *m = mf->u.frame.hwhdr.__hdr;
819 int ii, n;
820
821 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
822 ioc->name, m);
823 n = ioc->req_sz/4 - 1;
824 while (m[n] == 0)
825 n--;
826 for (ii=0; ii<=n; ii++) {
827 if (ii && ((ii%8)==0))
828 printk("\n" KERN_INFO " ");
829 printk(" %08x", le32_to_cpu(m[ii]));
830 }
831 printk("\n");
832 }
833#endif
834
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200835 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 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]));
837 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
838}
839
840/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
841/**
842 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
843 * @handle: Handle of registered MPT protocol driver
844 * @ioc: Pointer to MPT adapter structure
845 * @mf: Pointer to MPT request frame
846 *
847 * This routine places a MPT request frame back on the MPT adapter's
848 * FreeQ.
849 */
850void
851mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
852{
853 unsigned long flags;
854
855 /* Put Request back on FreeQ! */
856 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200857 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
859#ifdef MFCNT
860 ioc->mfcnt--;
861#endif
862 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
863}
864
865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
866/**
867 * mpt_add_sge - Place a simple SGE at address pAddr.
868 * @pAddr: virtual address for SGE
869 * @flagslength: SGE flags and data transfer length
870 * @dma_addr: Physical address
871 *
872 * This routine places a MPT request frame back on the MPT adapter's
873 * FreeQ.
874 */
875void
876mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
877{
878 if (sizeof(dma_addr_t) == sizeof(u64)) {
879 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
880 u32 tmp = dma_addr & 0xFFFFFFFF;
881
882 pSge->FlagsLength = cpu_to_le32(flagslength);
883 pSge->Address.Low = cpu_to_le32(tmp);
884 tmp = (u32) ((u64)dma_addr >> 32);
885 pSge->Address.High = cpu_to_le32(tmp);
886
887 } else {
888 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
889 pSge->FlagsLength = cpu_to_le32(flagslength);
890 pSge->Address = cpu_to_le32(dma_addr);
891 }
892}
893
894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
895/**
896 * mpt_send_handshake_request - Send MPT request via doorbell
897 * handshake method.
898 * @handle: Handle of registered MPT protocol driver
899 * @ioc: Pointer to MPT adapter structure
900 * @reqBytes: Size of the request in bytes
901 * @req: Pointer to MPT request frame
902 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
903 *
904 * This routine is used exclusively to send MptScsiTaskMgmt
905 * requests since they are required to be sent via doorbell handshake.
906 *
907 * NOTE: It is the callers responsibility to byte-swap fields in the
908 * request which are greater than 1 byte in size.
909 *
910 * Returns 0 for success, non-zero for failure.
911 */
912int
913mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
914{
915 int r = 0;
916 u8 *req_as_bytes;
917 int ii;
918
919 /* State is known to be good upon entering
920 * this function so issue the bus reset
921 * request.
922 */
923
924 /*
925 * Emulate what mpt_put_msg_frame() does /wrt to sanity
926 * setting cb_idx/req_idx. But ONLY if this request
927 * is in proper (pre-alloc'd) request buffer range...
928 */
929 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
930 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
931 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
932 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
933 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
934 }
935
936 /* Make sure there are no doorbells */
937 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 CHIPREG_WRITE32(&ioc->chip->Doorbell,
940 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
941 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
942
943 /* Wait for IOC doorbell int */
944 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
945 return ii;
946 }
947
948 /* Read doorbell and check for active bit */
949 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
950 return -5;
951
952 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200953 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
956
957 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
958 return -2;
959 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 /* Send request via doorbell handshake */
962 req_as_bytes = (u8 *) req;
963 for (ii = 0; ii < reqBytes/4; ii++) {
964 u32 word;
965
966 word = ((req_as_bytes[(ii*4) + 0] << 0) |
967 (req_as_bytes[(ii*4) + 1] << 8) |
968 (req_as_bytes[(ii*4) + 2] << 16) |
969 (req_as_bytes[(ii*4) + 3] << 24));
970 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
971 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
972 r = -3;
973 break;
974 }
975 }
976
977 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
978 r = 0;
979 else
980 r = -4;
981
982 /* Make sure there are no doorbells */
983 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return r;
986}
987
988/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
989/**
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200990 * mpt_host_page_access_control - provides mechanism for the host
991 * driver to control the IOC's Host Page Buffer access.
992 * @ioc: Pointer to MPT adapter structure
993 * @access_control_value: define bits below
994 *
995 * Access Control Value - bits[15:12]
996 * 0h Reserved
997 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
998 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
999 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1000 *
1001 * Returns 0 for success, non-zero for failure.
1002 */
1003
1004static int
1005mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1006{
1007 int r = 0;
1008
1009 /* return if in use */
1010 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1011 & MPI_DOORBELL_ACTIVE)
1012 return -1;
1013
1014 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1015
1016 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1017 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1018 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1019 (access_control_value<<12)));
1020
1021 /* Wait for IOC to clear Doorbell Status bit */
1022 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1023 return -2;
1024 }else
1025 return 0;
1026}
1027
1028/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1029/**
1030 * mpt_host_page_alloc - allocate system memory for the fw
1031 * If we already allocated memory in past, then resend the same pointer.
1032 * ioc@: Pointer to pointer to IOC adapter
1033 * ioc_init@: Pointer to ioc init config page
1034 *
1035 * Returns 0 for success, non-zero for failure.
1036 */
1037static int
1038mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1039{
1040 char *psge;
1041 int flags_length;
1042 u32 host_page_buffer_sz=0;
1043
1044 if(!ioc->HostPageBuffer) {
1045
1046 host_page_buffer_sz =
1047 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1048
1049 if(!host_page_buffer_sz)
1050 return 0; /* fw doesn't need any host buffers */
1051
1052 /* spin till we get enough memory */
1053 while(host_page_buffer_sz > 0) {
1054
1055 if((ioc->HostPageBuffer = pci_alloc_consistent(
1056 ioc->pcidev,
1057 host_page_buffer_sz,
1058 &ioc->HostPageBuffer_dma)) != NULL) {
1059
1060 dinitprintk((MYIOC_s_INFO_FMT
1061 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
1062 ioc->name,
1063 ioc->HostPageBuffer,
1064 ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001065 host_page_buffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001066 ioc->alloc_total += host_page_buffer_sz;
1067 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1068 break;
1069 }
1070
1071 host_page_buffer_sz -= (4*1024);
1072 }
1073 }
1074
1075 if(!ioc->HostPageBuffer) {
1076 printk(MYIOC_s_ERR_FMT
1077 "Failed to alloc memory for host_page_buffer!\n",
1078 ioc->name);
1079 return -999;
1080 }
1081
1082 psge = (char *)&ioc_init->HostPageBufferSGE;
1083 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1084 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1085 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1086 MPI_SGE_FLAGS_HOST_TO_IOC |
1087 MPI_SGE_FLAGS_END_OF_BUFFER;
1088 if (sizeof(dma_addr_t) == sizeof(u64)) {
1089 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1090 }
1091 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1092 flags_length |= ioc->HostPageBuffer_sz;
1093 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1094 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1095
1096return 0;
1097}
1098
1099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1100/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
1102 * the associated MPT adapter structure.
1103 * @iocid: IOC unique identifier (integer)
1104 * @iocpp: Pointer to pointer to IOC adapter
1105 *
1106 * Returns iocid and sets iocpp.
1107 */
1108int
1109mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1110{
1111 MPT_ADAPTER *ioc;
1112
1113 list_for_each_entry(ioc,&ioc_list,list) {
1114 if (ioc->id == iocid) {
1115 *iocpp =ioc;
1116 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 *iocpp = NULL;
1121 return -1;
1122}
1123
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001124int
1125mpt_alt_ioc_wait(MPT_ADAPTER *ioc)
1126{
1127 int loop_count = 30 * 4; /* Wait 30 seconds */
1128 int status = -1; /* -1 means failed to get board READY */
1129
1130 do {
1131 spin_lock(&ioc->initializing_hba_lock);
1132 if (ioc->initializing_hba_lock_flag == 0) {
1133 ioc->initializing_hba_lock_flag=1;
1134 spin_unlock(&ioc->initializing_hba_lock);
1135 status = 0;
1136 break;
1137 }
1138 spin_unlock(&ioc->initializing_hba_lock);
1139 set_current_state(TASK_INTERRUPTIBLE);
1140 schedule_timeout(HZ/4);
1141 } while (--loop_count);
1142
1143 return status;
1144}
1145
1146/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1147/*
1148 * mpt_bringup_adapter - This is a wrapper function for mpt_do_ioc_recovery
1149 * @ioc: Pointer to MPT adapter structure
1150 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1151 *
1152 * This routine performs all the steps necessary to bring the IOC
1153 * to a OPERATIONAL state.
1154 *
1155 * Special Note: This function was added with spin lock's so as to allow
1156 * the dv(domain validation) work thread to succeed on the other channel
1157 * that maybe occuring at the same time when this function is called.
1158 * Without this lock, the dv would fail when message frames were
1159 * requested during hba bringup on the alternate ioc.
1160 */
1161static int
1162mpt_bringup_adapter(MPT_ADAPTER *ioc, int sleepFlag)
1163{
1164 int r;
1165
1166 if(ioc->alt_ioc) {
1167 if((r=mpt_alt_ioc_wait(ioc->alt_ioc)!=0))
1168 return r;
1169 }
1170
1171 r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1172 CAN_SLEEP);
1173
1174 if(ioc->alt_ioc) {
1175 spin_lock(&ioc->alt_ioc->initializing_hba_lock);
1176 ioc->alt_ioc->initializing_hba_lock_flag=0;
1177 spin_unlock(&ioc->alt_ioc->initializing_hba_lock);
1178 }
1179
1180return r;
1181}
1182
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1184/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001185 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 * @pdev: Pointer to pci_dev structure
1187 *
1188 * This routine performs all the steps necessary to bring the IOC of
1189 * a MPT adapter to a OPERATIONAL state. This includes registering
1190 * memory regions, registering the interrupt, and allocating request
1191 * and reply memory pools.
1192 *
1193 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1194 * MPT adapter.
1195 *
1196 * Returns 0 for success, non-zero for failure.
1197 *
1198 * TODO: Add support for polled controllers
1199 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001200int
1201mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 MPT_ADAPTER *ioc;
1204 u8 __iomem *mem;
1205 unsigned long mem_phys;
1206 unsigned long port;
1207 u32 msize;
1208 u32 psize;
1209 int ii;
1210 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 u8 revision;
1212 u8 pcixcmd;
1213 static int mpt_ids = 0;
1214#ifdef CONFIG_PROC_FS
1215 struct proc_dir_entry *dent, *ent;
1216#endif
1217
1218 if (pci_enable_device(pdev))
1219 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001222
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001223 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 dprintk((KERN_INFO MYNAM
1225 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001226 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1228 return r;
1229 }
1230
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001231 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 dprintk((KERN_INFO MYNAM
1233 ": Using 64 bit consistent mask\n"));
1234 else
1235 dprintk((KERN_INFO MYNAM
1236 ": Not using 64 bit consistent mask\n"));
1237
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001238 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 if (ioc == NULL) {
1240 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1241 return -ENOMEM;
1242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 ioc->alloc_total = sizeof(MPT_ADAPTER);
1244 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1245 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001246
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 ioc->pcidev = pdev;
1248 ioc->diagPending = 0;
1249 spin_lock_init(&ioc->diagLock);
Michael Reed05e8ec12006-01-13 14:31:54 -06001250 spin_lock_init(&ioc->fc_rescan_work_lock);
1251 spin_lock_init(&ioc->fc_rport_lock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001252 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 /* Initialize the event logging.
1255 */
1256 ioc->eventTypes = 0; /* None */
1257 ioc->eventContext = 0;
1258 ioc->eventLogSize = 0;
1259 ioc->events = NULL;
1260
1261#ifdef MFCNT
1262 ioc->mfcnt = 0;
1263#endif
1264
1265 ioc->cached_fw = NULL;
1266
1267 /* Initilize SCSI Config Data structure
1268 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001269 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
1271 /* Initialize the running configQ head.
1272 */
1273 INIT_LIST_HEAD(&ioc->configQ);
1274
Michael Reed05e8ec12006-01-13 14:31:54 -06001275 /* Initialize the fc rport list head.
1276 */
1277 INIT_LIST_HEAD(&ioc->fc_rports);
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 /* Find lookup slot. */
1280 INIT_LIST_HEAD(&ioc->list);
1281 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 mem_phys = msize = 0;
1284 port = psize = 0;
1285 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1286 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1287 /* Get I/O space! */
1288 port = pci_resource_start(pdev, ii);
1289 psize = pci_resource_len(pdev,ii);
1290 } else {
1291 /* Get memmap */
1292 mem_phys = pci_resource_start(pdev, ii);
1293 msize = pci_resource_len(pdev,ii);
1294 break;
1295 }
1296 }
1297 ioc->mem_size = msize;
1298
1299 if (ii == DEVICE_COUNT_RESOURCE) {
1300 printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
1301 kfree(ioc);
1302 return -EINVAL;
1303 }
1304
1305 dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
1306 dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
1307
1308 mem = NULL;
1309 /* Get logical ptr for PciMem0 space */
1310 /*mem = ioremap(mem_phys, msize);*/
1311 mem = ioremap(mem_phys, 0x100);
1312 if (mem == NULL) {
1313 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1314 kfree(ioc);
1315 return -EINVAL;
1316 }
1317 ioc->memmap = mem;
1318 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1319
1320 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1321 &ioc->facts, &ioc->pfacts[0]));
1322
1323 ioc->mem_phys = mem_phys;
1324 ioc->chip = (SYSIF_REGS __iomem *)mem;
1325
1326 /* Save Port IO values in case we need to do downloadboot */
1327 {
1328 u8 *pmem = (u8*)port;
1329 ioc->pio_mem_phys = port;
1330 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1331 }
1332
1333 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1334 ioc->prod_name = "LSIFC909";
1335 ioc->bus_type = FC;
1336 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001337 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 ioc->prod_name = "LSIFC929";
1339 ioc->bus_type = FC;
1340 }
1341 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1342 ioc->prod_name = "LSIFC919";
1343 ioc->bus_type = FC;
1344 }
1345 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1346 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1347 ioc->bus_type = FC;
1348 if (revision < XL_929) {
1349 ioc->prod_name = "LSIFC929X";
1350 /* 929X Chip Fix. Set Split transactions level
1351 * for PCIX. Set MOST bits to zero.
1352 */
1353 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1354 pcixcmd &= 0x8F;
1355 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1356 } else {
1357 ioc->prod_name = "LSIFC929XL";
1358 /* 929XL Chip Fix. Set MMRBC to 0x08.
1359 */
1360 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1361 pcixcmd |= 0x08;
1362 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1363 }
1364 }
1365 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1366 ioc->prod_name = "LSIFC919X";
1367 ioc->bus_type = FC;
1368 /* 919X Chip Fix. Set Split transactions level
1369 * for PCIX. Set MOST bits to zero.
1370 */
1371 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1372 pcixcmd &= 0x8F;
1373 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1374 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001375 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1376 ioc->prod_name = "LSIFC939X";
1377 ioc->bus_type = FC;
1378 ioc->errata_flag_1064 = 1;
1379 }
1380 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1381 ioc->prod_name = "LSIFC949X";
1382 ioc->bus_type = FC;
1383 ioc->errata_flag_1064 = 1;
1384 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001385 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1386 ioc->prod_name = "LSIFC949E";
1387 ioc->bus_type = FC;
1388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1390 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001391 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 /* 1030 Chip Fix. Disable Split transactions
1393 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1394 */
1395 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1396 if (revision < C0_1030) {
1397 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1398 pcixcmd &= 0x8F;
1399 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1400 }
1401 }
1402 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1403 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001404 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001406 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1407 ioc->prod_name = "LSISAS1064";
1408 ioc->bus_type = SAS;
1409 ioc->errata_flag_1064 = 1;
1410 }
1411 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) {
1412 ioc->prod_name = "LSISAS1066";
1413 ioc->bus_type = SAS;
1414 ioc->errata_flag_1064 = 1;
1415 }
1416 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1417 ioc->prod_name = "LSISAS1068";
1418 ioc->bus_type = SAS;
1419 ioc->errata_flag_1064 = 1;
1420 }
1421 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1422 ioc->prod_name = "LSISAS1064E";
1423 ioc->bus_type = SAS;
1424 }
1425 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) {
1426 ioc->prod_name = "LSISAS1066E";
1427 ioc->bus_type = SAS;
1428 }
1429 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1430 ioc->prod_name = "LSISAS1068E";
1431 ioc->bus_type = SAS;
1432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001434 if (ioc->errata_flag_1064)
1435 pci_disable_io_access(pdev);
1436
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 sprintf(ioc->name, "ioc%d", ioc->id);
1438
1439 spin_lock_init(&ioc->FreeQlock);
1440
1441 /* Disable all! */
1442 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1443 ioc->active = 0;
1444 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1445
1446 /* Set lookup ptr. */
1447 list_add_tail(&ioc->list, &ioc_list);
1448
1449 ioc->pci_irq = -1;
1450 if (pdev->irq) {
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001451 if (mpt_msi_enable && !pci_enable_msi(pdev))
1452 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", ioc->name);
1453
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
1455
1456 if (r < 0) {
1457#ifndef __sparc__
1458 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
1459 ioc->name, pdev->irq);
1460#else
1461 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
1462 ioc->name, __irq_itoa(pdev->irq));
1463#endif
1464 list_del(&ioc->list);
1465 iounmap(mem);
1466 kfree(ioc);
1467 return -EBUSY;
1468 }
1469
1470 ioc->pci_irq = pdev->irq;
1471
1472 pci_set_master(pdev); /* ?? */
1473 pci_set_drvdata(pdev, ioc);
1474
1475#ifndef __sparc__
1476 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
1477#else
1478 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
1479#endif
1480 }
1481
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001482 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 */
1484 mpt_detect_bound_ports(ioc, pdev);
1485
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001486 if ((r = mpt_bringup_adapter(ioc, CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 printk(KERN_WARNING MYNAM
1488 ": WARNING - %s did not initialize properly! (%d)\n",
1489 ioc->name, r);
1490
1491 list_del(&ioc->list);
1492 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001493 if (mpt_msi_enable)
1494 pci_disable_msi(pdev);
Moore, Eric335a9412006-01-17 17:06:23 -07001495 if (ioc->alt_ioc)
1496 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 iounmap(mem);
1498 kfree(ioc);
1499 pci_set_drvdata(pdev, NULL);
1500 return r;
1501 }
1502
1503 /* call per device driver probe entry point */
1504 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1505 if(MptDeviceDriverHandlers[ii] &&
1506 MptDeviceDriverHandlers[ii]->probe) {
1507 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1508 }
1509 }
1510
1511#ifdef CONFIG_PROC_FS
1512 /*
1513 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1514 */
1515 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1516 if (dent) {
1517 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1518 if (ent) {
1519 ent->read_proc = procmpt_iocinfo_read;
1520 ent->data = ioc;
1521 }
1522 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1523 if (ent) {
1524 ent->read_proc = procmpt_summary_read;
1525 ent->data = ioc;
1526 }
1527 }
1528#endif
1529
1530 return 0;
1531}
1532
1533/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1534/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001535 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 * @pdev: Pointer to pci_dev structure
1537 *
1538 */
1539
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001540void
1541mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542{
1543 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1544 char pname[32];
1545 int ii;
1546
1547 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1548 remove_proc_entry(pname, NULL);
1549 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1550 remove_proc_entry(pname, NULL);
1551 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1552 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001553
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 /* call per device driver remove entry point */
1555 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1556 if(MptDeviceDriverHandlers[ii] &&
1557 MptDeviceDriverHandlers[ii]->remove) {
1558 MptDeviceDriverHandlers[ii]->remove(pdev);
1559 }
1560 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001561
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 /* Disable interrupts! */
1563 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1564
1565 ioc->active = 0;
1566 synchronize_irq(pdev->irq);
1567
1568 /* Clear any lingering interrupt */
1569 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1570
1571 CHIPREG_READ32(&ioc->chip->IntStatus);
1572
1573 mpt_adapter_dispose(ioc);
1574
1575 pci_set_drvdata(pdev, NULL);
1576}
1577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578/**************************************************************************
1579 * Power Management
1580 */
1581#ifdef CONFIG_PM
1582/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1583/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001584 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 *
1586 *
1587 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001588int
1589mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590{
1591 u32 device_state;
1592 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
Pavel Machek2a569572005-07-07 17:56:40 -07001594 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596 printk(MYIOC_s_INFO_FMT
1597 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1598 ioc->name, pdev, pci_name(pdev), device_state);
1599
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 pci_save_state(pdev);
1601
1602 /* put ioc into READY_STATE */
1603 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1604 printk(MYIOC_s_ERR_FMT
1605 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1606 }
1607
1608 /* disable interrupts */
1609 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1610 ioc->active = 0;
1611
1612 /* Clear any lingering interrupt */
1613 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1614
1615 pci_disable_device(pdev);
1616 pci_set_power_state(pdev, device_state);
1617
1618 return 0;
1619}
1620
1621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1622/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001623 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 *
1625 *
1626 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001627int
1628mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629{
1630 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1631 u32 device_state = pdev->current_state;
1632 int recovery_state;
1633 int ii;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001634
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 printk(MYIOC_s_INFO_FMT
1636 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1637 ioc->name, pdev, pci_name(pdev), device_state);
1638
1639 pci_set_power_state(pdev, 0);
1640 pci_restore_state(pdev);
1641 pci_enable_device(pdev);
1642
1643 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001644 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 ioc->active = 1;
1646
1647 /* F/W not running */
1648 if(!CHIPREG_READ32(&ioc->chip->Doorbell)) {
1649 /* enable domain validation flags */
1650 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
1651 ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_NEED_DV;
1652 }
1653 }
1654
1655 printk(MYIOC_s_INFO_FMT
1656 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1657 ioc->name,
1658 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1659 CHIPREG_READ32(&ioc->chip->Doorbell));
1660
1661 /* bring ioc to operational state */
1662 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1663 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1664 printk(MYIOC_s_INFO_FMT
1665 "pci-resume: Cannot recover, error:[%x]\n",
1666 ioc->name, recovery_state);
1667 } else {
1668 printk(MYIOC_s_INFO_FMT
1669 "pci-resume: success\n", ioc->name);
1670 }
1671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 return 0;
1673}
1674#endif
1675
1676/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1677/*
1678 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1679 * @ioc: Pointer to MPT adapter structure
1680 * @reason: Event word / reason
1681 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1682 *
1683 * This routine performs all the steps necessary to bring the IOC
1684 * to a OPERATIONAL state.
1685 *
1686 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1687 * MPT adapter.
1688 *
1689 * Returns:
1690 * 0 for success
1691 * -1 if failed to get board READY
1692 * -2 if READY but IOCFacts Failed
1693 * -3 if READY but PrimeIOCFifos Failed
1694 * -4 if READY but IOCInit Failed
1695 */
1696static int
1697mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1698{
1699 int hard_reset_done = 0;
1700 int alt_ioc_ready = 0;
1701 int hard;
1702 int rc=0;
1703 int ii;
1704 int handlers;
1705 int ret = 0;
1706 int reset_alt_ioc_active = 0;
1707
1708 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1709 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1710
1711 /* Disable reply interrupts (also blocks FreeQ) */
1712 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1713 ioc->active = 0;
1714
1715 if (ioc->alt_ioc) {
1716 if (ioc->alt_ioc->active)
1717 reset_alt_ioc_active = 1;
1718
1719 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1720 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1721 ioc->alt_ioc->active = 0;
1722 }
1723
1724 hard = 1;
1725 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1726 hard = 0;
1727
1728 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1729 if (hard_reset_done == -4) {
1730 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1731 ioc->name);
1732
1733 if (reset_alt_ioc_active && ioc->alt_ioc) {
1734 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1735 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1736 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001737 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 ioc->alt_ioc->active = 1;
1739 }
1740
1741 } else {
1742 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1743 ioc->name);
1744 }
1745 return -1;
1746 }
1747
1748 /* hard_reset_done = 0 if a soft reset was performed
1749 * and 1 if a hard reset was performed.
1750 */
1751 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1752 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1753 alt_ioc_ready = 1;
1754 else
1755 printk(KERN_WARNING MYNAM
1756 ": alt-%s: Not ready WARNING!\n",
1757 ioc->alt_ioc->name);
1758 }
1759
1760 for (ii=0; ii<5; ii++) {
1761 /* Get IOC facts! Allow 5 retries */
1762 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1763 break;
1764 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 if (ii == 5) {
1768 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1769 ret = -2;
1770 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1771 MptDisplayIocCapabilities(ioc);
1772 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 if (alt_ioc_ready) {
1775 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1776 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1777 /* Retry - alt IOC was initialized once
1778 */
1779 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1780 }
1781 if (rc) {
1782 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1783 alt_ioc_ready = 0;
1784 reset_alt_ioc_active = 0;
1785 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1786 MptDisplayIocCapabilities(ioc->alt_ioc);
1787 }
1788 }
1789
1790 /* Prime reply & request queues!
1791 * (mucho alloc's) Must be done prior to
1792 * init as upper addresses are needed for init.
1793 * If fails, continue with alt-ioc processing
1794 */
1795 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1796 ret = -3;
1797
1798 /* May need to check/upload firmware & data here!
1799 * If fails, continue with alt-ioc processing
1800 */
1801 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1802 ret = -4;
1803// NEW!
1804 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1805 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1806 ioc->alt_ioc->name, rc);
1807 alt_ioc_ready = 0;
1808 reset_alt_ioc_active = 0;
1809 }
1810
1811 if (alt_ioc_ready) {
1812 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1813 alt_ioc_ready = 0;
1814 reset_alt_ioc_active = 0;
1815 printk(KERN_WARNING MYNAM
1816 ": alt-%s: (%d) init failure WARNING!\n",
1817 ioc->alt_ioc->name, rc);
1818 }
1819 }
1820
1821 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1822 if (ioc->upload_fw) {
1823 ddlprintk((MYIOC_s_INFO_FMT
1824 "firmware upload required!\n", ioc->name));
1825
1826 /* Controller is not operational, cannot do upload
1827 */
1828 if (ret == 0) {
1829 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001830 if (rc == 0) {
1831 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1832 /*
1833 * Maintain only one pointer to FW memory
1834 * so there will not be two attempt to
1835 * downloadboot onboard dual function
1836 * chips (mpt_adapter_disable,
1837 * mpt_diag_reset)
1838 */
1839 ioc->cached_fw = NULL;
1840 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1841 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1842 }
1843 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001845 ret = -5;
1846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 }
1848 }
1849 }
1850
1851 if (ret == 0) {
1852 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001853 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 ioc->active = 1;
1855 }
1856
1857 if (reset_alt_ioc_active && ioc->alt_ioc) {
1858 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001859 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001861 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 ioc->alt_ioc->active = 1;
1863 }
1864
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001865 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 * and EventAck handling.
1867 */
1868 if ((ret == 0) && (!ioc->facts.EventState))
1869 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1870
1871 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1872 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1873
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001874 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1876 * recursive scenario; GetLanConfigPages times out, timer expired
1877 * routine calls HardResetHandler, which calls into here again,
1878 * and we try GetLanConfigPages again...
1879 */
1880 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001881 if (ioc->bus_type == SAS) {
1882
1883 /* clear persistency table */
1884 if(ioc->facts.IOCExceptions &
1885 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1886 ret = mptbase_sas_persist_operation(ioc,
1887 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1888 if(ret != 0)
1889 return -1;
1890 }
1891
1892 /* Find IM volumes
1893 */
1894 mpt_findImVolumes(ioc);
1895
1896 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 /*
1898 * Pre-fetch FC port WWN and stuff...
1899 * (FCPortPage0_t stuff)
1900 */
1901 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
Michael Reed05e8ec12006-01-13 14:31:54 -06001902 (void) mptbase_GetFcPortPage0(ioc, ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 }
1904
1905 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1906 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1907 /*
1908 * Pre-fetch the ports LAN MAC address!
1909 * (LANPage1_t stuff)
1910 */
1911 (void) GetLanConfigPages(ioc);
1912#ifdef MPT_DEBUG
1913 {
1914 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1915 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1916 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1917 }
1918#endif
1919 }
1920 } else {
1921 /* Get NVRAM and adapter maximums from SPP 0 and 2
1922 */
1923 mpt_GetScsiPortSettings(ioc, 0);
1924
1925 /* Get version and length of SDP 1
1926 */
1927 mpt_readScsiDevicePageHeaders(ioc, 0);
1928
1929 /* Find IM volumes
1930 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001931 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 mpt_findImVolumes(ioc);
1933
1934 /* Check, and possibly reset, the coalescing value
1935 */
1936 mpt_read_ioc_pg_1(ioc);
1937
1938 mpt_read_ioc_pg_4(ioc);
1939 }
1940
1941 GetIoUnitPage2(ioc);
1942 }
1943
1944 /*
1945 * Call each currently registered protocol IOC reset handler
1946 * with post-reset indication.
1947 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1948 * MptResetHandlers[] registered yet.
1949 */
1950 if (hard_reset_done) {
1951 rc = handlers = 0;
1952 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1953 if ((ret == 0) && MptResetHandlers[ii]) {
1954 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1955 ioc->name, ii));
1956 rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
1957 handlers++;
1958 }
1959
1960 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001961 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 ioc->name, ioc->alt_ioc->name, ii));
1963 rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
1964 handlers++;
1965 }
1966 }
1967 /* FIXME? Examine results here? */
1968 }
1969
1970 return ret;
1971}
1972
1973/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1974/*
1975 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1976 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1977 * 929X, 1030 or 1035.
1978 * @ioc: Pointer to MPT adapter structure
1979 * @pdev: Pointer to (struct pci_dev) structure
1980 *
1981 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1982 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1983 */
1984static void
1985mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1986{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001987 struct pci_dev *peer=NULL;
1988 unsigned int slot = PCI_SLOT(pdev->devfn);
1989 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 MPT_ADAPTER *ioc_srch;
1991
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001992 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1993 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001994 ioc->name, pci_name(pdev), pdev->bus->number,
1995 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001996
1997 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1998 if (!peer) {
1999 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2000 if (!peer)
2001 return;
2002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003
2004 list_for_each_entry(ioc_srch, &ioc_list, list) {
2005 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002006 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 /* Paranoia checks */
2008 if (ioc->alt_ioc != NULL) {
2009 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002010 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 break;
2012 } else if (ioc_srch->alt_ioc != NULL) {
2013 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002014 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 break;
2016 }
2017 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002018 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 ioc_srch->alt_ioc = ioc;
2020 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 }
2022 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002023 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024}
2025
2026/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2027/*
2028 * mpt_adapter_disable - Disable misbehaving MPT adapter.
2029 * @this: Pointer to MPT adapter structure
2030 */
2031static void
2032mpt_adapter_disable(MPT_ADAPTER *ioc)
2033{
2034 int sz;
2035 int ret;
2036
2037 if (ioc->cached_fw != NULL) {
2038 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002039 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 printk(KERN_WARNING MYNAM
2041 ": firmware downloadboot failure (%d)!\n", ret);
2042 }
2043 }
2044
2045 /* Disable adapter interrupts! */
2046 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2047 ioc->active = 0;
2048 /* Clear any lingering interrupt */
2049 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2050
2051 if (ioc->alloc != NULL) {
2052 sz = ioc->alloc_sz;
2053 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
2054 ioc->name, ioc->alloc, ioc->alloc_sz));
2055 pci_free_consistent(ioc->pcidev, sz,
2056 ioc->alloc, ioc->alloc_dma);
2057 ioc->reply_frames = NULL;
2058 ioc->req_frames = NULL;
2059 ioc->alloc = NULL;
2060 ioc->alloc_total -= sz;
2061 }
2062
2063 if (ioc->sense_buf_pool != NULL) {
2064 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2065 pci_free_consistent(ioc->pcidev, sz,
2066 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2067 ioc->sense_buf_pool = NULL;
2068 ioc->alloc_total -= sz;
2069 }
2070
2071 if (ioc->events != NULL){
2072 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2073 kfree(ioc->events);
2074 ioc->events = NULL;
2075 ioc->alloc_total -= sz;
2076 }
2077
2078 if (ioc->cached_fw != NULL) {
2079 sz = ioc->facts.FWImageSize;
2080 pci_free_consistent(ioc->pcidev, sz,
2081 ioc->cached_fw, ioc->cached_fw_dma);
2082 ioc->cached_fw = NULL;
2083 ioc->alloc_total -= sz;
2084 }
2085
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002086 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002087 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002088 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002089 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
2091 if (ioc->spi_data.pIocPg4 != NULL) {
2092 sz = ioc->spi_data.IocPg4Sz;
2093 pci_free_consistent(ioc->pcidev, sz,
2094 ioc->spi_data.pIocPg4,
2095 ioc->spi_data.IocPg4_dma);
2096 ioc->spi_data.pIocPg4 = NULL;
2097 ioc->alloc_total -= sz;
2098 }
2099
2100 if (ioc->ReqToChain != NULL) {
2101 kfree(ioc->ReqToChain);
2102 kfree(ioc->RequestNB);
2103 ioc->ReqToChain = NULL;
2104 }
2105
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002106 kfree(ioc->ChainToChain);
2107 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002108
2109 if (ioc->HostPageBuffer != NULL) {
2110 if((ret = mpt_host_page_access_control(ioc,
2111 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2112 printk(KERN_ERR MYNAM
2113 ": %s: host page buffers free failed (%d)!\n",
2114 __FUNCTION__, ret);
2115 }
2116 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2117 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2118 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2119 ioc->HostPageBuffer,
2120 ioc->HostPageBuffer_dma);
2121 ioc->HostPageBuffer = NULL;
2122 ioc->HostPageBuffer_sz = 0;
2123 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125}
2126
2127/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2128/*
2129 * mpt_adapter_dispose - Free all resources associated with a MPT
2130 * adapter.
2131 * @ioc: Pointer to MPT adapter structure
2132 *
2133 * This routine unregisters h/w resources and frees all alloc'd memory
2134 * associated with a MPT adapter structure.
2135 */
2136static void
2137mpt_adapter_dispose(MPT_ADAPTER *ioc)
2138{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002139 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002141 if (ioc == NULL)
2142 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002144 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002146 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002148 if (ioc->pci_irq != -1) {
2149 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002150 if (mpt_msi_enable)
2151 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002152 ioc->pci_irq = -1;
2153 }
2154
2155 if (ioc->memmap != NULL) {
2156 iounmap(ioc->memmap);
2157 ioc->memmap = NULL;
2158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159
2160#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002161 if (ioc->mtrr_reg > 0) {
2162 mtrr_del(ioc->mtrr_reg, 0, 0);
2163 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165#endif
2166
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002167 /* Zap the adapter lookup ptr! */
2168 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002170 sz_last = ioc->alloc_total;
2171 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2172 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002173
2174 if (ioc->alt_ioc)
2175 ioc->alt_ioc->alt_ioc = NULL;
2176
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002177 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178}
2179
2180/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2181/*
2182 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2183 * @ioc: Pointer to MPT adapter structure
2184 */
2185static void
2186MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2187{
2188 int i = 0;
2189
2190 printk(KERN_INFO "%s: ", ioc->name);
2191 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2192 printk("%s: ", ioc->prod_name+3);
2193 printk("Capabilities={");
2194
2195 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2196 printk("Initiator");
2197 i++;
2198 }
2199
2200 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2201 printk("%sTarget", i ? "," : "");
2202 i++;
2203 }
2204
2205 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2206 printk("%sLAN", i ? "," : "");
2207 i++;
2208 }
2209
2210#if 0
2211 /*
2212 * This would probably evoke more questions than it's worth
2213 */
2214 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2215 printk("%sLogBusAddr", i ? "," : "");
2216 i++;
2217 }
2218#endif
2219
2220 printk("}\n");
2221}
2222
2223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2224/*
2225 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2226 * @ioc: Pointer to MPT_ADAPTER structure
2227 * @force: Force hard KickStart of IOC
2228 * @sleepFlag: Specifies whether the process can sleep
2229 *
2230 * Returns:
2231 * 1 - DIAG reset and READY
2232 * 0 - READY initially OR soft reset and READY
2233 * -1 - Any failure on KickStart
2234 * -2 - Msg Unit Reset Failed
2235 * -3 - IO Unit Reset Failed
2236 * -4 - IOC owned by a PEER
2237 */
2238static int
2239MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2240{
2241 u32 ioc_state;
2242 int statefault = 0;
2243 int cntdn;
2244 int hard_reset_done = 0;
2245 int r;
2246 int ii;
2247 int whoinit;
2248
2249 /* Get current [raw] IOC state */
2250 ioc_state = mpt_GetIocState(ioc, 0);
2251 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2252
2253 /*
2254 * Check to see if IOC got left/stuck in doorbell handshake
2255 * grip of death. If so, hard reset the IOC.
2256 */
2257 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2258 statefault = 1;
2259 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2260 ioc->name);
2261 }
2262
2263 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002264 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 return 0;
2266
2267 /*
2268 * Check to see if IOC is in FAULT state.
2269 */
2270 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2271 statefault = 2;
2272 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2273 ioc->name);
2274 printk(KERN_WARNING " FAULT code = %04xh\n",
2275 ioc_state & MPI_DOORBELL_DATA_MASK);
2276 }
2277
2278 /*
2279 * Hmmm... Did it get left operational?
2280 */
2281 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002282 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 ioc->name));
2284
2285 /* Check WhoInit.
2286 * If PCI Peer, exit.
2287 * Else, if no fault conditions are present, issue a MessageUnitReset
2288 * Else, fall through to KickStart case
2289 */
2290 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002291 dinitprintk((KERN_INFO MYNAM
2292 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 whoinit, statefault, force));
2294 if (whoinit == MPI_WHOINIT_PCI_PEER)
2295 return -4;
2296 else {
2297 if ((statefault == 0 ) && (force == 0)) {
2298 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2299 return 0;
2300 }
2301 statefault = 3;
2302 }
2303 }
2304
2305 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2306 if (hard_reset_done < 0)
2307 return -1;
2308
2309 /*
2310 * Loop here waiting for IOC to come READY.
2311 */
2312 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002313 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
2315 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2316 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2317 /*
2318 * BIOS or previous driver load left IOC in OP state.
2319 * Reset messaging FIFOs.
2320 */
2321 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2322 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2323 return -2;
2324 }
2325 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2326 /*
2327 * Something is wrong. Try to get IOC back
2328 * to a known state.
2329 */
2330 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2331 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2332 return -3;
2333 }
2334 }
2335
2336 ii++; cntdn--;
2337 if (!cntdn) {
2338 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2339 ioc->name, (int)((ii+5)/HZ));
2340 return -ETIME;
2341 }
2342
2343 if (sleepFlag == CAN_SLEEP) {
2344 msleep_interruptible(1);
2345 } else {
2346 mdelay (1); /* 1 msec delay */
2347 }
2348
2349 }
2350
2351 if (statefault < 3) {
2352 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2353 ioc->name,
2354 statefault==1 ? "stuck handshake" : "IOC FAULT");
2355 }
2356
2357 return hard_reset_done;
2358}
2359
2360/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2361/*
2362 * mpt_GetIocState - Get the current state of a MPT adapter.
2363 * @ioc: Pointer to MPT_ADAPTER structure
2364 * @cooked: Request raw or cooked IOC state
2365 *
2366 * Returns all IOC Doorbell register bits if cooked==0, else just the
2367 * Doorbell bits in MPI_IOC_STATE_MASK.
2368 */
2369u32
2370mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2371{
2372 u32 s, sc;
2373
2374 /* Get! */
2375 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2376// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2377 sc = s & MPI_IOC_STATE_MASK;
2378
2379 /* Save! */
2380 ioc->last_state = sc;
2381
2382 return cooked ? sc : s;
2383}
2384
2385/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2386/*
2387 * GetIocFacts - Send IOCFacts request to MPT adapter.
2388 * @ioc: Pointer to MPT_ADAPTER structure
2389 * @sleepFlag: Specifies whether the process can sleep
2390 * @reason: If recovery, only update facts.
2391 *
2392 * Returns 0 for success, non-zero for failure.
2393 */
2394static int
2395GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2396{
2397 IOCFacts_t get_facts;
2398 IOCFactsReply_t *facts;
2399 int r;
2400 int req_sz;
2401 int reply_sz;
2402 int sz;
2403 u32 status, vv;
2404 u8 shiftFactor=1;
2405
2406 /* IOC *must* NOT be in RESET state! */
2407 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2408 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2409 ioc->name,
2410 ioc->last_state );
2411 return -44;
2412 }
2413
2414 facts = &ioc->facts;
2415
2416 /* Destination (reply area)... */
2417 reply_sz = sizeof(*facts);
2418 memset(facts, 0, reply_sz);
2419
2420 /* Request area (get_facts on the stack right now!) */
2421 req_sz = sizeof(get_facts);
2422 memset(&get_facts, 0, req_sz);
2423
2424 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2425 /* Assert: All other get_facts fields are zero! */
2426
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002427 dinitprintk((MYIOC_s_INFO_FMT
2428 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 ioc->name, req_sz, reply_sz));
2430
2431 /* No non-zero fields in the get_facts request are greater than
2432 * 1 byte in size, so we can just fire it off as is.
2433 */
2434 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2435 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2436 if (r != 0)
2437 return r;
2438
2439 /*
2440 * Now byte swap (GRRR) the necessary fields before any further
2441 * inspection of reply contents.
2442 *
2443 * But need to do some sanity checks on MsgLength (byte) field
2444 * to make sure we don't zero IOC's req_sz!
2445 */
2446 /* Did we get a valid reply? */
2447 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2448 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2449 /*
2450 * If not been here, done that, save off first WhoInit value
2451 */
2452 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2453 ioc->FirstWhoInit = facts->WhoInit;
2454 }
2455
2456 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2457 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2458 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2459 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2460 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002461 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 /* CHECKME! IOCStatus, IOCLogInfo */
2463
2464 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2465 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2466
2467 /*
2468 * FC f/w version changed between 1.1 and 1.2
2469 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2470 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2471 */
2472 if (facts->MsgVersion < 0x0102) {
2473 /*
2474 * Handle old FC f/w style, convert to new...
2475 */
2476 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2477 facts->FWVersion.Word =
2478 ((oldv<<12) & 0xFF000000) |
2479 ((oldv<<8) & 0x000FFF00);
2480 } else
2481 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2482
2483 facts->ProductID = le16_to_cpu(facts->ProductID);
2484 facts->CurrentHostMfaHighAddr =
2485 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2486 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2487 facts->CurrentSenseBufferHighAddr =
2488 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2489 facts->CurReplyFrameSize =
2490 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002491 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
2493 /*
2494 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2495 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2496 * to 14 in MPI-1.01.0x.
2497 */
2498 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2499 facts->MsgVersion > 0x0100) {
2500 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2501 }
2502
2503 sz = facts->FWImageSize;
2504 if ( sz & 0x01 )
2505 sz += 1;
2506 if ( sz & 0x02 )
2507 sz += 2;
2508 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002509
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 if (!facts->RequestFrameSize) {
2511 /* Something is wrong! */
2512 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2513 ioc->name);
2514 return -55;
2515 }
2516
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002517 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 vv = ((63 / (sz * 4)) + 1) & 0x03;
2519 ioc->NB_for_64_byte_frame = vv;
2520 while ( sz )
2521 {
2522 shiftFactor++;
2523 sz = sz >> 1;
2524 }
2525 ioc->NBShiftFactor = shiftFactor;
2526 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2527 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002528
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2530 /*
2531 * Set values for this IOC's request & reply frame sizes,
2532 * and request & reply queue depths...
2533 */
2534 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2535 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2536 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2537 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2538
2539 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2540 ioc->name, ioc->reply_sz, ioc->reply_depth));
2541 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2542 ioc->name, ioc->req_sz, ioc->req_depth));
2543
2544 /* Get port facts! */
2545 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2546 return r;
2547 }
2548 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002549 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2551 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2552 RequestFrameSize)/sizeof(u32)));
2553 return -66;
2554 }
2555
2556 return 0;
2557}
2558
2559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2560/*
2561 * GetPortFacts - Send PortFacts request to MPT adapter.
2562 * @ioc: Pointer to MPT_ADAPTER structure
2563 * @portnum: Port number
2564 * @sleepFlag: Specifies whether the process can sleep
2565 *
2566 * Returns 0 for success, non-zero for failure.
2567 */
2568static int
2569GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2570{
2571 PortFacts_t get_pfacts;
2572 PortFactsReply_t *pfacts;
2573 int ii;
2574 int req_sz;
2575 int reply_sz;
2576
2577 /* IOC *must* NOT be in RESET state! */
2578 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2579 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2580 ioc->name,
2581 ioc->last_state );
2582 return -4;
2583 }
2584
2585 pfacts = &ioc->pfacts[portnum];
2586
2587 /* Destination (reply area)... */
2588 reply_sz = sizeof(*pfacts);
2589 memset(pfacts, 0, reply_sz);
2590
2591 /* Request area (get_pfacts on the stack right now!) */
2592 req_sz = sizeof(get_pfacts);
2593 memset(&get_pfacts, 0, req_sz);
2594
2595 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2596 get_pfacts.PortNumber = portnum;
2597 /* Assert: All other get_pfacts fields are zero! */
2598
2599 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2600 ioc->name, portnum));
2601
2602 /* No non-zero fields in the get_pfacts request are greater than
2603 * 1 byte in size, so we can just fire it off as is.
2604 */
2605 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2606 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2607 if (ii != 0)
2608 return ii;
2609
2610 /* Did we get a valid reply? */
2611
2612 /* Now byte swap the necessary fields in the response. */
2613 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2614 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2615 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2616 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2617 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2618 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2619 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2620 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2621 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2622
2623 return 0;
2624}
2625
2626/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2627/*
2628 * SendIocInit - Send IOCInit request to MPT adapter.
2629 * @ioc: Pointer to MPT_ADAPTER structure
2630 * @sleepFlag: Specifies whether the process can sleep
2631 *
2632 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2633 *
2634 * Returns 0 for success, non-zero for failure.
2635 */
2636static int
2637SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2638{
2639 IOCInit_t ioc_init;
2640 MPIDefaultReply_t init_reply;
2641 u32 state;
2642 int r;
2643 int count;
2644 int cntdn;
2645
2646 memset(&ioc_init, 0, sizeof(ioc_init));
2647 memset(&init_reply, 0, sizeof(init_reply));
2648
2649 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2650 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2651
2652 /* If we are in a recovery mode and we uploaded the FW image,
2653 * then this pointer is not NULL. Skip the upload a second time.
2654 * Set this flag if cached_fw set for either IOC.
2655 */
2656 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2657 ioc->upload_fw = 1;
2658 else
2659 ioc->upload_fw = 0;
2660 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2661 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2662
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002663 if(ioc->bus_type == SAS)
2664 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2665 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2667 else
2668 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002670 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2671 ioc->name, ioc->facts.MsgVersion));
2672 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2673 // set MsgVersion and HeaderVersion host driver was built with
2674 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2675 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002677 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2678 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2679 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2680 return -99;
2681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2683
2684 if (sizeof(dma_addr_t) == sizeof(u64)) {
2685 /* Save the upper 32-bits of the request
2686 * (reply) and sense buffers.
2687 */
2688 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2689 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2690 } else {
2691 /* Force 32-bit addressing */
2692 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2693 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2694 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002695
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2697 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002698 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2699 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
2701 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2702 ioc->name, &ioc_init));
2703
2704 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2705 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002706 if (r != 0) {
2707 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710
2711 /* No need to byte swap the multibyte fields in the reply
2712 * since we don't even look at it's contents.
2713 */
2714
2715 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2716 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002717
2718 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2719 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002721 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
2723 /* YIKES! SUPER IMPORTANT!!!
2724 * Poll IocState until _OPERATIONAL while IOC is doing
2725 * LoopInit and TargetDiscovery!
2726 */
2727 count = 0;
2728 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2729 state = mpt_GetIocState(ioc, 1);
2730 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2731 if (sleepFlag == CAN_SLEEP) {
2732 msleep_interruptible(1);
2733 } else {
2734 mdelay(1);
2735 }
2736
2737 if (!cntdn) {
2738 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2739 ioc->name, (int)((count+5)/HZ));
2740 return -9;
2741 }
2742
2743 state = mpt_GetIocState(ioc, 1);
2744 count++;
2745 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002746 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 ioc->name, count));
2748
2749 return r;
2750}
2751
2752/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2753/*
2754 * SendPortEnable - Send PortEnable request to MPT adapter port.
2755 * @ioc: Pointer to MPT_ADAPTER structure
2756 * @portnum: Port number to enable
2757 * @sleepFlag: Specifies whether the process can sleep
2758 *
2759 * Send PortEnable to bring IOC to OPERATIONAL state.
2760 *
2761 * Returns 0 for success, non-zero for failure.
2762 */
2763static int
2764SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2765{
2766 PortEnable_t port_enable;
2767 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002768 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 int req_sz;
2770 int reply_sz;
2771
2772 /* Destination... */
2773 reply_sz = sizeof(MPIDefaultReply_t);
2774 memset(&reply_buf, 0, reply_sz);
2775
2776 req_sz = sizeof(PortEnable_t);
2777 memset(&port_enable, 0, req_sz);
2778
2779 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2780 port_enable.PortNumber = portnum;
2781/* port_enable.ChainOffset = 0; */
2782/* port_enable.MsgFlags = 0; */
2783/* port_enable.MsgContext = 0; */
2784
2785 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2786 ioc->name, portnum, &port_enable));
2787
2788 /* RAID FW may take a long time to enable
2789 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002790 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2791 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2792 (ioc->bus_type == SAS)) {
2793 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2794 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2795 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002796 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002797 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2798 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2799 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002801 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802}
2803
2804/*
2805 * ioc: Pointer to MPT_ADAPTER structure
2806 * size - total FW bytes
2807 */
2808void
2809mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2810{
2811 if (ioc->cached_fw)
2812 return; /* use already allocated memory */
2813 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2814 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2815 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2816 } else {
2817 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2818 ioc->alloc_total += size;
2819 }
2820}
2821/*
2822 * If alt_img is NULL, delete from ioc structure.
2823 * Else, delete a secondary image in same format.
2824 */
2825void
2826mpt_free_fw_memory(MPT_ADAPTER *ioc)
2827{
2828 int sz;
2829
2830 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002831 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2833 pci_free_consistent(ioc->pcidev, sz,
2834 ioc->cached_fw, ioc->cached_fw_dma);
2835 ioc->cached_fw = NULL;
2836
2837 return;
2838}
2839
2840
2841/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2842/*
2843 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2844 * @ioc: Pointer to MPT_ADAPTER structure
2845 * @sleepFlag: Specifies whether the process can sleep
2846 *
2847 * Returns 0 for success, >0 for handshake failure
2848 * <0 for fw upload failure.
2849 *
2850 * Remark: If bound IOC and a successful FWUpload was performed
2851 * on the bound IOC, the second image is discarded
2852 * and memory is free'd. Both channels must upload to prevent
2853 * IOC from running in degraded mode.
2854 */
2855static int
2856mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2857{
2858 u8 request[ioc->req_sz];
2859 u8 reply[sizeof(FWUploadReply_t)];
2860 FWUpload_t *prequest;
2861 FWUploadReply_t *preply;
2862 FWUploadTCSGE_t *ptcsge;
2863 int sgeoffset;
2864 u32 flagsLength;
2865 int ii, sz, reply_sz;
2866 int cmdStatus;
2867
2868 /* If the image size is 0, we are done.
2869 */
2870 if ((sz = ioc->facts.FWImageSize) == 0)
2871 return 0;
2872
2873 mpt_alloc_fw_memory(ioc, sz);
2874
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002875 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002877
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 if (ioc->cached_fw == NULL) {
2879 /* Major Failure.
2880 */
2881 return -ENOMEM;
2882 }
2883
2884 prequest = (FWUpload_t *)&request;
2885 preply = (FWUploadReply_t *)&reply;
2886
2887 /* Destination... */
2888 memset(prequest, 0, ioc->req_sz);
2889
2890 reply_sz = sizeof(reply);
2891 memset(preply, 0, reply_sz);
2892
2893 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2894 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2895
2896 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2897 ptcsge->DetailsLength = 12;
2898 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2899 ptcsge->ImageSize = cpu_to_le32(sz);
2900
2901 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2902
2903 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2904 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2905
2906 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002907 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 prequest, sgeoffset));
2909 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2910
2911 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2912 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2913
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002914 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915
2916 cmdStatus = -EFAULT;
2917 if (ii == 0) {
2918 /* Handshake transfer was complete and successful.
2919 * Check the Reply Frame.
2920 */
2921 int status, transfer_sz;
2922 status = le16_to_cpu(preply->IOCStatus);
2923 if (status == MPI_IOCSTATUS_SUCCESS) {
2924 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2925 if (transfer_sz == sz)
2926 cmdStatus = 0;
2927 }
2928 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002929 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 ioc->name, cmdStatus));
2931
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002932
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 if (cmdStatus) {
2934
2935 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2936 ioc->name));
2937 mpt_free_fw_memory(ioc);
2938 }
2939
2940 return cmdStatus;
2941}
2942
2943/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2944/*
2945 * mpt_downloadboot - DownloadBoot code
2946 * @ioc: Pointer to MPT_ADAPTER structure
2947 * @flag: Specify which part of IOC memory is to be uploaded.
2948 * @sleepFlag: Specifies whether the process can sleep
2949 *
2950 * FwDownloadBoot requires Programmed IO access.
2951 *
2952 * Returns 0 for success
2953 * -1 FW Image size is 0
2954 * -2 No valid cached_fw Pointer
2955 * <0 for fw upload failure.
2956 */
2957static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002958mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 MpiExtImageHeader_t *pExtImage;
2961 u32 fwSize;
2962 u32 diag0val;
2963 int count;
2964 u32 *ptrFw;
2965 u32 diagRwData;
2966 u32 nextImage;
2967 u32 load_addr;
2968 u32 ioc_state=0;
2969
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002970 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2971 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002972
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2974 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2975 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2976 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2977 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2978 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2979
2980 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2981
2982 /* wait 1 msec */
2983 if (sleepFlag == CAN_SLEEP) {
2984 msleep_interruptible(1);
2985 } else {
2986 mdelay (1);
2987 }
2988
2989 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2990 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2991
2992 for (count = 0; count < 30; count ++) {
2993 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2994 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2995 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2996 ioc->name, count));
2997 break;
2998 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002999 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003001 msleep_interruptible (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003003 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 }
3005 }
3006
3007 if ( count == 30 ) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003008 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
3009 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 ioc->name, diag0val));
3011 return -3;
3012 }
3013
3014 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3015 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3016 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3017 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3018 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3019 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3020
3021 /* Set the DiagRwEn and Disable ARM bits */
3022 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3023
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 fwSize = (pFwHeader->ImageSize + 3)/4;
3025 ptrFw = (u32 *) pFwHeader;
3026
3027 /* Write the LoadStartAddress to the DiagRw Address Register
3028 * using Programmed IO
3029 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003030 if (ioc->errata_flag_1064)
3031 pci_enable_io_access(ioc->pcidev);
3032
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
3034 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
3035 ioc->name, pFwHeader->LoadStartAddress));
3036
3037 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
3038 ioc->name, fwSize*4, ptrFw));
3039 while (fwSize--) {
3040 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3041 }
3042
3043 nextImage = pFwHeader->NextImageHeaderOffset;
3044 while (nextImage) {
3045 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3046
3047 load_addr = pExtImage->LoadStartAddress;
3048
3049 fwSize = (pExtImage->ImageSize + 3) >> 2;
3050 ptrFw = (u32 *)pExtImage;
3051
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003052 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
3053 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3055
3056 while (fwSize--) {
3057 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3058 }
3059 nextImage = pExtImage->NextImageHeaderOffset;
3060 }
3061
3062 /* Write the IopResetVectorRegAddr */
3063 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3064 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3065
3066 /* Write the IopResetVectorValue */
3067 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3068 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3069
3070 /* Clear the internal flash bad bit - autoincrementing register,
3071 * so must do two writes.
3072 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003073 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003074 /*
3075 * 1030 and 1035 H/W errata, workaround to access
3076 * the ClearFlashBadSignatureBit
3077 */
3078 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3079 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3080 diagRwData |= 0x40000000;
3081 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3082 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3083
3084 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3085 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3086 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3087 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3088
3089 /* wait 1 msec */
3090 if (sleepFlag == CAN_SLEEP) {
3091 msleep_interruptible (1);
3092 } else {
3093 mdelay (1);
3094 }
3095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003097 if (ioc->errata_flag_1064)
3098 pci_disable_io_access(ioc->pcidev);
3099
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003101 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3102 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003104 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3106 ioc->name, diag0val));
3107 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3108
3109 /* Write 0xFF to reset the sequencer */
3110 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3111
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003112 if (ioc->bus_type == SAS) {
3113 ioc_state = mpt_GetIocState(ioc, 0);
3114 if ( (GetIocFacts(ioc, sleepFlag,
3115 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3116 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3117 ioc->name, ioc_state));
3118 return -EFAULT;
3119 }
3120 }
3121
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 for (count=0; count<HZ*20; count++) {
3123 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3124 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3125 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003126 if (ioc->bus_type == SAS) {
3127 return 0;
3128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3130 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3131 ioc->name));
3132 return -EFAULT;
3133 }
3134 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3135 ioc->name));
3136 return 0;
3137 }
3138 if (sleepFlag == CAN_SLEEP) {
3139 msleep_interruptible (10);
3140 } else {
3141 mdelay (10);
3142 }
3143 }
3144 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3145 ioc->name, ioc_state));
3146 return -EFAULT;
3147}
3148
3149/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3150/*
3151 * KickStart - Perform hard reset of MPT adapter.
3152 * @ioc: Pointer to MPT_ADAPTER structure
3153 * @force: Force hard reset
3154 * @sleepFlag: Specifies whether the process can sleep
3155 *
3156 * This routine places MPT adapter in diagnostic mode via the
3157 * WriteSequence register, and then performs a hard reset of adapter
3158 * via the Diagnostic register.
3159 *
3160 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3161 * or NO_SLEEP (interrupt thread, use mdelay)
3162 * force - 1 if doorbell active, board fault state
3163 * board operational, IOC_RECOVERY or
3164 * IOC_BRINGUP and there is an alt_ioc.
3165 * 0 else
3166 *
3167 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003168 * 1 - hard reset, READY
3169 * 0 - no reset due to History bit, READY
3170 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 * OR reset but failed to come READY
3172 * -2 - no reset, could not enter DIAG mode
3173 * -3 - reset but bad FW bit
3174 */
3175static int
3176KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3177{
3178 int hard_reset_done = 0;
3179 u32 ioc_state=0;
3180 int cnt,cntdn;
3181
3182 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003183 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 /* Always issue a Msg Unit Reset first. This will clear some
3185 * SCSI bus hang conditions.
3186 */
3187 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3188
3189 if (sleepFlag == CAN_SLEEP) {
3190 msleep_interruptible (1000);
3191 } else {
3192 mdelay (1000);
3193 }
3194 }
3195
3196 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3197 if (hard_reset_done < 0)
3198 return hard_reset_done;
3199
3200 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3201 ioc->name));
3202
3203 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3204 for (cnt=0; cnt<cntdn; cnt++) {
3205 ioc_state = mpt_GetIocState(ioc, 1);
3206 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3207 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3208 ioc->name, cnt));
3209 return hard_reset_done;
3210 }
3211 if (sleepFlag == CAN_SLEEP) {
3212 msleep_interruptible (10);
3213 } else {
3214 mdelay (10);
3215 }
3216 }
3217
3218 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3219 ioc->name, ioc_state);
3220 return -1;
3221}
3222
3223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3224/*
3225 * mpt_diag_reset - Perform hard reset of the adapter.
3226 * @ioc: Pointer to MPT_ADAPTER structure
3227 * @ignore: Set if to honor and clear to ignore
3228 * the reset history bit
3229 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3230 * else set to NO_SLEEP (use mdelay instead)
3231 *
3232 * This routine places the adapter in diagnostic mode via the
3233 * WriteSequence register and then performs a hard reset of adapter
3234 * via the Diagnostic register. Adapter should be in ready state
3235 * upon successful completion.
3236 *
3237 * Returns: 1 hard reset successful
3238 * 0 no reset performed because reset history bit set
3239 * -2 enabling diagnostic mode failed
3240 * -3 diagnostic reset failed
3241 */
3242static int
3243mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3244{
3245 u32 diag0val;
3246 u32 doorbell;
3247 int hard_reset_done = 0;
3248 int count = 0;
3249#ifdef MPT_DEBUG
3250 u32 diag1val = 0;
3251#endif
3252
3253 /* Clear any existing interrupts */
3254 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3255
3256 /* Use "Diagnostic reset" method! (only thing available!) */
3257 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3258
3259#ifdef MPT_DEBUG
3260 if (ioc->alt_ioc)
3261 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3262 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3263 ioc->name, diag0val, diag1val));
3264#endif
3265
3266 /* Do the reset if we are told to ignore the reset history
3267 * or if the reset history is 0
3268 */
3269 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3270 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3271 /* Write magic sequence to WriteSequence register
3272 * Loop until in diagnostic mode
3273 */
3274 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3275 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3276 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3277 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3278 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3279 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3280
3281 /* wait 100 msec */
3282 if (sleepFlag == CAN_SLEEP) {
3283 msleep_interruptible (100);
3284 } else {
3285 mdelay (100);
3286 }
3287
3288 count++;
3289 if (count > 20) {
3290 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3291 ioc->name, diag0val);
3292 return -2;
3293
3294 }
3295
3296 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3297
3298 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3299 ioc->name, diag0val));
3300 }
3301
3302#ifdef MPT_DEBUG
3303 if (ioc->alt_ioc)
3304 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3305 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3306 ioc->name, diag0val, diag1val));
3307#endif
3308 /*
3309 * Disable the ARM (Bug fix)
3310 *
3311 */
3312 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003313 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
3315 /*
3316 * Now hit the reset bit in the Diagnostic register
3317 * (THE BIG HAMMER!) (Clears DRWE bit).
3318 */
3319 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3320 hard_reset_done = 1;
3321 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3322 ioc->name));
3323
3324 /*
3325 * Call each currently registered protocol IOC reset handler
3326 * with pre-reset indication.
3327 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3328 * MptResetHandlers[] registered yet.
3329 */
3330 {
3331 int ii;
3332 int r = 0;
3333
3334 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3335 if (MptResetHandlers[ii]) {
3336 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3337 ioc->name, ii));
3338 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
3339 if (ioc->alt_ioc) {
3340 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3341 ioc->name, ioc->alt_ioc->name, ii));
3342 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
3343 }
3344 }
3345 }
3346 /* FIXME? Examine results here? */
3347 }
3348
3349 if (ioc->cached_fw) {
3350 /* If the DownloadBoot operation fails, the
3351 * IOC will be left unusable. This is a fatal error
3352 * case. _diag_reset will return < 0
3353 */
3354 for (count = 0; count < 30; count ++) {
3355 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3356 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3357 break;
3358 }
3359
3360 /* wait 1 sec */
3361 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003362 msleep_interruptible (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 } else {
3364 mdelay (1000);
3365 }
3366 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003367 if ((count = mpt_downloadboot(ioc,
3368 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 printk(KERN_WARNING MYNAM
3370 ": firmware downloadboot failure (%d)!\n", count);
3371 }
3372
3373 } else {
3374 /* Wait for FW to reload and for board
3375 * to go to the READY state.
3376 * Maximum wait is 60 seconds.
3377 * If fail, no error will check again
3378 * with calling program.
3379 */
3380 for (count = 0; count < 60; count ++) {
3381 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3382 doorbell &= MPI_IOC_STATE_MASK;
3383
3384 if (doorbell == MPI_IOC_STATE_READY) {
3385 break;
3386 }
3387
3388 /* wait 1 sec */
3389 if (sleepFlag == CAN_SLEEP) {
3390 msleep_interruptible (1000);
3391 } else {
3392 mdelay (1000);
3393 }
3394 }
3395 }
3396 }
3397
3398 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3399#ifdef MPT_DEBUG
3400 if (ioc->alt_ioc)
3401 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3402 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3403 ioc->name, diag0val, diag1val));
3404#endif
3405
3406 /* Clear RESET_HISTORY bit! Place board in the
3407 * diagnostic mode to update the diag register.
3408 */
3409 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3410 count = 0;
3411 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3412 /* Write magic sequence to WriteSequence register
3413 * Loop until in diagnostic mode
3414 */
3415 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3416 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3417 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3418 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3419 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3420 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3421
3422 /* wait 100 msec */
3423 if (sleepFlag == CAN_SLEEP) {
3424 msleep_interruptible (100);
3425 } else {
3426 mdelay (100);
3427 }
3428
3429 count++;
3430 if (count > 20) {
3431 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3432 ioc->name, diag0val);
3433 break;
3434 }
3435 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3436 }
3437 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3438 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3439 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3440 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3441 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3442 ioc->name);
3443 }
3444
3445 /* Disable Diagnostic Mode
3446 */
3447 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3448
3449 /* Check FW reload status flags.
3450 */
3451 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3452 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3453 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3454 ioc->name, diag0val);
3455 return -3;
3456 }
3457
3458#ifdef MPT_DEBUG
3459 if (ioc->alt_ioc)
3460 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3461 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3462 ioc->name, diag0val, diag1val));
3463#endif
3464
3465 /*
3466 * Reset flag that says we've enabled event notification
3467 */
3468 ioc->facts.EventState = 0;
3469
3470 if (ioc->alt_ioc)
3471 ioc->alt_ioc->facts.EventState = 0;
3472
3473 return hard_reset_done;
3474}
3475
3476/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3477/*
3478 * SendIocReset - Send IOCReset request to MPT adapter.
3479 * @ioc: Pointer to MPT_ADAPTER structure
3480 * @reset_type: reset type, expected values are
3481 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3482 *
3483 * Send IOCReset request to the MPT adapter.
3484 *
3485 * Returns 0 for success, non-zero for failure.
3486 */
3487static int
3488SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3489{
3490 int r;
3491 u32 state;
3492 int cntdn, count;
3493
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003494 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 ioc->name, reset_type));
3496 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3497 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3498 return r;
3499
3500 /* FW ACK'd request, wait for READY state
3501 */
3502 count = 0;
3503 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3504
3505 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3506 cntdn--;
3507 count++;
3508 if (!cntdn) {
3509 if (sleepFlag != CAN_SLEEP)
3510 count *= 10;
3511
3512 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3513 ioc->name, (int)((count+5)/HZ));
3514 return -ETIME;
3515 }
3516
3517 if (sleepFlag == CAN_SLEEP) {
3518 msleep_interruptible(1);
3519 } else {
3520 mdelay (1); /* 1 msec delay */
3521 }
3522 }
3523
3524 /* TODO!
3525 * Cleanup all event stuff for this IOC; re-issue EventNotification
3526 * request if needed.
3527 */
3528 if (ioc->facts.Function)
3529 ioc->facts.EventState = 0;
3530
3531 return 0;
3532}
3533
3534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3535/*
3536 * initChainBuffers - Allocate memory for and initialize
3537 * chain buffers, chain buffer control arrays and spinlock.
3538 * @hd: Pointer to MPT_SCSI_HOST structure
3539 * @init: If set, initialize the spin lock.
3540 */
3541static int
3542initChainBuffers(MPT_ADAPTER *ioc)
3543{
3544 u8 *mem;
3545 int sz, ii, num_chain;
3546 int scale, num_sge, numSGE;
3547
3548 /* ReqToChain size must equal the req_depth
3549 * index = req_idx
3550 */
3551 if (ioc->ReqToChain == NULL) {
3552 sz = ioc->req_depth * sizeof(int);
3553 mem = kmalloc(sz, GFP_ATOMIC);
3554 if (mem == NULL)
3555 return -1;
3556
3557 ioc->ReqToChain = (int *) mem;
3558 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3559 ioc->name, mem, sz));
3560 mem = kmalloc(sz, GFP_ATOMIC);
3561 if (mem == NULL)
3562 return -1;
3563
3564 ioc->RequestNB = (int *) mem;
3565 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3566 ioc->name, mem, sz));
3567 }
3568 for (ii = 0; ii < ioc->req_depth; ii++) {
3569 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3570 }
3571
3572 /* ChainToChain size must equal the total number
3573 * of chain buffers to be allocated.
3574 * index = chain_idx
3575 *
3576 * Calculate the number of chain buffers needed(plus 1) per I/O
3577 * then multiply the the maximum number of simultaneous cmds
3578 *
3579 * num_sge = num sge in request frame + last chain buffer
3580 * scale = num sge per chain buffer if no chain element
3581 */
3582 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3583 if (sizeof(dma_addr_t) == sizeof(u64))
3584 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3585 else
3586 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3587
3588 if (sizeof(dma_addr_t) == sizeof(u64)) {
3589 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3590 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3591 } else {
3592 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3593 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3594 }
3595 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3596 ioc->name, num_sge, numSGE));
3597
3598 if ( numSGE > MPT_SCSI_SG_DEPTH )
3599 numSGE = MPT_SCSI_SG_DEPTH;
3600
3601 num_chain = 1;
3602 while (numSGE - num_sge > 0) {
3603 num_chain++;
3604 num_sge += (scale - 1);
3605 }
3606 num_chain++;
3607
3608 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3609 ioc->name, numSGE, num_sge, num_chain));
3610
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003611 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 num_chain *= MPT_SCSI_CAN_QUEUE;
3613 else
3614 num_chain *= MPT_FC_CAN_QUEUE;
3615
3616 ioc->num_chain = num_chain;
3617
3618 sz = num_chain * sizeof(int);
3619 if (ioc->ChainToChain == NULL) {
3620 mem = kmalloc(sz, GFP_ATOMIC);
3621 if (mem == NULL)
3622 return -1;
3623
3624 ioc->ChainToChain = (int *) mem;
3625 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3626 ioc->name, mem, sz));
3627 } else {
3628 mem = (u8 *) ioc->ChainToChain;
3629 }
3630 memset(mem, 0xFF, sz);
3631 return num_chain;
3632}
3633
3634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3635/*
3636 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3637 * @ioc: Pointer to MPT_ADAPTER structure
3638 *
3639 * This routine allocates memory for the MPT reply and request frame
3640 * pools (if necessary), and primes the IOC reply FIFO with
3641 * reply frames.
3642 *
3643 * Returns 0 for success, non-zero for failure.
3644 */
3645static int
3646PrimeIocFifos(MPT_ADAPTER *ioc)
3647{
3648 MPT_FRAME_HDR *mf;
3649 unsigned long flags;
3650 dma_addr_t alloc_dma;
3651 u8 *mem;
3652 int i, reply_sz, sz, total_size, num_chain;
3653
3654 /* Prime reply FIFO... */
3655
3656 if (ioc->reply_frames == NULL) {
3657 if ( (num_chain = initChainBuffers(ioc)) < 0)
3658 return -1;
3659
3660 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3661 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3662 ioc->name, ioc->reply_sz, ioc->reply_depth));
3663 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3664 ioc->name, reply_sz, reply_sz));
3665
3666 sz = (ioc->req_sz * ioc->req_depth);
3667 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3668 ioc->name, ioc->req_sz, ioc->req_depth));
3669 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3670 ioc->name, sz, sz));
3671 total_size += sz;
3672
3673 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3674 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3675 ioc->name, ioc->req_sz, num_chain));
3676 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3677 ioc->name, sz, sz, num_chain));
3678
3679 total_size += sz;
3680 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3681 if (mem == NULL) {
3682 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3683 ioc->name);
3684 goto out_fail;
3685 }
3686
3687 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3688 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3689
3690 memset(mem, 0, total_size);
3691 ioc->alloc_total += total_size;
3692 ioc->alloc = mem;
3693 ioc->alloc_dma = alloc_dma;
3694 ioc->alloc_sz = total_size;
3695 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3696 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3697
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003698 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3699 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3700
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 alloc_dma += reply_sz;
3702 mem += reply_sz;
3703
3704 /* Request FIFO - WE manage this! */
3705
3706 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3707 ioc->req_frames_dma = alloc_dma;
3708
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003709 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 ioc->name, mem, (void *)(ulong)alloc_dma));
3711
3712 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3713
3714#if defined(CONFIG_MTRR) && 0
3715 /*
3716 * Enable Write Combining MTRR for IOC's memory region.
3717 * (at least as much as we can; "size and base must be
3718 * multiples of 4 kiB"
3719 */
3720 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3721 sz,
3722 MTRR_TYPE_WRCOMB, 1);
3723 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3724 ioc->name, ioc->req_frames_dma, sz));
3725#endif
3726
3727 for (i = 0; i < ioc->req_depth; i++) {
3728 alloc_dma += ioc->req_sz;
3729 mem += ioc->req_sz;
3730 }
3731
3732 ioc->ChainBuffer = mem;
3733 ioc->ChainBufferDMA = alloc_dma;
3734
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003735 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3737
3738 /* Initialize the free chain Q.
3739 */
3740
3741 INIT_LIST_HEAD(&ioc->FreeChainQ);
3742
3743 /* Post the chain buffers to the FreeChainQ.
3744 */
3745 mem = (u8 *)ioc->ChainBuffer;
3746 for (i=0; i < num_chain; i++) {
3747 mf = (MPT_FRAME_HDR *) mem;
3748 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3749 mem += ioc->req_sz;
3750 }
3751
3752 /* Initialize Request frames linked list
3753 */
3754 alloc_dma = ioc->req_frames_dma;
3755 mem = (u8 *) ioc->req_frames;
3756
3757 spin_lock_irqsave(&ioc->FreeQlock, flags);
3758 INIT_LIST_HEAD(&ioc->FreeQ);
3759 for (i = 0; i < ioc->req_depth; i++) {
3760 mf = (MPT_FRAME_HDR *) mem;
3761
3762 /* Queue REQUESTs *internally*! */
3763 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3764
3765 mem += ioc->req_sz;
3766 }
3767 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3768
3769 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3770 ioc->sense_buf_pool =
3771 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3772 if (ioc->sense_buf_pool == NULL) {
3773 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3774 ioc->name);
3775 goto out_fail;
3776 }
3777
3778 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3779 ioc->alloc_total += sz;
3780 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3781 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3782
3783 }
3784
3785 /* Post Reply frames to FIFO
3786 */
3787 alloc_dma = ioc->alloc_dma;
3788 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3789 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3790
3791 for (i = 0; i < ioc->reply_depth; i++) {
3792 /* Write each address to the IOC! */
3793 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3794 alloc_dma += ioc->reply_sz;
3795 }
3796
3797 return 0;
3798
3799out_fail:
3800 if (ioc->alloc != NULL) {
3801 sz = ioc->alloc_sz;
3802 pci_free_consistent(ioc->pcidev,
3803 sz,
3804 ioc->alloc, ioc->alloc_dma);
3805 ioc->reply_frames = NULL;
3806 ioc->req_frames = NULL;
3807 ioc->alloc_total -= sz;
3808 }
3809 if (ioc->sense_buf_pool != NULL) {
3810 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3811 pci_free_consistent(ioc->pcidev,
3812 sz,
3813 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3814 ioc->sense_buf_pool = NULL;
3815 }
3816 return -1;
3817}
3818
3819/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3820/**
3821 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3822 * from IOC via doorbell handshake method.
3823 * @ioc: Pointer to MPT_ADAPTER structure
3824 * @reqBytes: Size of the request in bytes
3825 * @req: Pointer to MPT request frame
3826 * @replyBytes: Expected size of the reply in bytes
3827 * @u16reply: Pointer to area where reply should be written
3828 * @maxwait: Max wait time for a reply (in seconds)
3829 * @sleepFlag: Specifies whether the process can sleep
3830 *
3831 * NOTES: It is the callers responsibility to byte-swap fields in the
3832 * request which are greater than 1 byte in size. It is also the
3833 * callers responsibility to byte-swap response fields which are
3834 * greater than 1 byte in size.
3835 *
3836 * Returns 0 for success, non-zero for failure.
3837 */
3838static int
3839mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003840 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841{
3842 MPIDefaultReply_t *mptReply;
3843 int failcnt = 0;
3844 int t;
3845
3846 /*
3847 * Get ready to cache a handshake reply
3848 */
3849 ioc->hs_reply_idx = 0;
3850 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3851 mptReply->MsgLength = 0;
3852
3853 /*
3854 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3855 * then tell IOC that we want to handshake a request of N words.
3856 * (WRITE u32val to Doorbell reg).
3857 */
3858 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3859 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3860 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3861 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3862
3863 /*
3864 * Wait for IOC's doorbell handshake int
3865 */
3866 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3867 failcnt++;
3868
3869 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3870 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3871
3872 /* Read doorbell and check for active bit */
3873 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3874 return -1;
3875
3876 /*
3877 * Clear doorbell int (WRITE 0 to IntStatus reg),
3878 * then wait for IOC to ACKnowledge that it's ready for
3879 * our handshake request.
3880 */
3881 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3882 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3883 failcnt++;
3884
3885 if (!failcnt) {
3886 int ii;
3887 u8 *req_as_bytes = (u8 *) req;
3888
3889 /*
3890 * Stuff request words via doorbell handshake,
3891 * with ACK from IOC for each.
3892 */
3893 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3894 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3895 (req_as_bytes[(ii*4) + 1] << 8) |
3896 (req_as_bytes[(ii*4) + 2] << 16) |
3897 (req_as_bytes[(ii*4) + 3] << 24));
3898
3899 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3900 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3901 failcnt++;
3902 }
3903
3904 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3905 DBG_DUMP_REQUEST_FRAME_HDR(req)
3906
3907 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3908 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3909
3910 /*
3911 * Wait for completion of doorbell handshake reply from the IOC
3912 */
3913 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3914 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003915
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3917 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3918
3919 /*
3920 * Copy out the cached reply...
3921 */
3922 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3923 u16reply[ii] = ioc->hs_reply[ii];
3924 } else {
3925 return -99;
3926 }
3927
3928 return -failcnt;
3929}
3930
3931/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3932/*
3933 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3934 * in it's IntStatus register.
3935 * @ioc: Pointer to MPT_ADAPTER structure
3936 * @howlong: How long to wait (in seconds)
3937 * @sleepFlag: Specifies whether the process can sleep
3938 *
3939 * This routine waits (up to ~2 seconds max) for IOC doorbell
3940 * handshake ACKnowledge.
3941 *
3942 * Returns a negative value on failure, else wait loop count.
3943 */
3944static int
3945WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3946{
3947 int cntdn;
3948 int count = 0;
3949 u32 intstat=0;
3950
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003951 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952
3953 if (sleepFlag == CAN_SLEEP) {
3954 while (--cntdn) {
3955 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3956 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3957 break;
3958 msleep_interruptible (1);
3959 count++;
3960 }
3961 } else {
3962 while (--cntdn) {
3963 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3964 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3965 break;
3966 mdelay (1);
3967 count++;
3968 }
3969 }
3970
3971 if (cntdn) {
3972 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3973 ioc->name, count));
3974 return count;
3975 }
3976
3977 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3978 ioc->name, count, intstat);
3979 return -1;
3980}
3981
3982/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3983/*
3984 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3985 * in it's IntStatus register.
3986 * @ioc: Pointer to MPT_ADAPTER structure
3987 * @howlong: How long to wait (in seconds)
3988 * @sleepFlag: Specifies whether the process can sleep
3989 *
3990 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3991 *
3992 * Returns a negative value on failure, else wait loop count.
3993 */
3994static int
3995WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3996{
3997 int cntdn;
3998 int count = 0;
3999 u32 intstat=0;
4000
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004001 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 if (sleepFlag == CAN_SLEEP) {
4003 while (--cntdn) {
4004 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4005 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4006 break;
4007 msleep_interruptible(1);
4008 count++;
4009 }
4010 } else {
4011 while (--cntdn) {
4012 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4013 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4014 break;
4015 mdelay(1);
4016 count++;
4017 }
4018 }
4019
4020 if (cntdn) {
4021 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
4022 ioc->name, count, howlong));
4023 return count;
4024 }
4025
4026 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4027 ioc->name, count, intstat);
4028 return -1;
4029}
4030
4031/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4032/*
4033 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
4034 * @ioc: Pointer to MPT_ADAPTER structure
4035 * @howlong: How long to wait (in seconds)
4036 * @sleepFlag: Specifies whether the process can sleep
4037 *
4038 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4039 * Reply is cached to IOC private area large enough to hold a maximum
4040 * of 128 bytes of reply data.
4041 *
4042 * Returns a negative value on failure, else size of reply in WORDS.
4043 */
4044static int
4045WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4046{
4047 int u16cnt = 0;
4048 int failcnt = 0;
4049 int t;
4050 u16 *hs_reply = ioc->hs_reply;
4051 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4052 u16 hword;
4053
4054 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4055
4056 /*
4057 * Get first two u16's so we can look at IOC's intended reply MsgLength
4058 */
4059 u16cnt=0;
4060 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4061 failcnt++;
4062 } else {
4063 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4064 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4065 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4066 failcnt++;
4067 else {
4068 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4069 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4070 }
4071 }
4072
4073 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004074 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4076
4077 /*
4078 * If no error (and IOC said MsgLength is > 0), piece together
4079 * reply 16 bits at a time.
4080 */
4081 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4082 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4083 failcnt++;
4084 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4085 /* don't overflow our IOC hs_reply[] buffer! */
4086 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4087 hs_reply[u16cnt] = hword;
4088 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4089 }
4090
4091 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4092 failcnt++;
4093 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4094
4095 if (failcnt) {
4096 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4097 ioc->name);
4098 return -failcnt;
4099 }
4100#if 0
4101 else if (u16cnt != (2 * mptReply->MsgLength)) {
4102 return -101;
4103 }
4104 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4105 return -102;
4106 }
4107#endif
4108
4109 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4110 DBG_DUMP_REPLY_FRAME(mptReply)
4111
4112 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4113 ioc->name, t, u16cnt/2));
4114 return u16cnt/2;
4115}
4116
4117/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4118/*
4119 * GetLanConfigPages - Fetch LANConfig pages.
4120 * @ioc: Pointer to MPT_ADAPTER structure
4121 *
4122 * Return: 0 for success
4123 * -ENOMEM if no memory available
4124 * -EPERM if not allowed due to ISR context
4125 * -EAGAIN if no msg frames currently available
4126 * -EFAULT for non-successful reply or no reply (timeout)
4127 */
4128static int
4129GetLanConfigPages(MPT_ADAPTER *ioc)
4130{
4131 ConfigPageHeader_t hdr;
4132 CONFIGPARMS cfg;
4133 LANPage0_t *ppage0_alloc;
4134 dma_addr_t page0_dma;
4135 LANPage1_t *ppage1_alloc;
4136 dma_addr_t page1_dma;
4137 int rc = 0;
4138 int data_sz;
4139 int copy_sz;
4140
4141 /* Get LAN Page 0 header */
4142 hdr.PageVersion = 0;
4143 hdr.PageLength = 0;
4144 hdr.PageNumber = 0;
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 cfg.timeout = 0;
4152
4153 if ((rc = mpt_config(ioc, &cfg)) != 0)
4154 return rc;
4155
4156 if (hdr.PageLength > 0) {
4157 data_sz = hdr.PageLength * 4;
4158 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4159 rc = -ENOMEM;
4160 if (ppage0_alloc) {
4161 memset((u8 *)ppage0_alloc, 0, data_sz);
4162 cfg.physAddr = page0_dma;
4163 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4164
4165 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4166 /* save the data */
4167 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4168 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4169
4170 }
4171
4172 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4173
4174 /* FIXME!
4175 * Normalize endianness of structure data,
4176 * by byte-swapping all > 1 byte fields!
4177 */
4178
4179 }
4180
4181 if (rc)
4182 return rc;
4183 }
4184
4185 /* Get LAN Page 1 header */
4186 hdr.PageVersion = 0;
4187 hdr.PageLength = 0;
4188 hdr.PageNumber = 1;
4189 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004190 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 cfg.physAddr = -1;
4192 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4193 cfg.dir = 0;
4194 cfg.pageAddr = 0;
4195
4196 if ((rc = mpt_config(ioc, &cfg)) != 0)
4197 return rc;
4198
4199 if (hdr.PageLength == 0)
4200 return 0;
4201
4202 data_sz = hdr.PageLength * 4;
4203 rc = -ENOMEM;
4204 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4205 if (ppage1_alloc) {
4206 memset((u8 *)ppage1_alloc, 0, data_sz);
4207 cfg.physAddr = page1_dma;
4208 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4209
4210 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4211 /* save the data */
4212 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4213 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4214 }
4215
4216 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4217
4218 /* FIXME!
4219 * Normalize endianness of structure data,
4220 * by byte-swapping all > 1 byte fields!
4221 */
4222
4223 }
4224
4225 return rc;
4226}
4227
4228/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4229/*
Michael Reed05e8ec12006-01-13 14:31:54 -06004230 * mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 * @ioc: Pointer to MPT_ADAPTER structure
4232 * @portnum: IOC Port number
4233 *
4234 * Return: 0 for success
4235 * -ENOMEM if no memory available
4236 * -EPERM if not allowed due to ISR context
4237 * -EAGAIN if no msg frames currently available
4238 * -EFAULT for non-successful reply or no reply (timeout)
4239 */
Michael Reed05e8ec12006-01-13 14:31:54 -06004240int
4241mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242{
4243 ConfigPageHeader_t hdr;
4244 CONFIGPARMS cfg;
4245 FCPortPage0_t *ppage0_alloc;
4246 FCPortPage0_t *pp0dest;
4247 dma_addr_t page0_dma;
4248 int data_sz;
4249 int copy_sz;
4250 int rc;
Michael Reed05e8ec12006-01-13 14:31:54 -06004251 int count = 400;
4252
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253
4254 /* Get FCPort Page 0 header */
4255 hdr.PageVersion = 0;
4256 hdr.PageLength = 0;
4257 hdr.PageNumber = 0;
4258 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004259 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 cfg.physAddr = -1;
4261 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4262 cfg.dir = 0;
4263 cfg.pageAddr = portnum;
4264 cfg.timeout = 0;
4265
4266 if ((rc = mpt_config(ioc, &cfg)) != 0)
4267 return rc;
4268
4269 if (hdr.PageLength == 0)
4270 return 0;
4271
4272 data_sz = hdr.PageLength * 4;
4273 rc = -ENOMEM;
4274 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4275 if (ppage0_alloc) {
Michael Reed05e8ec12006-01-13 14:31:54 -06004276
4277 try_again:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 memset((u8 *)ppage0_alloc, 0, data_sz);
4279 cfg.physAddr = page0_dma;
4280 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4281
4282 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4283 /* save the data */
4284 pp0dest = &ioc->fc_port_page0[portnum];
4285 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
4286 memcpy(pp0dest, ppage0_alloc, copy_sz);
4287
4288 /*
4289 * Normalize endianness of structure data,
4290 * by byte-swapping all > 1 byte fields!
4291 */
4292 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
4293 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
4294 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
4295 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
4296 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
4297 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
4298 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
4299 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
4300 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
4301 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
4302 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
4303 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
4304 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
4305 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
4306 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
4307 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
4308
Michael Reed05e8ec12006-01-13 14:31:54 -06004309 /*
4310 * if still doing discovery,
4311 * hang loose a while until finished
4312 */
4313 if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
4314 if (count-- > 0) {
4315 msleep_interruptible(100);
4316 goto try_again;
4317 }
4318 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
4319 " complete.\n",
4320 ioc->name);
4321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 }
4323
4324 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4325 }
4326
4327 return rc;
4328}
4329
4330/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4331/*
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004332 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4333 * @ioc: Pointer to MPT_ADAPTER structure
4334 * @sas_address: 64bit SAS Address for operation.
4335 * @target_id: specified target for operation
4336 * @bus: specified bus for operation
4337 * @persist_opcode: see below
4338 *
4339 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4340 * devices not currently present.
4341 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4342 *
4343 * NOTE: Don't use not this function during interrupt time.
4344 *
4345 * Returns: 0 for success, non-zero error
4346 */
4347
4348/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4349int
4350mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4351{
4352 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4353 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4354 MPT_FRAME_HDR *mf = NULL;
4355 MPIHeader_t *mpi_hdr;
4356
4357
4358 /* insure garbage is not sent to fw */
4359 switch(persist_opcode) {
4360
4361 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4362 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4363 break;
4364
4365 default:
4366 return -1;
4367 break;
4368 }
4369
4370 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4371
4372 /* Get a MF for this command.
4373 */
4374 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4375 printk("%s: no msg frames!\n",__FUNCTION__);
4376 return -1;
4377 }
4378
4379 mpi_hdr = (MPIHeader_t *) mf;
4380 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4381 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4382 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4383 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4384 sasIoUnitCntrReq->Operation = persist_opcode;
4385
4386 init_timer(&ioc->persist_timer);
4387 ioc->persist_timer.data = (unsigned long) ioc;
4388 ioc->persist_timer.function = mpt_timer_expired;
4389 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4390 ioc->persist_wait_done=0;
4391 add_timer(&ioc->persist_timer);
4392 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4393 wait_event(mpt_waitq, ioc->persist_wait_done);
4394
4395 sasIoUnitCntrReply =
4396 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4397 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4398 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4399 __FUNCTION__,
4400 sasIoUnitCntrReply->IOCStatus,
4401 sasIoUnitCntrReply->IOCLogInfo);
4402 return -1;
4403 }
4404
4405 printk("%s: success\n",__FUNCTION__);
4406 return 0;
4407}
4408
4409/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004410
4411static void
4412mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4413 MpiEventDataRaid_t * pRaidEventData)
4414{
4415 int volume;
4416 int reason;
4417 int disk;
4418 int status;
4419 int flags;
4420 int state;
4421
4422 volume = pRaidEventData->VolumeID;
4423 reason = pRaidEventData->ReasonCode;
4424 disk = pRaidEventData->PhysDiskNum;
4425 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4426 flags = (status >> 0) & 0xff;
4427 state = (status >> 8) & 0xff;
4428
4429 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4430 return;
4431 }
4432
4433 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4434 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4435 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4436 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4437 ioc->name, disk);
4438 } else {
4439 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4440 ioc->name, volume);
4441 }
4442
4443 switch(reason) {
4444 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4445 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4446 ioc->name);
4447 break;
4448
4449 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4450
4451 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4452 ioc->name);
4453 break;
4454
4455 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4456 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4457 ioc->name);
4458 break;
4459
4460 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4461 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4462 ioc->name,
4463 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4464 ? "optimal"
4465 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4466 ? "degraded"
4467 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4468 ? "failed"
4469 : "state unknown",
4470 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4471 ? ", enabled" : "",
4472 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4473 ? ", quiesced" : "",
4474 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4475 ? ", resync in progress" : "" );
4476 break;
4477
4478 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4479 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4480 ioc->name, disk);
4481 break;
4482
4483 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4484 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4485 ioc->name);
4486 break;
4487
4488 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4489 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4490 ioc->name);
4491 break;
4492
4493 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4494 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4495 ioc->name);
4496 break;
4497
4498 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4499 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4500 ioc->name,
4501 state == MPI_PHYSDISK0_STATUS_ONLINE
4502 ? "online"
4503 : state == MPI_PHYSDISK0_STATUS_MISSING
4504 ? "missing"
4505 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4506 ? "not compatible"
4507 : state == MPI_PHYSDISK0_STATUS_FAILED
4508 ? "failed"
4509 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4510 ? "initializing"
4511 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4512 ? "offline requested"
4513 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4514 ? "failed requested"
4515 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4516 ? "offline"
4517 : "state unknown",
4518 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4519 ? ", out of sync" : "",
4520 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4521 ? ", quiesced" : "" );
4522 break;
4523
4524 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4525 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4526 ioc->name, disk);
4527 break;
4528
4529 case MPI_EVENT_RAID_RC_SMART_DATA:
4530 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4531 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4532 break;
4533
4534 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4535 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4536 ioc->name, disk);
4537 break;
4538 }
4539}
4540
4541/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004542/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4544 * @ioc: Pointer to MPT_ADAPTER structure
4545 *
4546 * Returns: 0 for success
4547 * -ENOMEM if no memory available
4548 * -EPERM if not allowed due to ISR context
4549 * -EAGAIN if no msg frames currently available
4550 * -EFAULT for non-successful reply or no reply (timeout)
4551 */
4552static int
4553GetIoUnitPage2(MPT_ADAPTER *ioc)
4554{
4555 ConfigPageHeader_t hdr;
4556 CONFIGPARMS cfg;
4557 IOUnitPage2_t *ppage_alloc;
4558 dma_addr_t page_dma;
4559 int data_sz;
4560 int rc;
4561
4562 /* Get the page header */
4563 hdr.PageVersion = 0;
4564 hdr.PageLength = 0;
4565 hdr.PageNumber = 2;
4566 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004567 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 cfg.physAddr = -1;
4569 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4570 cfg.dir = 0;
4571 cfg.pageAddr = 0;
4572 cfg.timeout = 0;
4573
4574 if ((rc = mpt_config(ioc, &cfg)) != 0)
4575 return rc;
4576
4577 if (hdr.PageLength == 0)
4578 return 0;
4579
4580 /* Read the config page */
4581 data_sz = hdr.PageLength * 4;
4582 rc = -ENOMEM;
4583 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4584 if (ppage_alloc) {
4585 memset((u8 *)ppage_alloc, 0, data_sz);
4586 cfg.physAddr = page_dma;
4587 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4588
4589 /* If Good, save data */
4590 if ((rc = mpt_config(ioc, &cfg)) == 0)
4591 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4592
4593 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4594 }
4595
4596 return rc;
4597}
4598
4599/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4600/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4601 * @ioc: Pointer to a Adapter Strucutre
4602 * @portnum: IOC port number
4603 *
4604 * Return: -EFAULT if read of config page header fails
4605 * or if no nvram
4606 * If read of SCSI Port Page 0 fails,
4607 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4608 * Adapter settings: async, narrow
4609 * Return 1
4610 * If read of SCSI Port Page 2 fails,
4611 * Adapter settings valid
4612 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4613 * Return 1
4614 * Else
4615 * Both valid
4616 * Return 0
4617 * CHECK - what type of locking mechanisms should be used????
4618 */
4619static int
4620mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4621{
4622 u8 *pbuf;
4623 dma_addr_t buf_dma;
4624 CONFIGPARMS cfg;
4625 ConfigPageHeader_t header;
4626 int ii;
4627 int data, rc = 0;
4628
4629 /* Allocate memory
4630 */
4631 if (!ioc->spi_data.nvram) {
4632 int sz;
4633 u8 *mem;
4634 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4635 mem = kmalloc(sz, GFP_ATOMIC);
4636 if (mem == NULL)
4637 return -EFAULT;
4638
4639 ioc->spi_data.nvram = (int *) mem;
4640
4641 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4642 ioc->name, ioc->spi_data.nvram, sz));
4643 }
4644
4645 /* Invalidate NVRAM information
4646 */
4647 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4648 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4649 }
4650
4651 /* Read SPP0 header, allocate memory, then read page.
4652 */
4653 header.PageVersion = 0;
4654 header.PageLength = 0;
4655 header.PageNumber = 0;
4656 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004657 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 cfg.physAddr = -1;
4659 cfg.pageAddr = portnum;
4660 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4661 cfg.dir = 0;
4662 cfg.timeout = 0; /* use default */
4663 if (mpt_config(ioc, &cfg) != 0)
4664 return -EFAULT;
4665
4666 if (header.PageLength > 0) {
4667 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4668 if (pbuf) {
4669 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4670 cfg.physAddr = buf_dma;
4671 if (mpt_config(ioc, &cfg) != 0) {
4672 ioc->spi_data.maxBusWidth = MPT_NARROW;
4673 ioc->spi_data.maxSyncOffset = 0;
4674 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4675 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4676 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004677 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4678 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 } else {
4680 /* Save the Port Page 0 data
4681 */
4682 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4683 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4684 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4685
4686 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4687 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004688 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 ioc->name, pPP0->Capabilities));
4690 }
4691 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4692 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4693 if (data) {
4694 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4695 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4696 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004697 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4698 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 } else {
4700 ioc->spi_data.maxSyncOffset = 0;
4701 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4702 }
4703
4704 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4705
4706 /* Update the minSyncFactor based on bus type.
4707 */
4708 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4709 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4710
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004711 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004713 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4714 ioc->name, ioc->spi_data.minSyncFactor));
4715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 }
4717 }
4718 if (pbuf) {
4719 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4720 }
4721 }
4722 }
4723
4724 /* SCSI Port Page 2 - Read the header then the page.
4725 */
4726 header.PageVersion = 0;
4727 header.PageLength = 0;
4728 header.PageNumber = 2;
4729 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004730 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 cfg.physAddr = -1;
4732 cfg.pageAddr = portnum;
4733 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4734 cfg.dir = 0;
4735 if (mpt_config(ioc, &cfg) != 0)
4736 return -EFAULT;
4737
4738 if (header.PageLength > 0) {
4739 /* Allocate memory and read SCSI Port Page 2
4740 */
4741 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4742 if (pbuf) {
4743 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4744 cfg.physAddr = buf_dma;
4745 if (mpt_config(ioc, &cfg) != 0) {
4746 /* Nvram data is left with INVALID mark
4747 */
4748 rc = 1;
4749 } else {
4750 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4751 MpiDeviceInfo_t *pdevice = NULL;
4752
Moore, Ericd8e925d2006-01-16 18:53:06 -07004753 /*
4754 * Save "Set to Avoid SCSI Bus Resets" flag
4755 */
4756 ioc->spi_data.bus_reset =
4757 (le32_to_cpu(pPP2->PortFlags) &
4758 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4759 0 : 1 ;
4760
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 /* Save the Port Page 2 data
4762 * (reformat into a 32bit quantity)
4763 */
4764 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4765 ioc->spi_data.PortFlags = data;
4766 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4767 pdevice = &pPP2->DeviceSettings[ii];
4768 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4769 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4770 ioc->spi_data.nvram[ii] = data;
4771 }
4772 }
4773
4774 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4775 }
4776 }
4777
4778 /* Update Adapter limits with those from NVRAM
4779 * Comment: Don't need to do this. Target performance
4780 * parameters will never exceed the adapters limits.
4781 */
4782
4783 return rc;
4784}
4785
4786/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4787/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4788 * @ioc: Pointer to a Adapter Strucutre
4789 * @portnum: IOC port number
4790 *
4791 * Return: -EFAULT if read of config page header fails
4792 * or 0 if success.
4793 */
4794static int
4795mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4796{
4797 CONFIGPARMS cfg;
4798 ConfigPageHeader_t header;
4799
4800 /* Read the SCSI Device Page 1 header
4801 */
4802 header.PageVersion = 0;
4803 header.PageLength = 0;
4804 header.PageNumber = 1;
4805 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004806 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 cfg.physAddr = -1;
4808 cfg.pageAddr = portnum;
4809 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4810 cfg.dir = 0;
4811 cfg.timeout = 0;
4812 if (mpt_config(ioc, &cfg) != 0)
4813 return -EFAULT;
4814
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004815 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4816 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817
4818 header.PageVersion = 0;
4819 header.PageLength = 0;
4820 header.PageNumber = 0;
4821 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4822 if (mpt_config(ioc, &cfg) != 0)
4823 return -EFAULT;
4824
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004825 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4826 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827
4828 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4829 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4830
4831 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4832 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4833 return 0;
4834}
4835
4836/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4837/**
4838 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4839 * @ioc: Pointer to a Adapter Strucutre
4840 * @portnum: IOC port number
4841 *
4842 * Return:
4843 * 0 on success
4844 * -EFAULT if read of config page header fails or data pointer not NULL
4845 * -ENOMEM if pci_alloc failed
4846 */
4847int
4848mpt_findImVolumes(MPT_ADAPTER *ioc)
4849{
4850 IOCPage2_t *pIoc2;
4851 u8 *mem;
4852 ConfigPageIoc2RaidVol_t *pIocRv;
4853 dma_addr_t ioc2_dma;
4854 CONFIGPARMS cfg;
4855 ConfigPageHeader_t header;
4856 int jj;
4857 int rc = 0;
4858 int iocpage2sz;
4859 u8 nVols, nPhys;
4860 u8 vid, vbus, vioc;
4861
4862 /* Read IOCP2 header then the page.
4863 */
4864 header.PageVersion = 0;
4865 header.PageLength = 0;
4866 header.PageNumber = 2;
4867 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004868 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 cfg.physAddr = -1;
4870 cfg.pageAddr = 0;
4871 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4872 cfg.dir = 0;
4873 cfg.timeout = 0;
4874 if (mpt_config(ioc, &cfg) != 0)
4875 return -EFAULT;
4876
4877 if (header.PageLength == 0)
4878 return -EFAULT;
4879
4880 iocpage2sz = header.PageLength * 4;
4881 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4882 if (!pIoc2)
4883 return -ENOMEM;
4884
4885 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4886 cfg.physAddr = ioc2_dma;
4887 if (mpt_config(ioc, &cfg) != 0)
4888 goto done_and_free;
4889
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004890 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4892 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004893 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 } else {
4895 goto done_and_free;
4896 }
4897 }
4898 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4899
4900 /* Identify RAID Volume Id's */
4901 nVols = pIoc2->NumActiveVolumes;
4902 if ( nVols == 0) {
4903 /* No RAID Volume.
4904 */
4905 goto done_and_free;
4906 } else {
4907 /* At least 1 RAID Volume
4908 */
4909 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004910 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4912 vid = pIocRv->VolumeID;
4913 vbus = pIocRv->VolumeBus;
4914 vioc = pIocRv->VolumeIOC;
4915
4916 /* find the match
4917 */
4918 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004919 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 } else {
4921 /* Error! Always bus 0
4922 */
4923 }
4924 }
4925 }
4926
4927 /* Identify Hidden Physical Disk Id's */
4928 nPhys = pIoc2->NumActivePhysDisks;
4929 if (nPhys == 0) {
4930 /* No physical disks.
4931 */
4932 } else {
4933 mpt_read_ioc_pg_3(ioc);
4934 }
4935
4936done_and_free:
4937 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4938
4939 return rc;
4940}
4941
4942int
4943mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4944{
4945 IOCPage3_t *pIoc3;
4946 u8 *mem;
4947 CONFIGPARMS cfg;
4948 ConfigPageHeader_t header;
4949 dma_addr_t ioc3_dma;
4950 int iocpage3sz = 0;
4951
4952 /* Free the old page
4953 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004954 kfree(ioc->raid_data.pIocPg3);
4955 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956
4957 /* There is at least one physical disk.
4958 * Read and save IOC Page 3
4959 */
4960 header.PageVersion = 0;
4961 header.PageLength = 0;
4962 header.PageNumber = 3;
4963 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004964 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 cfg.physAddr = -1;
4966 cfg.pageAddr = 0;
4967 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4968 cfg.dir = 0;
4969 cfg.timeout = 0;
4970 if (mpt_config(ioc, &cfg) != 0)
4971 return 0;
4972
4973 if (header.PageLength == 0)
4974 return 0;
4975
4976 /* Read Header good, alloc memory
4977 */
4978 iocpage3sz = header.PageLength * 4;
4979 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4980 if (!pIoc3)
4981 return 0;
4982
4983 /* Read the Page and save the data
4984 * into malloc'd memory.
4985 */
4986 cfg.physAddr = ioc3_dma;
4987 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4988 if (mpt_config(ioc, &cfg) == 0) {
4989 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4990 if (mem) {
4991 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004992 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 }
4994 }
4995
4996 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4997
4998 return 0;
4999}
5000
5001static void
5002mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5003{
5004 IOCPage4_t *pIoc4;
5005 CONFIGPARMS cfg;
5006 ConfigPageHeader_t header;
5007 dma_addr_t ioc4_dma;
5008 int iocpage4sz;
5009
5010 /* Read and save IOC Page 4
5011 */
5012 header.PageVersion = 0;
5013 header.PageLength = 0;
5014 header.PageNumber = 4;
5015 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005016 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 cfg.physAddr = -1;
5018 cfg.pageAddr = 0;
5019 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5020 cfg.dir = 0;
5021 cfg.timeout = 0;
5022 if (mpt_config(ioc, &cfg) != 0)
5023 return;
5024
5025 if (header.PageLength == 0)
5026 return;
5027
5028 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5029 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5030 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5031 if (!pIoc4)
5032 return;
5033 } else {
5034 ioc4_dma = ioc->spi_data.IocPg4_dma;
5035 iocpage4sz = ioc->spi_data.IocPg4Sz;
5036 }
5037
5038 /* Read the Page into dma memory.
5039 */
5040 cfg.physAddr = ioc4_dma;
5041 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5042 if (mpt_config(ioc, &cfg) == 0) {
5043 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5044 ioc->spi_data.IocPg4_dma = ioc4_dma;
5045 ioc->spi_data.IocPg4Sz = iocpage4sz;
5046 } else {
5047 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5048 ioc->spi_data.pIocPg4 = NULL;
5049 }
5050}
5051
5052static void
5053mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5054{
5055 IOCPage1_t *pIoc1;
5056 CONFIGPARMS cfg;
5057 ConfigPageHeader_t header;
5058 dma_addr_t ioc1_dma;
5059 int iocpage1sz = 0;
5060 u32 tmp;
5061
5062 /* Check the Coalescing Timeout in IOC Page 1
5063 */
5064 header.PageVersion = 0;
5065 header.PageLength = 0;
5066 header.PageNumber = 1;
5067 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005068 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 cfg.physAddr = -1;
5070 cfg.pageAddr = 0;
5071 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5072 cfg.dir = 0;
5073 cfg.timeout = 0;
5074 if (mpt_config(ioc, &cfg) != 0)
5075 return;
5076
5077 if (header.PageLength == 0)
5078 return;
5079
5080 /* Read Header good, alloc memory
5081 */
5082 iocpage1sz = header.PageLength * 4;
5083 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5084 if (!pIoc1)
5085 return;
5086
5087 /* Read the Page and check coalescing timeout
5088 */
5089 cfg.physAddr = ioc1_dma;
5090 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5091 if (mpt_config(ioc, &cfg) == 0) {
5092
5093 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5094 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5095 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5096
5097 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5098 ioc->name, tmp));
5099
5100 if (tmp > MPT_COALESCING_TIMEOUT) {
5101 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5102
5103 /* Write NVRAM and current
5104 */
5105 cfg.dir = 1;
5106 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5107 if (mpt_config(ioc, &cfg) == 0) {
5108 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5109 ioc->name, MPT_COALESCING_TIMEOUT));
5110
5111 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5112 if (mpt_config(ioc, &cfg) == 0) {
5113 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5114 ioc->name, MPT_COALESCING_TIMEOUT));
5115 } else {
5116 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5117 ioc->name));
5118 }
5119
5120 } else {
5121 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5122 ioc->name));
5123 }
5124 }
5125
5126 } else {
5127 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5128 }
5129 }
5130
5131 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5132
5133 return;
5134}
5135
5136/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5137/*
5138 * SendEventNotification - Send EventNotification (on or off) request
5139 * to MPT adapter.
5140 * @ioc: Pointer to MPT_ADAPTER structure
5141 * @EvSwitch: Event switch flags
5142 */
5143static int
5144SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5145{
5146 EventNotification_t *evnp;
5147
5148 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5149 if (evnp == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005150 devtprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 ioc->name));
5152 return 0;
5153 }
5154 memset(evnp, 0, sizeof(*evnp));
5155
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005156 devtprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157
5158 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5159 evnp->ChainOffset = 0;
5160 evnp->MsgFlags = 0;
5161 evnp->Switch = EvSwitch;
5162
5163 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5164
5165 return 0;
5166}
5167
5168/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5169/**
5170 * SendEventAck - Send EventAck request to MPT adapter.
5171 * @ioc: Pointer to MPT_ADAPTER structure
5172 * @evnp: Pointer to original EventNotification request
5173 */
5174static int
5175SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5176{
5177 EventAck_t *pAck;
5178
5179 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005180 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5181 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5182 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5183 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 return -1;
5185 }
5186 memset(pAck, 0, sizeof(*pAck));
5187
5188 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5189
5190 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5191 pAck->ChainOffset = 0;
5192 pAck->MsgFlags = 0;
5193 pAck->Event = evnp->Event;
5194 pAck->EventContext = evnp->EventContext;
5195
5196 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5197
5198 return 0;
5199}
5200
5201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5202/**
5203 * mpt_config - Generic function to issue config message
5204 * @ioc - Pointer to an adapter structure
5205 * @cfg - Pointer to a configuration structure. Struct contains
5206 * action, page address, direction, physical address
5207 * and pointer to a configuration page header
5208 * Page header is updated.
5209 *
5210 * Returns 0 for success
5211 * -EPERM if not allowed due to ISR context
5212 * -EAGAIN if no msg frames currently available
5213 * -EFAULT for non-successful reply or no reply (timeout)
5214 */
5215int
5216mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5217{
5218 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005219 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 MPT_FRAME_HDR *mf;
5221 unsigned long flags;
5222 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005223 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 int in_isr;
5225
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005226 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 * to be in ISR context, because that is fatal!
5228 */
5229 in_isr = in_interrupt();
5230 if (in_isr) {
5231 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5232 ioc->name));
5233 return -EPERM;
5234 }
5235
5236 /* Get and Populate a free Frame
5237 */
5238 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5239 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5240 ioc->name));
5241 return -EAGAIN;
5242 }
5243 pReq = (Config_t *)mf;
5244 pReq->Action = pCfg->action;
5245 pReq->Reserved = 0;
5246 pReq->ChainOffset = 0;
5247 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005248
5249 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 pReq->ExtPageLength = 0;
5251 pReq->ExtPageType = 0;
5252 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005253
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 for (ii=0; ii < 8; ii++)
5255 pReq->Reserved2[ii] = 0;
5256
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005257 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5258 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5259 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5260 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5261
5262 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5263 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5264 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5265 pReq->ExtPageType = pExtHdr->ExtPageType;
5266 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5267
5268 /* Page Length must be treated as a reserved field for the extended header. */
5269 pReq->Header.PageLength = 0;
5270 }
5271
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5273
5274 /* Add a SGE to the config request.
5275 */
5276 if (pCfg->dir)
5277 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5278 else
5279 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5280
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005281 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5282 flagsLength |= pExtHdr->ExtPageLength * 4;
5283
5284 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5285 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5286 }
5287 else {
5288 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5289
5290 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5291 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293
5294 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5295
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 /* Append pCfg pointer to end of mf
5297 */
5298 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5299
5300 /* Initalize the timer
5301 */
5302 init_timer(&pCfg->timer);
5303 pCfg->timer.data = (unsigned long) ioc;
5304 pCfg->timer.function = mpt_timer_expired;
5305 pCfg->wait_done = 0;
5306
5307 /* Set the timer; ensure 10 second minimum */
5308 if (pCfg->timeout < 10)
5309 pCfg->timer.expires = jiffies + HZ*10;
5310 else
5311 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5312
5313 /* Add to end of Q, set timer and then issue this command */
5314 spin_lock_irqsave(&ioc->FreeQlock, flags);
5315 list_add_tail(&pCfg->linkage, &ioc->configQ);
5316 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5317
5318 add_timer(&pCfg->timer);
5319 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5320 wait_event(mpt_waitq, pCfg->wait_done);
5321
5322 /* mf has been freed - do not access */
5323
5324 rc = pCfg->status;
5325
5326 return rc;
5327}
5328
5329/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5330/**
5331 * mpt_toolbox - Generic function to issue toolbox message
5332 * @ioc - Pointer to an adapter structure
5333 * @cfg - Pointer to a toolbox structure. Struct contains
5334 * action, page address, direction, physical address
5335 * and pointer to a configuration page header
5336 * Page header is updated.
5337 *
5338 * Returns 0 for success
5339 * -EPERM if not allowed due to ISR context
5340 * -EAGAIN if no msg frames currently available
5341 * -EFAULT for non-successful reply or no reply (timeout)
5342 */
5343int
5344mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5345{
5346 ToolboxIstwiReadWriteRequest_t *pReq;
5347 MPT_FRAME_HDR *mf;
5348 struct pci_dev *pdev;
5349 unsigned long flags;
5350 int rc;
5351 u32 flagsLength;
5352 int in_isr;
5353
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005354 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 * to be in ISR context, because that is fatal!
5356 */
5357 in_isr = in_interrupt();
5358 if (in_isr) {
5359 dcprintk((MYIOC_s_WARN_FMT "toobox request not allowed in ISR context!\n",
5360 ioc->name));
5361 return -EPERM;
5362 }
5363
5364 /* Get and Populate a free Frame
5365 */
5366 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5367 dcprintk((MYIOC_s_WARN_FMT "mpt_toolbox: no msg frames!\n",
5368 ioc->name));
5369 return -EAGAIN;
5370 }
5371 pReq = (ToolboxIstwiReadWriteRequest_t *)mf;
5372 pReq->Tool = pCfg->action;
5373 pReq->Reserved = 0;
5374 pReq->ChainOffset = 0;
5375 pReq->Function = MPI_FUNCTION_TOOLBOX;
5376 pReq->Reserved1 = 0;
5377 pReq->Reserved2 = 0;
5378 pReq->MsgFlags = 0;
5379 pReq->Flags = pCfg->dir;
5380 pReq->BusNum = 0;
5381 pReq->Reserved3 = 0;
5382 pReq->NumAddressBytes = 0x01;
5383 pReq->Reserved4 = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005384 pReq->DataLength = cpu_to_le16(0x04);
5385 pdev = ioc->pcidev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 if (pdev->devfn & 1)
5387 pReq->DeviceAddr = 0xB2;
5388 else
5389 pReq->DeviceAddr = 0xB0;
5390 pReq->Addr1 = 0;
5391 pReq->Addr2 = 0;
5392 pReq->Addr3 = 0;
5393 pReq->Reserved5 = 0;
5394
5395 /* Add a SGE to the config request.
5396 */
5397
5398 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 4;
5399
5400 mpt_add_sge((char *)&pReq->SGL, flagsLength, pCfg->physAddr);
5401
5402 dcprintk((MYIOC_s_INFO_FMT "Sending Toolbox request, Tool=%x\n",
5403 ioc->name, pReq->Tool));
5404
5405 /* Append pCfg pointer to end of mf
5406 */
5407 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5408
5409 /* Initalize the timer
5410 */
5411 init_timer(&pCfg->timer);
5412 pCfg->timer.data = (unsigned long) ioc;
5413 pCfg->timer.function = mpt_timer_expired;
5414 pCfg->wait_done = 0;
5415
5416 /* Set the timer; ensure 10 second minimum */
5417 if (pCfg->timeout < 10)
5418 pCfg->timer.expires = jiffies + HZ*10;
5419 else
5420 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5421
5422 /* Add to end of Q, set timer and then issue this command */
5423 spin_lock_irqsave(&ioc->FreeQlock, flags);
5424 list_add_tail(&pCfg->linkage, &ioc->configQ);
5425 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5426
5427 add_timer(&pCfg->timer);
5428 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5429 wait_event(mpt_waitq, pCfg->wait_done);
5430
5431 /* mf has been freed - do not access */
5432
5433 rc = pCfg->status;
5434
5435 return rc;
5436}
5437
5438/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5439/*
5440 * mpt_timer_expired - Call back for timer process.
5441 * Used only internal config functionality.
5442 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5443 */
5444static void
5445mpt_timer_expired(unsigned long data)
5446{
5447 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5448
5449 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5450
5451 /* Perform a FW reload */
5452 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5453 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5454
5455 /* No more processing.
5456 * Hard reset clean-up will wake up
5457 * process and free all resources.
5458 */
5459 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5460
5461 return;
5462}
5463
5464/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5465/*
5466 * mpt_ioc_reset - Base cleanup for hard reset
5467 * @ioc: Pointer to the adapter structure
5468 * @reset_phase: Indicates pre- or post-reset functionality
5469 *
5470 * Remark: Free's resources with internally generated commands.
5471 */
5472static int
5473mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5474{
5475 CONFIGPARMS *pCfg;
5476 unsigned long flags;
5477
5478 dprintk((KERN_WARNING MYNAM
5479 ": IOC %s_reset routed to MPT base driver!\n",
5480 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5481 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5482
5483 if (reset_phase == MPT_IOC_SETUP_RESET) {
5484 ;
5485 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5486 /* If the internal config Q is not empty -
5487 * delete timer. MF resources will be freed when
5488 * the FIFO's are primed.
5489 */
5490 spin_lock_irqsave(&ioc->FreeQlock, flags);
5491 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5492 del_timer(&pCfg->timer);
5493 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5494
5495 } else {
5496 CONFIGPARMS *pNext;
5497
5498 /* Search the configQ for internal commands.
5499 * Flush the Q, and wake up all suspended threads.
5500 */
5501 spin_lock_irqsave(&ioc->FreeQlock, flags);
5502 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5503 list_del(&pCfg->linkage);
5504
5505 pCfg->status = MPT_CONFIG_ERROR;
5506 pCfg->wait_done = 1;
5507 wake_up(&mpt_waitq);
5508 }
5509 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5510 }
5511
5512 return 1; /* currently means nothing really */
5513}
5514
5515
5516#ifdef CONFIG_PROC_FS /* { */
5517/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5518/*
5519 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5520 */
5521/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5522/*
5523 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5524 *
5525 * Returns 0 for success, non-zero for failure.
5526 */
5527static int
5528procmpt_create(void)
5529{
5530 struct proc_dir_entry *ent;
5531
5532 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5533 if (mpt_proc_root_dir == NULL)
5534 return -ENOTDIR;
5535
5536 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5537 if (ent)
5538 ent->read_proc = procmpt_summary_read;
5539
5540 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5541 if (ent)
5542 ent->read_proc = procmpt_version_read;
5543
5544 return 0;
5545}
5546
5547/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5548/*
5549 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5550 *
5551 * Returns 0 for success, non-zero for failure.
5552 */
5553static void
5554procmpt_destroy(void)
5555{
5556 remove_proc_entry("version", mpt_proc_root_dir);
5557 remove_proc_entry("summary", mpt_proc_root_dir);
5558 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5559}
5560
5561/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5562/*
5563 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5564 * or from /proc/mpt/iocN/summary.
5565 * @buf: Pointer to area to write information
5566 * @start: Pointer to start pointer
5567 * @offset: Offset to start writing
5568 * @request:
5569 * @eof: Pointer to EOF integer
5570 * @data: Pointer
5571 *
5572 * Returns number of characters written to process performing the read.
5573 */
5574static int
5575procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5576{
5577 MPT_ADAPTER *ioc;
5578 char *out = buf;
5579 int len;
5580
5581 if (data) {
5582 int more = 0;
5583
5584 ioc = data;
5585 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5586
5587 out += more;
5588 } else {
5589 list_for_each_entry(ioc, &ioc_list, list) {
5590 int more = 0;
5591
5592 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5593
5594 out += more;
5595 if ((out-buf) >= request)
5596 break;
5597 }
5598 }
5599
5600 len = out - buf;
5601
5602 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5603}
5604
5605/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5606/*
5607 * procmpt_version_read - Handle read request from /proc/mpt/version.
5608 * @buf: Pointer to area to write information
5609 * @start: Pointer to start pointer
5610 * @offset: Offset to start writing
5611 * @request:
5612 * @eof: Pointer to EOF integer
5613 * @data: Pointer
5614 *
5615 * Returns number of characters written to process performing the read.
5616 */
5617static int
5618procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5619{
5620 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005621 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 char *drvname;
5623 int len;
5624
5625 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5626 len += sprintf(buf+len, " Fusion MPT base driver\n");
5627
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005628 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5630 drvname = NULL;
5631 if (MptCallbacks[ii]) {
5632 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005633 case MPTSPI_DRIVER:
5634 if (!scsi++) drvname = "SPI host";
5635 break;
5636 case MPTFC_DRIVER:
5637 if (!fc++) drvname = "FC host";
5638 break;
5639 case MPTSAS_DRIVER:
5640 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 break;
5642 case MPTLAN_DRIVER:
5643 if (!lan++) drvname = "LAN";
5644 break;
5645 case MPTSTM_DRIVER:
5646 if (!targ++) drvname = "SCSI target";
5647 break;
5648 case MPTCTL_DRIVER:
5649 if (!ctl++) drvname = "ioctl";
5650 break;
5651 }
5652
5653 if (drvname)
5654 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5655 }
5656 }
5657
5658 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5659}
5660
5661/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5662/*
5663 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5664 * @buf: Pointer to area to write information
5665 * @start: Pointer to start pointer
5666 * @offset: Offset to start writing
5667 * @request:
5668 * @eof: Pointer to EOF integer
5669 * @data: Pointer
5670 *
5671 * Returns number of characters written to process performing the read.
5672 */
5673static int
5674procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5675{
5676 MPT_ADAPTER *ioc = data;
5677 int len;
5678 char expVer[32];
5679 int sz;
5680 int p;
5681
5682 mpt_get_fw_exp_ver(expVer, ioc);
5683
5684 len = sprintf(buf, "%s:", ioc->name);
5685 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5686 len += sprintf(buf+len, " (f/w download boot flag set)");
5687// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5688// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5689
5690 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5691 ioc->facts.ProductID,
5692 ioc->prod_name);
5693 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5694 if (ioc->facts.FWImageSize)
5695 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5696 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5697 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5698 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5699
5700 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5701 ioc->facts.CurrentHostMfaHighAddr);
5702 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5703 ioc->facts.CurrentSenseBufferHighAddr);
5704
5705 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5706 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5707
5708 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5709 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5710 /*
5711 * Rounding UP to nearest 4-kB boundary here...
5712 */
5713 sz = (ioc->req_sz * ioc->req_depth) + 128;
5714 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5715 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5716 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5717 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5718 4*ioc->facts.RequestFrameSize,
5719 ioc->facts.GlobalCredits);
5720
5721 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5722 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5723 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5724 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5725 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5726 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5727 ioc->facts.CurReplyFrameSize,
5728 ioc->facts.ReplyQueueDepth);
5729
5730 len += sprintf(buf+len, " MaxDevices = %d\n",
5731 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5732 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5733
5734 /* per-port info */
5735 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5736 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5737 p+1,
5738 ioc->facts.NumberOfPorts);
5739 if (ioc->bus_type == FC) {
5740 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5741 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5742 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5743 a[5], a[4], a[3], a[2], a[1], a[0]);
5744 }
5745 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5746 ioc->fc_port_page0[p].WWNN.High,
5747 ioc->fc_port_page0[p].WWNN.Low,
5748 ioc->fc_port_page0[p].WWPN.High,
5749 ioc->fc_port_page0[p].WWPN.Low);
5750 }
5751 }
5752
5753 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5754}
5755
5756#endif /* CONFIG_PROC_FS } */
5757
5758/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5759static void
5760mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5761{
5762 buf[0] ='\0';
5763 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5764 sprintf(buf, " (Exp %02d%02d)",
5765 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5766 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5767
5768 /* insider hack! */
5769 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5770 strcat(buf, " [MDBG]");
5771 }
5772}
5773
5774/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5775/**
5776 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5777 * @ioc: Pointer to MPT_ADAPTER structure
5778 * @buffer: Pointer to buffer where IOC summary info should be written
5779 * @size: Pointer to number of bytes we wrote (set by this routine)
5780 * @len: Offset at which to start writing in buffer
5781 * @showlan: Display LAN stuff?
5782 *
5783 * This routine writes (english readable) ASCII text, which represents
5784 * a summary of IOC information, to a buffer.
5785 */
5786void
5787mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5788{
5789 char expVer[32];
5790 int y;
5791
5792 mpt_get_fw_exp_ver(expVer, ioc);
5793
5794 /*
5795 * Shorter summary of attached ioc's...
5796 */
5797 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5798 ioc->name,
5799 ioc->prod_name,
5800 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5801 ioc->facts.FWVersion.Word,
5802 expVer,
5803 ioc->facts.NumberOfPorts,
5804 ioc->req_depth);
5805
5806 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5807 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5808 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5809 a[5], a[4], a[3], a[2], a[1], a[0]);
5810 }
5811
5812#ifndef __sparc__
5813 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
5814#else
5815 y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
5816#endif
5817
5818 if (!ioc->active)
5819 y += sprintf(buffer+len+y, " (disabled)");
5820
5821 y += sprintf(buffer+len+y, "\n");
5822
5823 *size = y;
5824}
5825
5826/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5827/*
5828 * Reset Handling
5829 */
5830/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5831/**
5832 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5833 * Management call based on input arg values. If TaskMgmt fails,
5834 * return associated SCSI request.
5835 * @ioc: Pointer to MPT_ADAPTER structure
5836 * @sleepFlag: Indicates if sleep or schedule must be called.
5837 *
5838 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5839 * or a non-interrupt thread. In the former, must not call schedule().
5840 *
5841 * Remark: A return of -1 is a FATAL error case, as it means a
5842 * FW reload/initialization failed.
5843 *
5844 * Returns 0 for SUCCESS or -1 if FAILED.
5845 */
5846int
5847mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5848{
5849 int rc;
5850 unsigned long flags;
5851
5852 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5853#ifdef MFCNT
5854 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5855 printk("MF count 0x%x !\n", ioc->mfcnt);
5856#endif
5857
5858 /* Reset the adapter. Prevent more than 1 call to
5859 * mpt_do_ioc_recovery at any instant in time.
5860 */
5861 spin_lock_irqsave(&ioc->diagLock, flags);
5862 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5863 spin_unlock_irqrestore(&ioc->diagLock, flags);
5864 return 0;
5865 } else {
5866 ioc->diagPending = 1;
5867 }
5868 spin_unlock_irqrestore(&ioc->diagLock, flags);
5869
5870 /* FIXME: If do_ioc_recovery fails, repeat....
5871 */
5872
5873 /* The SCSI driver needs to adjust timeouts on all current
5874 * commands prior to the diagnostic reset being issued.
5875 * Prevents timeouts occuring during a diagnostic reset...very bad.
5876 * For all other protocol drivers, this is a no-op.
5877 */
5878 {
5879 int ii;
5880 int r = 0;
5881
5882 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5883 if (MptResetHandlers[ii]) {
5884 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5885 ioc->name, ii));
5886 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
5887 if (ioc->alt_ioc) {
5888 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5889 ioc->name, ioc->alt_ioc->name, ii));
5890 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
5891 }
5892 }
5893 }
5894 }
5895
5896 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5897 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5898 rc, ioc->name);
5899 }
5900 ioc->reload_fw = 0;
5901 if (ioc->alt_ioc)
5902 ioc->alt_ioc->reload_fw = 0;
5903
5904 spin_lock_irqsave(&ioc->diagLock, flags);
5905 ioc->diagPending = 0;
5906 if (ioc->alt_ioc)
5907 ioc->alt_ioc->diagPending = 0;
5908 spin_unlock_irqrestore(&ioc->diagLock, flags);
5909
5910 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5911
5912 return rc;
5913}
5914
5915/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005916static void
5917EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918{
5919 char *ds;
5920
5921 switch(event) {
5922 case MPI_EVENT_NONE:
5923 ds = "None";
5924 break;
5925 case MPI_EVENT_LOG_DATA:
5926 ds = "Log Data";
5927 break;
5928 case MPI_EVENT_STATE_CHANGE:
5929 ds = "State Change";
5930 break;
5931 case MPI_EVENT_UNIT_ATTENTION:
5932 ds = "Unit Attention";
5933 break;
5934 case MPI_EVENT_IOC_BUS_RESET:
5935 ds = "IOC Bus Reset";
5936 break;
5937 case MPI_EVENT_EXT_BUS_RESET:
5938 ds = "External Bus Reset";
5939 break;
5940 case MPI_EVENT_RESCAN:
5941 ds = "Bus Rescan Event";
5942 /* Ok, do we need to do anything here? As far as
5943 I can tell, this is when a new device gets added
5944 to the loop. */
5945 break;
5946 case MPI_EVENT_LINK_STATUS_CHANGE:
5947 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5948 ds = "Link Status(FAILURE) Change";
5949 else
5950 ds = "Link Status(ACTIVE) Change";
5951 break;
5952 case MPI_EVENT_LOOP_STATE_CHANGE:
5953 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5954 ds = "Loop State(LIP) Change";
5955 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
5956 ds = "Loop State(LPE) Change"; /* ??? */
5957 else
5958 ds = "Loop State(LPB) Change"; /* ??? */
5959 break;
5960 case MPI_EVENT_LOGOUT:
5961 ds = "Logout";
5962 break;
5963 case MPI_EVENT_EVENT_CHANGE:
5964 if (evData0)
5965 ds = "Events(ON) Change";
5966 else
5967 ds = "Events(OFF) Change";
5968 break;
5969 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005970 {
5971 u8 ReasonCode = (u8)(evData0 >> 16);
5972 switch (ReasonCode) {
5973 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5974 ds = "Integrated Raid: Volume Created";
5975 break;
5976 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5977 ds = "Integrated Raid: Volume Deleted";
5978 break;
5979 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5980 ds = "Integrated Raid: Volume Settings Changed";
5981 break;
5982 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5983 ds = "Integrated Raid: Volume Status Changed";
5984 break;
5985 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5986 ds = "Integrated Raid: Volume Physdisk Changed";
5987 break;
5988 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5989 ds = "Integrated Raid: Physdisk Created";
5990 break;
5991 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5992 ds = "Integrated Raid: Physdisk Deleted";
5993 break;
5994 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5995 ds = "Integrated Raid: Physdisk Settings Changed";
5996 break;
5997 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5998 ds = "Integrated Raid: Physdisk Status Changed";
5999 break;
6000 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6001 ds = "Integrated Raid: Domain Validation Needed";
6002 break;
6003 case MPI_EVENT_RAID_RC_SMART_DATA :
6004 ds = "Integrated Raid; Smart Data";
6005 break;
6006 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6007 ds = "Integrated Raid: Replace Action Started";
6008 break;
6009 default:
6010 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006012 }
6013 break;
6014 }
6015 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6016 ds = "SCSI Device Status Change";
6017 break;
6018 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6019 {
6020 u8 ReasonCode = (u8)(evData0 >> 16);
6021 switch (ReasonCode) {
6022 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
6023 ds = "SAS Device Status Change: Added";
6024 break;
6025 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
6026 ds = "SAS Device Status Change: Deleted";
6027 break;
6028 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
6029 ds = "SAS Device Status Change: SMART Data";
6030 break;
6031 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
6032 ds = "SAS Device Status Change: No Persistancy Added";
6033 break;
6034 default:
6035 ds = "SAS Device Status Change: Unknown";
6036 break;
6037 }
6038 break;
6039 }
6040 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6041 ds = "Bus Timer Expired";
6042 break;
6043 case MPI_EVENT_QUEUE_FULL:
6044 ds = "Queue Full";
6045 break;
6046 case MPI_EVENT_SAS_SES:
6047 ds = "SAS SES Event";
6048 break;
6049 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6050 ds = "Persistent Table Full";
6051 break;
6052 case MPI_EVENT_SAS_PHY_LINK_STATUS:
6053 ds = "SAS PHY Link Status";
6054 break;
6055 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6056 ds = "SAS Discovery Error";
6057 break;
6058
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 /*
6060 * MPT base "custom" events may be added here...
6061 */
6062 default:
6063 ds = "Unknown";
6064 break;
6065 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006066 strcpy(evStr,ds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067}
6068
6069/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6070/*
6071 * ProcessEventNotification - Route a received EventNotificationReply to
6072 * all currently regeistered event handlers.
6073 * @ioc: Pointer to MPT_ADAPTER structure
6074 * @pEventReply: Pointer to EventNotification reply frame
6075 * @evHandlers: Pointer to integer, number of event handlers
6076 *
6077 * Returns sum of event handlers return values.
6078 */
6079static int
6080ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6081{
6082 u16 evDataLen;
6083 u32 evData0 = 0;
6084// u32 evCtx;
6085 int ii;
6086 int r = 0;
6087 int handlers = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006088 char evStr[100];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089 u8 event;
6090
6091 /*
6092 * Do platform normalization of values
6093 */
6094 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6095// evCtx = le32_to_cpu(pEventReply->EventContext);
6096 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6097 if (evDataLen) {
6098 evData0 = le32_to_cpu(pEventReply->Data[0]);
6099 }
6100
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006101 EventDescriptionStr(event, evData0, evStr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 devtprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
6103 ioc->name,
6104 evStr,
6105 event));
6106
6107#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
6108 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6109 for (ii = 0; ii < evDataLen; ii++)
6110 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6111 printk("\n");
6112#endif
6113
6114 /*
6115 * Do general / base driver event processing
6116 */
6117 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6119 if (evDataLen) {
6120 u8 evState = evData0 & 0xFF;
6121
6122 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6123
6124 /* Update EventState field in cached IocFacts */
6125 if (ioc->facts.Function) {
6126 ioc->facts.EventState = evState;
6127 }
6128 }
6129 break;
Moore, Ericece50912006-01-16 18:53:19 -07006130 case MPI_EVENT_INTEGRATED_RAID:
6131 mptbase_raid_process_event_data(ioc,
6132 (MpiEventDataRaid_t *)pEventReply->Data);
6133 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006134 default:
6135 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 }
6137
6138 /*
6139 * Should this event be logged? Events are written sequentially.
6140 * When buffer is full, start again at the top.
6141 */
6142 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6143 int idx;
6144
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006145 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146
6147 ioc->events[idx].event = event;
6148 ioc->events[idx].eventContext = ioc->eventContext;
6149
6150 for (ii = 0; ii < 2; ii++) {
6151 if (ii < evDataLen)
6152 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6153 else
6154 ioc->events[idx].data[ii] = 0;
6155 }
6156
6157 ioc->eventContext++;
6158 }
6159
6160
6161 /*
6162 * Call each currently registered protocol event handler.
6163 */
6164 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6165 if (MptEvHandlers[ii]) {
6166 devtprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
6167 ioc->name, ii));
6168 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6169 handlers++;
6170 }
6171 }
6172 /* FIXME? Examine results here? */
6173
6174 /*
6175 * If needed, send (a single) EventAck.
6176 */
6177 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006178 devtprintk((MYIOC_s_WARN_FMT
6179 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
6181 devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
6182 ioc->name, ii));
6183 }
6184 }
6185
6186 *evHandlers = handlers;
6187 return r;
6188}
6189
6190/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6191/*
6192 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6193 * @ioc: Pointer to MPT_ADAPTER structure
6194 * @log_info: U32 LogInfo reply word from the IOC
6195 *
6196 * Refer to lsi/fc_log.h.
6197 */
6198static void
6199mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6200{
6201 static char *subcl_str[8] = {
6202 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6203 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6204 };
6205 u8 subcl = (log_info >> 24) & 0x7;
6206
6207 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6208 ioc->name, log_info, subcl_str[subcl]);
6209}
6210
6211/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6212/*
Moore, Eric335a9412006-01-17 17:06:23 -07006213 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 * @ioc: Pointer to MPT_ADAPTER structure
6215 * @mr: Pointer to MPT reply frame
6216 * @log_info: U32 LogInfo word from the IOC
6217 *
6218 * Refer to lsi/sp_log.h.
6219 */
6220static void
Moore, Eric335a9412006-01-17 17:06:23 -07006221mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222{
6223 u32 info = log_info & 0x00FF0000;
6224 char *desc = "unknown";
6225
6226 switch (info) {
6227 case 0x00010000:
6228 desc = "bug! MID not found";
6229 if (ioc->reload_fw == 0)
6230 ioc->reload_fw++;
6231 break;
6232
6233 case 0x00020000:
6234 desc = "Parity Error";
6235 break;
6236
6237 case 0x00030000:
6238 desc = "ASYNC Outbound Overrun";
6239 break;
6240
6241 case 0x00040000:
6242 desc = "SYNC Offset Error";
6243 break;
6244
6245 case 0x00050000:
6246 desc = "BM Change";
6247 break;
6248
6249 case 0x00060000:
6250 desc = "Msg In Overflow";
6251 break;
6252
6253 case 0x00070000:
6254 desc = "DMA Error";
6255 break;
6256
6257 case 0x00080000:
6258 desc = "Outbound DMA Overrun";
6259 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006260
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261 case 0x00090000:
6262 desc = "Task Management";
6263 break;
6264
6265 case 0x000A0000:
6266 desc = "Device Problem";
6267 break;
6268
6269 case 0x000B0000:
6270 desc = "Invalid Phase Change";
6271 break;
6272
6273 case 0x000C0000:
6274 desc = "Untagged Table Size";
6275 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006276
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277 }
6278
6279 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6280}
6281
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006282/* strings for sas loginfo */
6283 static char *originator_str[] = {
6284 "IOP", /* 00h */
6285 "PL", /* 01h */
6286 "IR" /* 02h */
6287 };
6288 static char *iop_code_str[] = {
6289 NULL, /* 00h */
6290 "Invalid SAS Address", /* 01h */
6291 NULL, /* 02h */
6292 "Invalid Page", /* 03h */
6293 NULL, /* 04h */
6294 "Task Terminated" /* 05h */
6295 };
6296 static char *pl_code_str[] = {
6297 NULL, /* 00h */
6298 "Open Failure", /* 01h */
6299 "Invalid Scatter Gather List", /* 02h */
6300 "Wrong Relative Offset or Frame Length", /* 03h */
6301 "Frame Transfer Error", /* 04h */
6302 "Transmit Frame Connected Low", /* 05h */
6303 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6304 "SATA Read Log Receive Data Error", /* 07h */
6305 "SATA NCQ Fail All Commands After Error", /* 08h */
6306 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6307 "Receive Frame Invalid Message", /* 0Ah */
6308 "Receive Context Message Valid Error", /* 0Bh */
6309 "Receive Frame Current Frame Error", /* 0Ch */
6310 "SATA Link Down", /* 0Dh */
6311 "Discovery SATA Init W IOS", /* 0Eh */
6312 "Config Invalid Page", /* 0Fh */
6313 "Discovery SATA Init Timeout", /* 10h */
6314 "Reset", /* 11h */
6315 "Abort", /* 12h */
6316 "IO Not Yet Executed", /* 13h */
6317 "IO Executed", /* 14h */
6318 NULL, /* 15h */
6319 NULL, /* 16h */
6320 NULL, /* 17h */
6321 NULL, /* 18h */
6322 NULL, /* 19h */
6323 NULL, /* 1Ah */
6324 NULL, /* 1Bh */
6325 NULL, /* 1Ch */
6326 NULL, /* 1Dh */
6327 NULL, /* 1Eh */
6328 NULL, /* 1Fh */
6329 "Enclosure Management" /* 20h */
6330 };
6331
6332/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6333/*
6334 * mpt_sas_log_info - Log information returned from SAS IOC.
6335 * @ioc: Pointer to MPT_ADAPTER structure
6336 * @log_info: U32 LogInfo reply word from the IOC
6337 *
6338 * Refer to lsi/mpi_log_sas.h.
6339 */
6340static void
6341mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6342{
6343union loginfo_type {
6344 u32 loginfo;
6345 struct {
6346 u32 subcode:16;
6347 u32 code:8;
6348 u32 originator:4;
6349 u32 bus_type:4;
6350 }dw;
6351};
6352 union loginfo_type sas_loginfo;
6353 char *code_desc = NULL;
6354
6355 sas_loginfo.loginfo = log_info;
6356 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6357 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6358 return;
6359 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6360 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6361 code_desc = iop_code_str[sas_loginfo.dw.code];
6362 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6363 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6364 code_desc = pl_code_str[sas_loginfo.dw.code];
6365 }
6366
6367 if (code_desc != NULL)
6368 printk(MYIOC_s_INFO_FMT
6369 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6370 " SubCode(0x%04x)\n",
6371 ioc->name,
6372 log_info,
6373 originator_str[sas_loginfo.dw.originator],
6374 code_desc,
6375 sas_loginfo.dw.subcode);
6376 else
6377 printk(MYIOC_s_INFO_FMT
6378 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6379 " SubCode(0x%04x)\n",
6380 ioc->name,
6381 log_info,
6382 originator_str[sas_loginfo.dw.originator],
6383 sas_loginfo.dw.code,
6384 sas_loginfo.dw.subcode);
6385}
6386
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6388/*
6389 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6390 * @ioc: Pointer to MPT_ADAPTER structure
6391 * @ioc_status: U32 IOCStatus word from IOC
6392 * @mf: Pointer to MPT request frame
6393 *
6394 * Refer to lsi/mpi.h.
6395 */
6396static void
6397mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6398{
6399 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
6400 char *desc = "";
6401
6402 switch (status) {
6403 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6404 desc = "Invalid Function";
6405 break;
6406
6407 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6408 desc = "Busy";
6409 break;
6410
6411 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6412 desc = "Invalid SGL";
6413 break;
6414
6415 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6416 desc = "Internal Error";
6417 break;
6418
6419 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6420 desc = "Reserved";
6421 break;
6422
6423 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6424 desc = "Insufficient Resources";
6425 break;
6426
6427 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6428 desc = "Invalid Field";
6429 break;
6430
6431 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6432 desc = "Invalid State";
6433 break;
6434
6435 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6436 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6437 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6438 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6439 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6440 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6441 /* No message for Config IOCStatus values */
6442 break;
6443
6444 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6445 /* No message for recovered error
6446 desc = "SCSI Recovered Error";
6447 */
6448 break;
6449
6450 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6451 desc = "SCSI Invalid Bus";
6452 break;
6453
6454 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6455 desc = "SCSI Invalid TargetID";
6456 break;
6457
6458 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6459 {
6460 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6461 U8 cdb = pScsiReq->CDB[0];
6462 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6463 desc = "SCSI Device Not There";
6464 }
6465 break;
6466 }
6467
6468 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6469 desc = "SCSI Data Overrun";
6470 break;
6471
6472 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006473 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474 desc = "SCSI Data Underrun";
6475 */
6476 break;
6477
6478 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6479 desc = "SCSI I/O Data Error";
6480 break;
6481
6482 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6483 desc = "SCSI Protocol Error";
6484 break;
6485
6486 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6487 desc = "SCSI Task Terminated";
6488 break;
6489
6490 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6491 desc = "SCSI Residual Mismatch";
6492 break;
6493
6494 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6495 desc = "SCSI Task Management Failed";
6496 break;
6497
6498 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6499 desc = "SCSI IOC Terminated";
6500 break;
6501
6502 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6503 desc = "SCSI Ext Terminated";
6504 break;
6505
6506 default:
6507 desc = "Others";
6508 break;
6509 }
6510 if (desc != "")
6511 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6512}
6513
6514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006515EXPORT_SYMBOL(mpt_attach);
6516EXPORT_SYMBOL(mpt_detach);
6517#ifdef CONFIG_PM
6518EXPORT_SYMBOL(mpt_resume);
6519EXPORT_SYMBOL(mpt_suspend);
6520#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006521EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006522EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523EXPORT_SYMBOL(mpt_register);
6524EXPORT_SYMBOL(mpt_deregister);
6525EXPORT_SYMBOL(mpt_event_register);
6526EXPORT_SYMBOL(mpt_event_deregister);
6527EXPORT_SYMBOL(mpt_reset_register);
6528EXPORT_SYMBOL(mpt_reset_deregister);
6529EXPORT_SYMBOL(mpt_device_driver_register);
6530EXPORT_SYMBOL(mpt_device_driver_deregister);
6531EXPORT_SYMBOL(mpt_get_msg_frame);
6532EXPORT_SYMBOL(mpt_put_msg_frame);
6533EXPORT_SYMBOL(mpt_free_msg_frame);
6534EXPORT_SYMBOL(mpt_add_sge);
6535EXPORT_SYMBOL(mpt_send_handshake_request);
6536EXPORT_SYMBOL(mpt_verify_adapter);
6537EXPORT_SYMBOL(mpt_GetIocState);
6538EXPORT_SYMBOL(mpt_print_ioc_summary);
6539EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006540EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006541EXPORT_SYMBOL(mpt_HardResetHandler);
6542EXPORT_SYMBOL(mpt_config);
6543EXPORT_SYMBOL(mpt_toolbox);
6544EXPORT_SYMBOL(mpt_findImVolumes);
6545EXPORT_SYMBOL(mpt_read_ioc_pg_3);
6546EXPORT_SYMBOL(mpt_alloc_fw_memory);
6547EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006548EXPORT_SYMBOL(mptbase_sas_persist_operation);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07006549EXPORT_SYMBOL(mpt_alt_ioc_wait);
Michael Reed05e8ec12006-01-13 14:31:54 -06006550EXPORT_SYMBOL(mptbase_GetFcPortPage0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006551
Linus Torvalds1da177e2005-04-16 15:20:36 -07006552
6553/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6554/*
6555 * fusion_init - Fusion MPT base driver initialization routine.
6556 *
6557 * Returns 0 for success, non-zero for failure.
6558 */
6559static int __init
6560fusion_init(void)
6561{
6562 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006563
6564 show_mptmod_ver(my_NAME, my_VERSION);
6565 printk(KERN_INFO COPYRIGHT "\n");
6566
6567 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6568 MptCallbacks[i] = NULL;
6569 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6570 MptEvHandlers[i] = NULL;
6571 MptResetHandlers[i] = NULL;
6572 }
6573
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006574 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006575 * EventNotification handling.
6576 */
6577 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6578
6579 /* Register for hard reset handling callbacks.
6580 */
6581 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6582 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6583 } else {
6584 /* FIXME! */
6585 }
6586
6587#ifdef CONFIG_PROC_FS
6588 (void) procmpt_create();
6589#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006590 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006591}
6592
6593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6594/*
6595 * fusion_exit - Perform driver unload cleanup.
6596 *
6597 * This routine frees all resources associated with each MPT adapter
6598 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6599 */
6600static void __exit
6601fusion_exit(void)
6602{
6603
6604 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6605
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606 mpt_reset_deregister(mpt_base_index);
6607
6608#ifdef CONFIG_PROC_FS
6609 procmpt_destroy();
6610#endif
6611}
6612
Linus Torvalds1da177e2005-04-16 15:20:36 -07006613module_init(fusion_init);
6614module_exit(fusion_exit);