blob: 04f75e24dcecb2cd513a1275df597ed914ea7676 [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 *
Eric Moore9f4203b2007-01-04 20:47:47 -07008 * Copyright (c) 1999-2007 LSI Logic Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000082static int mpt_msi_enable;
83module_param(mpt_msi_enable, int, 0);
84MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086static int mpt_channel_mapping;
87module_param(mpt_channel_mapping, int, 0);
88MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
89
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#ifdef MFCNT
91static int mfcounter = 0;
92#define PRINT_MF_COUNT 20000
93#endif
94
95/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
96/*
97 * Public data...
98 */
99int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -0800100int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Linus Torvaldsf7473072005-11-29 14:21:57 -0800102struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104#define WHOINIT_UNKNOWN 0xAA
105
106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
107/*
108 * Private data...
109 */
110 /* Adapter link list */
111LIST_HEAD(ioc_list);
112 /* Callback lookup table */
113static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
114 /* Protocol driver class lookup table */
115static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
116 /* Event handler lookup table */
117static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
118 /* Reset handler lookup table */
119static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
120static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
121
122static int mpt_base_index = -1;
123static int last_drv_idx = -1;
124
125static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
126
127/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
128/*
129 * Forward protos...
130 */
David Howells7d12e782006-10-05 14:55:46 +0100131static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
133static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
134 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
135 int sleepFlag);
136static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
137static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
138static void mpt_adapter_disable(MPT_ADAPTER *ioc);
139static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
140
141static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
142static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
144static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
145static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
146static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
147static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200148static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
150static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
151static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
152static int PrimeIocFifos(MPT_ADAPTER *ioc);
153static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
154static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
155static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
156static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200158int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
160static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
161static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
162static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
163static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530164static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
166static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200167static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
168static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
170#ifdef CONFIG_PROC_FS
171static int procmpt_summary_read(char *buf, char **start, off_t offset,
172 int request, int *eof, void *data);
173static int procmpt_version_read(char *buf, char **start, off_t offset,
174 int request, int *eof, void *data);
175static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
176 int request, int *eof, void *data);
177#endif
178static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
179
180//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
181static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700182#ifdef MPT_DEBUG_REPLY
183static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
184#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700186static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600187static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700188static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700189static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192static int __init fusion_init (void);
193static void __exit fusion_exit (void);
194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195#define CHIPREG_READ32(addr) readl_relaxed(addr)
196#define CHIPREG_READ32_dmasync(addr) readl(addr)
197#define CHIPREG_WRITE32(addr,val) writel(val, addr)
198#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
199#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
200
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600201static void
202pci_disable_io_access(struct pci_dev *pdev)
203{
204 u16 command_reg;
205
206 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
207 command_reg &= ~1;
208 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
209}
210
211static void
212pci_enable_io_access(struct pci_dev *pdev)
213{
214 u16 command_reg;
215
216 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
217 command_reg |= 1;
218 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
219}
220
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600221/*
222 * Process turbo (context) reply...
223 */
224static void
225mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
226{
227 MPT_FRAME_HDR *mf = NULL;
228 MPT_FRAME_HDR *mr = NULL;
229 int req_idx = 0;
230 int cb_idx;
231
232 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
233 ioc->name, pa));
234
235 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
236 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
237 req_idx = pa & 0x0000FFFF;
238 cb_idx = (pa & 0x00FF0000) >> 16;
239 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
240 break;
241 case MPI_CONTEXT_REPLY_TYPE_LAN:
242 cb_idx = mpt_lan_index;
243 /*
244 * Blind set of mf to NULL here was fatal
245 * after lan_reply says "freeme"
246 * Fix sort of combined with an optimization here;
247 * added explicit check for case where lan_reply
248 * was just returning 1 and doing nothing else.
249 * For this case skip the callback, but set up
250 * proper mf value first here:-)
251 */
252 if ((pa & 0x58000000) == 0x58000000) {
253 req_idx = pa & 0x0000FFFF;
254 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
255 mpt_free_msg_frame(ioc, mf);
256 mb();
257 return;
258 break;
259 }
260 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
261 break;
262 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
263 cb_idx = mpt_stm_index;
264 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
265 break;
266 default:
267 cb_idx = 0;
268 BUG();
269 }
270
271 /* Check for (valid) IO callback! */
272 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
273 MptCallbacks[cb_idx] == NULL) {
274 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
275 __FUNCTION__, ioc->name, cb_idx);
276 goto out;
277 }
278
279 if (MptCallbacks[cb_idx](ioc, mf, mr))
280 mpt_free_msg_frame(ioc, mf);
281 out:
282 mb();
283}
284
285static void
286mpt_reply(MPT_ADAPTER *ioc, u32 pa)
287{
288 MPT_FRAME_HDR *mf;
289 MPT_FRAME_HDR *mr;
290 int req_idx;
291 int cb_idx;
292 int freeme;
293
294 u32 reply_dma_low;
295 u16 ioc_stat;
296
297 /* non-TURBO reply! Hmmm, something may be up...
298 * Newest turbo reply mechanism; get address
299 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
300 */
301
302 /* Map DMA address of reply header to cpu address.
303 * pa is 32 bits - but the dma address may be 32 or 64 bits
304 * get offset based only only the low addresses
305 */
306
307 reply_dma_low = (pa <<= 1);
308 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
309 (reply_dma_low - ioc->reply_frames_low_dma));
310
311 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
312 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
313 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
314
315 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
316 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
317 DBG_DUMP_REPLY_FRAME(mr)
318
319 /* Check/log IOC log info
320 */
321 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
322 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
323 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
324 if (ioc->bus_type == FC)
325 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700326 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700327 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600328 else if (ioc->bus_type == SAS)
329 mpt_sas_log_info(ioc, log_info);
330 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600331
Eric Moorec6c727a2007-01-29 09:44:54 -0700332#ifdef MPT_DEBUG_REPLY
333 if (ioc_stat & MPI_IOCSTATUS_MASK)
334 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
335#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600336
337 /* Check for (valid) IO callback! */
338 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
339 MptCallbacks[cb_idx] == NULL) {
340 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
341 __FUNCTION__, ioc->name, cb_idx);
342 freeme = 0;
343 goto out;
344 }
345
346 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
347
348 out:
349 /* Flush (non-TURBO) reply with a WRITE! */
350 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
351
352 if (freeme)
353 mpt_free_msg_frame(ioc, mf);
354 mb();
355}
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800358/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
360 * @irq: irq number (not used)
361 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 *
363 * This routine is registered via the request_irq() kernel API call,
364 * and handles all interrupts generated from a specific MPT adapter
365 * (also referred to as a IO Controller or IOC).
366 * This routine must clear the interrupt from the adapter and does
367 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200368 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 *
370 * This routine handles register-level access of the adapter but
371 * dispatches (calls) a protocol-specific callback routine to handle
372 * the protocol-specific details of the MPT request completion.
373 */
374static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100375mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600377 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600378 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
379
380 if (pa == 0xFFFFFFFF)
381 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 /*
384 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600386 do {
387 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600388 mpt_reply(ioc, pa);
389 else
390 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600391 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
392 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
394 return IRQ_HANDLED;
395}
396
397/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800398/**
399 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 * @ioc: Pointer to MPT_ADAPTER structure
401 * @mf: Pointer to original MPT request frame
402 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
403 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800404 * MPT base driver's callback routine; all base driver
405 * "internal" request/reply processing is routed here.
406 * Currently used for EventNotification and EventAck handling.
407 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200408 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 * should be freed, or 0 if it shouldn't.
410 */
411static int
412mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
413{
414 int freereq = 1;
415 u8 func;
416
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200417 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200419#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
421 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
422 DBG_DUMP_REQUEST_FRAME_HDR(mf)
423 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200424#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200427 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 ioc->name, func));
429
430 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
431 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
432 int evHandlers = 0;
433 int results;
434
435 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
436 if (results != evHandlers) {
437 /* CHECKME! Any special handling needed here? */
Moore, Eric3a892be2006-03-14 09:14:03 -0700438 devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 ioc->name, evHandlers, results));
440 }
441
442 /*
443 * Hmmm... It seems that EventNotificationReply is an exception
444 * to the rule of one reply per request.
445 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200446 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200448 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700449 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200450 ioc->name, pEvReply));
451 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
453#ifdef CONFIG_PROC_FS
454// LogEvent(ioc, pEvReply);
455#endif
456
457 } else if (func == MPI_FUNCTION_EVENT_ACK) {
458 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
459 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700460 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 CONFIGPARMS *pCfg;
462 unsigned long flags;
463
464 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
465 ioc->name, mf, reply));
466
467 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
468
469 if (pCfg) {
470 /* disable timer and remove from linked list */
471 del_timer(&pCfg->timer);
472
473 spin_lock_irqsave(&ioc->FreeQlock, flags);
474 list_del(&pCfg->linkage);
475 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
476
477 /*
478 * If IOC Status is SUCCESS, save the header
479 * and set the status code to GOOD.
480 */
481 pCfg->status = MPT_CONFIG_ERROR;
482 if (reply) {
483 ConfigReply_t *pReply = (ConfigReply_t *)reply;
484 u16 status;
485
486 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
487 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
488 status, le32_to_cpu(pReply->IOCLogInfo)));
489
490 pCfg->status = status;
491 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200492 if ((pReply->Header.PageType &
493 MPI_CONFIG_PAGETYPE_MASK) ==
494 MPI_CONFIG_PAGETYPE_EXTENDED) {
495 pCfg->cfghdr.ehdr->ExtPageLength =
496 le16_to_cpu(pReply->ExtPageLength);
497 pCfg->cfghdr.ehdr->ExtPageType =
498 pReply->ExtPageType;
499 }
500 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
501
502 /* If this is a regular header, save PageLength. */
503 /* LMP Do this better so not using a reserved field! */
504 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
505 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
506 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 }
508 }
509
510 /*
511 * Wake up the original calling thread
512 */
513 pCfg->wait_done = 1;
514 wake_up(&mpt_waitq);
515 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200516 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
517 /* we should be always getting a reply frame */
518 memcpy(ioc->persist_reply_frame, reply,
519 min(MPT_DEFAULT_FRAME_SIZE,
520 4*reply->u.reply.MsgLength));
521 del_timer(&ioc->persist_timer);
522 ioc->persist_wait_done = 1;
523 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 } else {
525 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
526 ioc->name, func);
527 }
528
529 /*
530 * Conditionally tell caller to free the original
531 * EventNotification/EventAck/unexpected request frame!
532 */
533 return freereq;
534}
535
536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
537/**
538 * mpt_register - Register protocol-specific main callback handler.
539 * @cbfunc: callback function pointer
540 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
541 *
542 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800543 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 * protocol-specific driver must do this before it will be able to
545 * use any IOC resources, such as obtaining request frames.
546 *
547 * NOTES: The SCSI protocol driver currently calls this routine thrice
548 * in order to register separate callbacks; one for "normal" SCSI IO;
549 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
550 *
551 * Returns a positive integer valued "handle" in the
552 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
553 * Any non-positive return value (including zero!) should be considered
554 * an error by the caller.
555 */
556int
557mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
558{
559 int i;
560
561 last_drv_idx = -1;
562
563 /*
564 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
565 * (slot/handle 0 is reserved!)
566 */
567 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
568 if (MptCallbacks[i] == NULL) {
569 MptCallbacks[i] = cbfunc;
570 MptDriverClass[i] = dclass;
571 MptEvHandlers[i] = NULL;
572 last_drv_idx = i;
573 break;
574 }
575 }
576
577 return last_drv_idx;
578}
579
580/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
581/**
582 * mpt_deregister - Deregister a protocol drivers resources.
583 * @cb_idx: previously registered callback handle
584 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800585 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 * module is unloaded.
587 */
588void
589mpt_deregister(int cb_idx)
590{
591 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
592 MptCallbacks[cb_idx] = NULL;
593 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
594 MptEvHandlers[cb_idx] = NULL;
595
596 last_drv_idx++;
597 }
598}
599
600/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
601/**
602 * mpt_event_register - Register protocol-specific event callback
603 * handler.
604 * @cb_idx: previously registered (via mpt_register) callback handle
605 * @ev_cbfunc: callback function
606 *
607 * This routine can be called by one or more protocol-specific drivers
608 * if/when they choose to be notified of MPT events.
609 *
610 * Returns 0 for success.
611 */
612int
613mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
614{
615 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
616 return -1;
617
618 MptEvHandlers[cb_idx] = ev_cbfunc;
619 return 0;
620}
621
622/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
623/**
624 * mpt_event_deregister - Deregister protocol-specific event callback
625 * handler.
626 * @cb_idx: previously registered callback handle
627 *
628 * Each protocol-specific driver should call this routine
629 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800630 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 */
632void
633mpt_event_deregister(int cb_idx)
634{
635 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
636 return;
637
638 MptEvHandlers[cb_idx] = NULL;
639}
640
641/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
642/**
643 * mpt_reset_register - Register protocol-specific IOC reset handler.
644 * @cb_idx: previously registered (via mpt_register) callback handle
645 * @reset_func: reset function
646 *
647 * This routine can be called by one or more protocol-specific drivers
648 * if/when they choose to be notified of IOC resets.
649 *
650 * Returns 0 for success.
651 */
652int
653mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
654{
655 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
656 return -1;
657
658 MptResetHandlers[cb_idx] = reset_func;
659 return 0;
660}
661
662/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
663/**
664 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
665 * @cb_idx: previously registered callback handle
666 *
667 * Each protocol-specific driver should call this routine
668 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800669 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 */
671void
672mpt_reset_deregister(int cb_idx)
673{
674 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
675 return;
676
677 MptResetHandlers[cb_idx] = NULL;
678}
679
680/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
681/**
682 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800683 * @dd_cbfunc: driver callbacks struct
684 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 */
686int
687mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
688{
689 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600690 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Eric Moored58b2722006-07-11 17:23:23 -0600692 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400693 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
696
697 /* call per pci device probe entry point */
698 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600699 id = ioc->pcidev->driver ?
700 ioc->pcidev->driver->id_table : NULL;
701 if (dd_cbfunc->probe)
702 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 }
704
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400705 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706}
707
708/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
709/**
710 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800711 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 */
713void
714mpt_device_driver_deregister(int cb_idx)
715{
716 struct mpt_pci_driver *dd_cbfunc;
717 MPT_ADAPTER *ioc;
718
719 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
720 return;
721
722 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
723
724 list_for_each_entry(ioc, &ioc_list, list) {
725 if (dd_cbfunc->remove)
726 dd_cbfunc->remove(ioc->pcidev);
727 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200728
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 MptDeviceDriverHandlers[cb_idx] = NULL;
730}
731
732
733/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
734/**
735 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
736 * allocated per MPT adapter.
737 * @handle: Handle of registered MPT protocol driver
738 * @ioc: Pointer to MPT adapter structure
739 *
740 * Returns pointer to a MPT request frame or %NULL if none are available
741 * or IOC is not active.
742 */
743MPT_FRAME_HDR*
744mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
745{
746 MPT_FRAME_HDR *mf;
747 unsigned long flags;
748 u16 req_idx; /* Request index */
749
750 /* validate handle and ioc identifier */
751
752#ifdef MFCNT
753 if (!ioc->active)
754 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
755#endif
756
757 /* If interrupts are not attached, do not return a request frame */
758 if (!ioc->active)
759 return NULL;
760
761 spin_lock_irqsave(&ioc->FreeQlock, flags);
762 if (!list_empty(&ioc->FreeQ)) {
763 int req_offset;
764
765 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
766 u.frame.linkage.list);
767 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200768 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
770 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
771 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500772 req_idx = req_offset / ioc->req_sz;
773 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
775 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
776#ifdef MFCNT
777 ioc->mfcnt++;
778#endif
779 }
780 else
781 mf = NULL;
782 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
783
784#ifdef MFCNT
785 if (mf == NULL)
786 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
787 mfcounter++;
788 if (mfcounter == PRINT_MF_COUNT)
789 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
790#endif
791
792 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
793 ioc->name, handle, ioc->id, mf));
794 return mf;
795}
796
797/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
798/**
799 * mpt_put_msg_frame - Send a protocol specific MPT request frame
800 * to a IOC.
801 * @handle: Handle of registered MPT protocol driver
802 * @ioc: Pointer to MPT adapter structure
803 * @mf: Pointer to MPT request frame
804 *
805 * This routine posts a MPT request frame to the request post FIFO of a
806 * specific MPT adapter.
807 */
808void
809mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
810{
811 u32 mf_dma_addr;
812 int req_offset;
813 u16 req_idx; /* Request index */
814
815 /* ensure values are reset properly! */
816 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
817 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
818 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500819 req_idx = req_offset / ioc->req_sz;
820 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
822
823#ifdef MPT_DEBUG_MSG_FRAME
824 {
825 u32 *m = mf->u.frame.hwhdr.__hdr;
826 int ii, n;
827
828 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
829 ioc->name, m);
830 n = ioc->req_sz/4 - 1;
831 while (m[n] == 0)
832 n--;
833 for (ii=0; ii<=n; ii++) {
834 if (ii && ((ii%8)==0))
835 printk("\n" KERN_INFO " ");
836 printk(" %08x", le32_to_cpu(m[ii]));
837 }
838 printk("\n");
839 }
840#endif
841
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200842 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 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]));
844 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
845}
846
847/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
848/**
849 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
850 * @handle: Handle of registered MPT protocol driver
851 * @ioc: Pointer to MPT adapter structure
852 * @mf: Pointer to MPT request frame
853 *
854 * This routine places a MPT request frame back on the MPT adapter's
855 * FreeQ.
856 */
857void
858mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
859{
860 unsigned long flags;
861
862 /* Put Request back on FreeQ! */
863 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200864 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
866#ifdef MFCNT
867 ioc->mfcnt--;
868#endif
869 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
870}
871
872/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
873/**
874 * mpt_add_sge - Place a simple SGE at address pAddr.
875 * @pAddr: virtual address for SGE
876 * @flagslength: SGE flags and data transfer length
877 * @dma_addr: Physical address
878 *
879 * This routine places a MPT request frame back on the MPT adapter's
880 * FreeQ.
881 */
882void
883mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
884{
885 if (sizeof(dma_addr_t) == sizeof(u64)) {
886 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
887 u32 tmp = dma_addr & 0xFFFFFFFF;
888
889 pSge->FlagsLength = cpu_to_le32(flagslength);
890 pSge->Address.Low = cpu_to_le32(tmp);
891 tmp = (u32) ((u64)dma_addr >> 32);
892 pSge->Address.High = cpu_to_le32(tmp);
893
894 } else {
895 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
896 pSge->FlagsLength = cpu_to_le32(flagslength);
897 pSge->Address = cpu_to_le32(dma_addr);
898 }
899}
900
901/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
902/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800903 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 * @handle: Handle of registered MPT protocol driver
905 * @ioc: Pointer to MPT adapter structure
906 * @reqBytes: Size of the request in bytes
907 * @req: Pointer to MPT request frame
908 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
909 *
910 * This routine is used exclusively to send MptScsiTaskMgmt
911 * requests since they are required to be sent via doorbell handshake.
912 *
913 * NOTE: It is the callers responsibility to byte-swap fields in the
914 * request which are greater than 1 byte in size.
915 *
916 * Returns 0 for success, non-zero for failure.
917 */
918int
919mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
920{
Eric Moorecd2c6192007-01-29 09:47:47 -0700921 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 u8 *req_as_bytes;
923 int ii;
924
925 /* State is known to be good upon entering
926 * this function so issue the bus reset
927 * request.
928 */
929
930 /*
931 * Emulate what mpt_put_msg_frame() does /wrt to sanity
932 * setting cb_idx/req_idx. But ONLY if this request
933 * is in proper (pre-alloc'd) request buffer range...
934 */
935 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
936 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
937 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
938 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
939 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
940 }
941
942 /* Make sure there are no doorbells */
943 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200944
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 CHIPREG_WRITE32(&ioc->chip->Doorbell,
946 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
947 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
948
949 /* Wait for IOC doorbell int */
950 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
951 return ii;
952 }
953
954 /* Read doorbell and check for active bit */
955 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
956 return -5;
957
958 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200959 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
962
963 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
964 return -2;
965 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 /* Send request via doorbell handshake */
968 req_as_bytes = (u8 *) req;
969 for (ii = 0; ii < reqBytes/4; ii++) {
970 u32 word;
971
972 word = ((req_as_bytes[(ii*4) + 0] << 0) |
973 (req_as_bytes[(ii*4) + 1] << 8) |
974 (req_as_bytes[(ii*4) + 2] << 16) |
975 (req_as_bytes[(ii*4) + 3] << 24));
976 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
977 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
978 r = -3;
979 break;
980 }
981 }
982
983 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
984 r = 0;
985 else
986 r = -4;
987
988 /* Make sure there are no doorbells */
989 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 return r;
992}
993
994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
995/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800996 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200997 * @ioc: Pointer to MPT adapter structure
998 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800999 * @sleepFlag: Specifies whether the process can sleep
1000 *
1001 * Provides mechanism for the host driver to control the IOC's
1002 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001003 *
1004 * Access Control Value - bits[15:12]
1005 * 0h Reserved
1006 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1007 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1008 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1009 *
1010 * Returns 0 for success, non-zero for failure.
1011 */
1012
1013static int
1014mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1015{
1016 int r = 0;
1017
1018 /* return if in use */
1019 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1020 & MPI_DOORBELL_ACTIVE)
1021 return -1;
1022
1023 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1024
1025 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1026 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1027 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1028 (access_control_value<<12)));
1029
1030 /* Wait for IOC to clear Doorbell Status bit */
1031 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1032 return -2;
1033 }else
1034 return 0;
1035}
1036
1037/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1038/**
1039 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001040 * @ioc: Pointer to pointer to IOC adapter
1041 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001042 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001043 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001044 * Returns 0 for success, non-zero for failure.
1045 */
1046static int
1047mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1048{
1049 char *psge;
1050 int flags_length;
1051 u32 host_page_buffer_sz=0;
1052
1053 if(!ioc->HostPageBuffer) {
1054
1055 host_page_buffer_sz =
1056 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1057
1058 if(!host_page_buffer_sz)
1059 return 0; /* fw doesn't need any host buffers */
1060
1061 /* spin till we get enough memory */
1062 while(host_page_buffer_sz > 0) {
1063
1064 if((ioc->HostPageBuffer = pci_alloc_consistent(
1065 ioc->pcidev,
1066 host_page_buffer_sz,
1067 &ioc->HostPageBuffer_dma)) != NULL) {
1068
1069 dinitprintk((MYIOC_s_INFO_FMT
1070 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001071 ioc->name, ioc->HostPageBuffer,
1072 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001073 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001074 ioc->alloc_total += host_page_buffer_sz;
1075 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1076 break;
1077 }
1078
1079 host_page_buffer_sz -= (4*1024);
1080 }
1081 }
1082
1083 if(!ioc->HostPageBuffer) {
1084 printk(MYIOC_s_ERR_FMT
1085 "Failed to alloc memory for host_page_buffer!\n",
1086 ioc->name);
1087 return -999;
1088 }
1089
1090 psge = (char *)&ioc_init->HostPageBufferSGE;
1091 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1092 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1093 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1094 MPI_SGE_FLAGS_HOST_TO_IOC |
1095 MPI_SGE_FLAGS_END_OF_BUFFER;
1096 if (sizeof(dma_addr_t) == sizeof(u64)) {
1097 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1098 }
1099 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1100 flags_length |= ioc->HostPageBuffer_sz;
1101 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1102 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1103
1104return 0;
1105}
1106
1107/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1108/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001109 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 * @iocid: IOC unique identifier (integer)
1111 * @iocpp: Pointer to pointer to IOC adapter
1112 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001113 * Given a unique IOC identifier, set pointer to the associated MPT
1114 * adapter structure.
1115 *
1116 * Returns iocid and sets iocpp if iocid is found.
1117 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 */
1119int
1120mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1121{
1122 MPT_ADAPTER *ioc;
1123
1124 list_for_each_entry(ioc,&ioc_list,list) {
1125 if (ioc->id == iocid) {
1126 *iocpp =ioc;
1127 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 *iocpp = NULL;
1132 return -1;
1133}
1134
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301135/**
1136 * mpt_get_product_name - returns product string
1137 * @vendor: pci vendor id
1138 * @device: pci device id
1139 * @revision: pci revision id
1140 * @prod_name: string returned
1141 *
1142 * Returns product string displayed when driver loads,
1143 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1144 *
1145 **/
1146static void
1147mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1148{
1149 char *product_str = NULL;
1150
1151 if (vendor == PCI_VENDOR_ID_BROCADE) {
1152 switch (device)
1153 {
1154 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1155 switch (revision)
1156 {
1157 case 0x00:
1158 product_str = "BRE040 A0";
1159 break;
1160 case 0x01:
1161 product_str = "BRE040 A1";
1162 break;
1163 default:
1164 product_str = "BRE040";
1165 break;
1166 }
1167 break;
1168 }
1169 goto out;
1170 }
1171
1172 switch (device)
1173 {
1174 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1175 product_str = "LSIFC909 B1";
1176 break;
1177 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1178 product_str = "LSIFC919 B0";
1179 break;
1180 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1181 product_str = "LSIFC929 B0";
1182 break;
1183 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1184 if (revision < 0x80)
1185 product_str = "LSIFC919X A0";
1186 else
1187 product_str = "LSIFC919XL A1";
1188 break;
1189 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1190 if (revision < 0x80)
1191 product_str = "LSIFC929X A0";
1192 else
1193 product_str = "LSIFC929XL A1";
1194 break;
1195 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1196 product_str = "LSIFC939X A1";
1197 break;
1198 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1199 product_str = "LSIFC949X A1";
1200 break;
1201 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1202 switch (revision)
1203 {
1204 case 0x00:
1205 product_str = "LSIFC949E A0";
1206 break;
1207 case 0x01:
1208 product_str = "LSIFC949E A1";
1209 break;
1210 default:
1211 product_str = "LSIFC949E";
1212 break;
1213 }
1214 break;
1215 case MPI_MANUFACTPAGE_DEVID_53C1030:
1216 switch (revision)
1217 {
1218 case 0x00:
1219 product_str = "LSI53C1030 A0";
1220 break;
1221 case 0x01:
1222 product_str = "LSI53C1030 B0";
1223 break;
1224 case 0x03:
1225 product_str = "LSI53C1030 B1";
1226 break;
1227 case 0x07:
1228 product_str = "LSI53C1030 B2";
1229 break;
1230 case 0x08:
1231 product_str = "LSI53C1030 C0";
1232 break;
1233 case 0x80:
1234 product_str = "LSI53C1030T A0";
1235 break;
1236 case 0x83:
1237 product_str = "LSI53C1030T A2";
1238 break;
1239 case 0x87:
1240 product_str = "LSI53C1030T A3";
1241 break;
1242 case 0xc1:
1243 product_str = "LSI53C1020A A1";
1244 break;
1245 default:
1246 product_str = "LSI53C1030";
1247 break;
1248 }
1249 break;
1250 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1251 switch (revision)
1252 {
1253 case 0x03:
1254 product_str = "LSI53C1035 A2";
1255 break;
1256 case 0x04:
1257 product_str = "LSI53C1035 B0";
1258 break;
1259 default:
1260 product_str = "LSI53C1035";
1261 break;
1262 }
1263 break;
1264 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1265 switch (revision)
1266 {
1267 case 0x00:
1268 product_str = "LSISAS1064 A1";
1269 break;
1270 case 0x01:
1271 product_str = "LSISAS1064 A2";
1272 break;
1273 case 0x02:
1274 product_str = "LSISAS1064 A3";
1275 break;
1276 case 0x03:
1277 product_str = "LSISAS1064 A4";
1278 break;
1279 default:
1280 product_str = "LSISAS1064";
1281 break;
1282 }
1283 break;
1284 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1285 switch (revision)
1286 {
1287 case 0x00:
1288 product_str = "LSISAS1064E A0";
1289 break;
1290 case 0x01:
1291 product_str = "LSISAS1064E B0";
1292 break;
1293 case 0x02:
1294 product_str = "LSISAS1064E B1";
1295 break;
1296 case 0x04:
1297 product_str = "LSISAS1064E B2";
1298 break;
1299 case 0x08:
1300 product_str = "LSISAS1064E B3";
1301 break;
1302 default:
1303 product_str = "LSISAS1064E";
1304 break;
1305 }
1306 break;
1307 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1308 switch (revision)
1309 {
1310 case 0x00:
1311 product_str = "LSISAS1068 A0";
1312 break;
1313 case 0x01:
1314 product_str = "LSISAS1068 B0";
1315 break;
1316 case 0x02:
1317 product_str = "LSISAS1068 B1";
1318 break;
1319 default:
1320 product_str = "LSISAS1068";
1321 break;
1322 }
1323 break;
1324 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1325 switch (revision)
1326 {
1327 case 0x00:
1328 product_str = "LSISAS1068E A0";
1329 break;
1330 case 0x01:
1331 product_str = "LSISAS1068E B0";
1332 break;
1333 case 0x02:
1334 product_str = "LSISAS1068E B1";
1335 break;
1336 case 0x04:
1337 product_str = "LSISAS1068E B2";
1338 break;
1339 case 0x08:
1340 product_str = "LSISAS1068E B3";
1341 break;
1342 default:
1343 product_str = "LSISAS1068E";
1344 break;
1345 }
1346 break;
1347 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1348 switch (revision)
1349 {
1350 case 0x00:
1351 product_str = "LSISAS1078 A0";
1352 break;
1353 case 0x01:
1354 product_str = "LSISAS1078 B0";
1355 break;
1356 case 0x02:
1357 product_str = "LSISAS1078 C0";
1358 break;
1359 case 0x03:
1360 product_str = "LSISAS1078 C1";
1361 break;
1362 case 0x04:
1363 product_str = "LSISAS1078 C2";
1364 break;
1365 default:
1366 product_str = "LSISAS1078";
1367 break;
1368 }
1369 break;
1370 }
1371
1372 out:
1373 if (product_str)
1374 sprintf(prod_name, "%s", product_str);
1375}
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001378/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001379 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001381 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 *
1383 * This routine performs all the steps necessary to bring the IOC of
1384 * a MPT adapter to a OPERATIONAL state. This includes registering
1385 * memory regions, registering the interrupt, and allocating request
1386 * and reply memory pools.
1387 *
1388 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1389 * MPT adapter.
1390 *
1391 * Returns 0 for success, non-zero for failure.
1392 *
1393 * TODO: Add support for polled controllers
1394 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001395int
1396mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
1398 MPT_ADAPTER *ioc;
1399 u8 __iomem *mem;
1400 unsigned long mem_phys;
1401 unsigned long port;
1402 u32 msize;
1403 u32 psize;
1404 int ii;
1405 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 u8 revision;
1407 u8 pcixcmd;
1408 static int mpt_ids = 0;
1409#ifdef CONFIG_PROC_FS
1410 struct proc_dir_entry *dent, *ent;
1411#endif
1412
1413 if (pci_enable_device(pdev))
1414 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001415
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001417
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001418 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 dprintk((KERN_INFO MYNAM
1420 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001421 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1423 return r;
1424 }
1425
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001426 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 dprintk((KERN_INFO MYNAM
1428 ": Using 64 bit consistent mask\n"));
1429 else
1430 dprintk((KERN_INFO MYNAM
1431 ": Not using 64 bit consistent mask\n"));
1432
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001433 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 if (ioc == NULL) {
1435 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1436 return -ENOMEM;
1437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 ioc->alloc_total = sizeof(MPT_ADAPTER);
1439 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1440 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 ioc->pcidev = pdev;
1443 ioc->diagPending = 0;
1444 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001445 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
1447 /* Initialize the event logging.
1448 */
1449 ioc->eventTypes = 0; /* None */
1450 ioc->eventContext = 0;
1451 ioc->eventLogSize = 0;
1452 ioc->events = NULL;
1453
1454#ifdef MFCNT
1455 ioc->mfcnt = 0;
1456#endif
1457
1458 ioc->cached_fw = NULL;
1459
1460 /* Initilize SCSI Config Data structure
1461 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001462 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
1464 /* Initialize the running configQ head.
1465 */
1466 INIT_LIST_HEAD(&ioc->configQ);
1467
Michael Reed05e8ec12006-01-13 14:31:54 -06001468 /* Initialize the fc rport list head.
1469 */
1470 INIT_LIST_HEAD(&ioc->fc_rports);
1471
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 /* Find lookup slot. */
1473 INIT_LIST_HEAD(&ioc->list);
1474 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001475
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 mem_phys = msize = 0;
1477 port = psize = 0;
1478 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1479 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001480 if (psize)
1481 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 /* Get I/O space! */
1483 port = pci_resource_start(pdev, ii);
1484 psize = pci_resource_len(pdev,ii);
1485 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001486 if (msize)
1487 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 /* Get memmap */
1489 mem_phys = pci_resource_start(pdev, ii);
1490 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 }
1492 }
1493 ioc->mem_size = msize;
1494
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 mem = NULL;
1496 /* Get logical ptr for PciMem0 space */
1497 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001498 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 if (mem == NULL) {
1500 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1501 kfree(ioc);
1502 return -EINVAL;
1503 }
1504 ioc->memmap = mem;
1505 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1506
1507 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1508 &ioc->facts, &ioc->pfacts[0]));
1509
1510 ioc->mem_phys = mem_phys;
1511 ioc->chip = (SYSIF_REGS __iomem *)mem;
1512
1513 /* Save Port IO values in case we need to do downloadboot */
1514 {
1515 u8 *pmem = (u8*)port;
1516 ioc->pio_mem_phys = port;
1517 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1518 }
1519
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301520 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1521 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1522
1523 switch (pdev->device)
1524 {
1525 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1526 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1527 ioc->errata_flag_1064 = 1;
1528 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1529 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1530 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1531 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301533 break;
1534
1535 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 /* 929X Chip Fix. Set Split transactions level
1538 * for PCIX. Set MOST bits to zero.
1539 */
1540 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1541 pcixcmd &= 0x8F;
1542 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1543 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 /* 929XL Chip Fix. Set MMRBC to 0x08.
1545 */
1546 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1547 pcixcmd |= 0x08;
1548 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301551 break;
1552
1553 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 /* 919X Chip Fix. Set Split transactions level
1555 * for PCIX. Set MOST bits to zero.
1556 */
1557 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1558 pcixcmd &= 0x8F;
1559 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001560 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301561 break;
1562
1563 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 /* 1030 Chip Fix. Disable Split transactions
1565 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1566 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 if (revision < C0_1030) {
1568 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1569 pcixcmd &= 0x8F;
1570 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1571 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301572
1573 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001574 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301575 break;
1576
1577 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1578 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001579 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301580
1581 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1582 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1583 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001584 ioc->bus_type = SAS;
1585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001587 if (ioc->errata_flag_1064)
1588 pci_disable_io_access(pdev);
1589
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 sprintf(ioc->name, "ioc%d", ioc->id);
1591
1592 spin_lock_init(&ioc->FreeQlock);
1593
1594 /* Disable all! */
1595 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1596 ioc->active = 0;
1597 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1598
1599 /* Set lookup ptr. */
1600 list_add_tail(&ioc->list, &ioc_list);
1601
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001602 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 */
1604 mpt_detect_bound_ports(ioc, pdev);
1605
James Bottomleyc92f2222006-03-01 09:02:49 -06001606 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1607 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 printk(KERN_WARNING MYNAM
1609 ": WARNING - %s did not initialize properly! (%d)\n",
1610 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001613 if (ioc->alt_ioc)
1614 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 iounmap(mem);
1616 kfree(ioc);
1617 pci_set_drvdata(pdev, NULL);
1618 return r;
1619 }
1620
1621 /* call per device driver probe entry point */
1622 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1623 if(MptDeviceDriverHandlers[ii] &&
1624 MptDeviceDriverHandlers[ii]->probe) {
1625 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1626 }
1627 }
1628
1629#ifdef CONFIG_PROC_FS
1630 /*
1631 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1632 */
1633 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1634 if (dent) {
1635 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1636 if (ent) {
1637 ent->read_proc = procmpt_iocinfo_read;
1638 ent->data = ioc;
1639 }
1640 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1641 if (ent) {
1642 ent->read_proc = procmpt_summary_read;
1643 ent->data = ioc;
1644 }
1645 }
1646#endif
1647
1648 return 0;
1649}
1650
1651/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001652/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001653 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 */
1656
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001657void
1658mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659{
1660 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1661 char pname[32];
1662 int ii;
1663
1664 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1665 remove_proc_entry(pname, NULL);
1666 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1667 remove_proc_entry(pname, NULL);
1668 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1669 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001670
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 /* call per device driver remove entry point */
1672 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1673 if(MptDeviceDriverHandlers[ii] &&
1674 MptDeviceDriverHandlers[ii]->remove) {
1675 MptDeviceDriverHandlers[ii]->remove(pdev);
1676 }
1677 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 /* Disable interrupts! */
1680 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1681
1682 ioc->active = 0;
1683 synchronize_irq(pdev->irq);
1684
1685 /* Clear any lingering interrupt */
1686 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1687
1688 CHIPREG_READ32(&ioc->chip->IntStatus);
1689
1690 mpt_adapter_dispose(ioc);
1691
1692 pci_set_drvdata(pdev, NULL);
1693}
1694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695/**************************************************************************
1696 * Power Management
1697 */
1698#ifdef CONFIG_PM
1699/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001700/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001701 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001702 * @pdev: Pointer to pci_dev structure
1703 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001705int
1706mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707{
1708 u32 device_state;
1709 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
Pavel Machek2a569572005-07-07 17:56:40 -07001711 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
1713 printk(MYIOC_s_INFO_FMT
1714 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1715 ioc->name, pdev, pci_name(pdev), device_state);
1716
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 pci_save_state(pdev);
1718
1719 /* put ioc into READY_STATE */
1720 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1721 printk(MYIOC_s_ERR_FMT
1722 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1723 }
1724
1725 /* disable interrupts */
1726 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1727 ioc->active = 0;
1728
1729 /* Clear any lingering interrupt */
1730 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1731
1732 pci_disable_device(pdev);
1733 pci_set_power_state(pdev, device_state);
1734
1735 return 0;
1736}
1737
1738/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001739/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001740 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001741 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001743int
1744mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745{
1746 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1747 u32 device_state = pdev->current_state;
1748 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001749 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 printk(MYIOC_s_INFO_FMT
1752 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1753 ioc->name, pdev, pci_name(pdev), device_state);
1754
1755 pci_set_power_state(pdev, 0);
1756 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001757 err = pci_enable_device(pdev);
1758 if (err)
1759 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
1761 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001762 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 ioc->active = 1;
1764
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 printk(MYIOC_s_INFO_FMT
1766 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1767 ioc->name,
1768 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1769 CHIPREG_READ32(&ioc->chip->Doorbell));
1770
1771 /* bring ioc to operational state */
1772 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1773 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1774 printk(MYIOC_s_INFO_FMT
1775 "pci-resume: Cannot recover, error:[%x]\n",
1776 ioc->name, recovery_state);
1777 } else {
1778 printk(MYIOC_s_INFO_FMT
1779 "pci-resume: success\n", ioc->name);
1780 }
1781
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 return 0;
1783}
1784#endif
1785
James Bottomley4ff42a62006-05-17 18:06:52 -05001786static int
1787mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1788{
1789 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1790 ioc->bus_type != SPI) ||
1791 (MptDriverClass[index] == MPTFC_DRIVER &&
1792 ioc->bus_type != FC) ||
1793 (MptDriverClass[index] == MPTSAS_DRIVER &&
1794 ioc->bus_type != SAS))
1795 /* make sure we only call the relevant reset handler
1796 * for the bus */
1797 return 0;
1798 return (MptResetHandlers[index])(ioc, reset_phase);
1799}
1800
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001802/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1804 * @ioc: Pointer to MPT adapter structure
1805 * @reason: Event word / reason
1806 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1807 *
1808 * This routine performs all the steps necessary to bring the IOC
1809 * to a OPERATIONAL state.
1810 *
1811 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1812 * MPT adapter.
1813 *
1814 * Returns:
1815 * 0 for success
1816 * -1 if failed to get board READY
1817 * -2 if READY but IOCFacts Failed
1818 * -3 if READY but PrimeIOCFifos Failed
1819 * -4 if READY but IOCInit Failed
1820 */
1821static int
1822mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1823{
1824 int hard_reset_done = 0;
1825 int alt_ioc_ready = 0;
1826 int hard;
1827 int rc=0;
1828 int ii;
1829 int handlers;
1830 int ret = 0;
1831 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001832 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
1834 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1835 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1836
1837 /* Disable reply interrupts (also blocks FreeQ) */
1838 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1839 ioc->active = 0;
1840
1841 if (ioc->alt_ioc) {
1842 if (ioc->alt_ioc->active)
1843 reset_alt_ioc_active = 1;
1844
1845 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1846 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1847 ioc->alt_ioc->active = 0;
1848 }
1849
1850 hard = 1;
1851 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1852 hard = 0;
1853
1854 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1855 if (hard_reset_done == -4) {
1856 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1857 ioc->name);
1858
1859 if (reset_alt_ioc_active && ioc->alt_ioc) {
1860 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1861 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1862 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001863 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 ioc->alt_ioc->active = 1;
1865 }
1866
1867 } else {
1868 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1869 ioc->name);
1870 }
1871 return -1;
1872 }
1873
1874 /* hard_reset_done = 0 if a soft reset was performed
1875 * and 1 if a hard reset was performed.
1876 */
1877 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1878 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1879 alt_ioc_ready = 1;
1880 else
1881 printk(KERN_WARNING MYNAM
1882 ": alt-%s: Not ready WARNING!\n",
1883 ioc->alt_ioc->name);
1884 }
1885
1886 for (ii=0; ii<5; ii++) {
1887 /* Get IOC facts! Allow 5 retries */
1888 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1889 break;
1890 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001891
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892
1893 if (ii == 5) {
1894 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1895 ret = -2;
1896 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1897 MptDisplayIocCapabilities(ioc);
1898 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001899
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 if (alt_ioc_ready) {
1901 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1902 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1903 /* Retry - alt IOC was initialized once
1904 */
1905 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1906 }
1907 if (rc) {
1908 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1909 alt_ioc_ready = 0;
1910 reset_alt_ioc_active = 0;
1911 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1912 MptDisplayIocCapabilities(ioc->alt_ioc);
1913 }
1914 }
1915
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001916 /*
1917 * Device is reset now. It must have de-asserted the interrupt line
1918 * (if it was asserted) and it should be safe to register for the
1919 * interrupt now.
1920 */
1921 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1922 ioc->pci_irq = -1;
1923 if (ioc->pcidev->irq) {
1924 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1925 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1926 ioc->name);
1927 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001928 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001929 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001930 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1931 "interrupt %d!\n", ioc->name,
1932 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001933 if (mpt_msi_enable)
1934 pci_disable_msi(ioc->pcidev);
1935 return -EBUSY;
1936 }
1937 irq_allocated = 1;
1938 ioc->pci_irq = ioc->pcidev->irq;
1939 pci_set_master(ioc->pcidev); /* ?? */
1940 pci_set_drvdata(ioc->pcidev, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001941 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1942 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001943 }
1944 }
1945
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 /* Prime reply & request queues!
1947 * (mucho alloc's) Must be done prior to
1948 * init as upper addresses are needed for init.
1949 * If fails, continue with alt-ioc processing
1950 */
1951 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1952 ret = -3;
1953
1954 /* May need to check/upload firmware & data here!
1955 * If fails, continue with alt-ioc processing
1956 */
1957 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1958 ret = -4;
1959// NEW!
1960 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1961 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1962 ioc->alt_ioc->name, rc);
1963 alt_ioc_ready = 0;
1964 reset_alt_ioc_active = 0;
1965 }
1966
1967 if (alt_ioc_ready) {
1968 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1969 alt_ioc_ready = 0;
1970 reset_alt_ioc_active = 0;
1971 printk(KERN_WARNING MYNAM
1972 ": alt-%s: (%d) init failure WARNING!\n",
1973 ioc->alt_ioc->name, rc);
1974 }
1975 }
1976
1977 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1978 if (ioc->upload_fw) {
1979 ddlprintk((MYIOC_s_INFO_FMT
1980 "firmware upload required!\n", ioc->name));
1981
1982 /* Controller is not operational, cannot do upload
1983 */
1984 if (ret == 0) {
1985 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001986 if (rc == 0) {
1987 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1988 /*
1989 * Maintain only one pointer to FW memory
1990 * so there will not be two attempt to
1991 * downloadboot onboard dual function
1992 * chips (mpt_adapter_disable,
1993 * mpt_diag_reset)
1994 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001995 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1996 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06001997 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001998 }
1999 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002001 ret = -5;
2002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 }
2004 }
2005 }
2006
2007 if (ret == 0) {
2008 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002009 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 ioc->active = 1;
2011 }
2012
2013 if (reset_alt_ioc_active && ioc->alt_ioc) {
2014 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002015 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002017 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 ioc->alt_ioc->active = 1;
2019 }
2020
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002021 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 * and EventAck handling.
2023 */
2024 if ((ret == 0) && (!ioc->facts.EventState))
2025 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2026
2027 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2028 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2029
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002030 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2032 * recursive scenario; GetLanConfigPages times out, timer expired
2033 * routine calls HardResetHandler, which calls into here again,
2034 * and we try GetLanConfigPages again...
2035 */
2036 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002037
2038 /*
2039 * Initalize link list for inactive raid volumes.
2040 */
2041 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2042 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2043
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002044 if (ioc->bus_type == SAS) {
2045
2046 /* clear persistency table */
2047 if(ioc->facts.IOCExceptions &
2048 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2049 ret = mptbase_sas_persist_operation(ioc,
2050 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2051 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002052 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002053 }
2054
2055 /* Find IM volumes
2056 */
2057 mpt_findImVolumes(ioc);
2058
2059 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2061 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2062 /*
2063 * Pre-fetch the ports LAN MAC address!
2064 * (LANPage1_t stuff)
2065 */
2066 (void) GetLanConfigPages(ioc);
2067#ifdef MPT_DEBUG
2068 {
2069 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2070 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2071 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
2072 }
2073#endif
2074 }
2075 } else {
2076 /* Get NVRAM and adapter maximums from SPP 0 and 2
2077 */
2078 mpt_GetScsiPortSettings(ioc, 0);
2079
2080 /* Get version and length of SDP 1
2081 */
2082 mpt_readScsiDevicePageHeaders(ioc, 0);
2083
2084 /* Find IM volumes
2085 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002086 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 mpt_findImVolumes(ioc);
2088
2089 /* Check, and possibly reset, the coalescing value
2090 */
2091 mpt_read_ioc_pg_1(ioc);
2092
2093 mpt_read_ioc_pg_4(ioc);
2094 }
2095
2096 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302097 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 }
2099
2100 /*
2101 * Call each currently registered protocol IOC reset handler
2102 * with post-reset indication.
2103 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2104 * MptResetHandlers[] registered yet.
2105 */
2106 if (hard_reset_done) {
2107 rc = handlers = 0;
2108 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
2109 if ((ret == 0) && MptResetHandlers[ii]) {
2110 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
2111 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05002112 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 handlers++;
2114 }
2115
2116 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002117 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05002119 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 handlers++;
2121 }
2122 }
2123 /* FIXME? Examine results here? */
2124 }
2125
Eric Moore0ccdb002006-07-11 17:33:13 -06002126 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002127 if ((ret != 0) && irq_allocated) {
2128 free_irq(ioc->pci_irq, ioc);
2129 if (mpt_msi_enable)
2130 pci_disable_msi(ioc->pcidev);
2131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 return ret;
2133}
2134
2135/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002136/**
2137 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 * @ioc: Pointer to MPT adapter structure
2139 * @pdev: Pointer to (struct pci_dev) structure
2140 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002141 * Search for PCI bus/dev_function which matches
2142 * PCI bus/dev_function (+/-1) for newly discovered 929,
2143 * 929X, 1030 or 1035.
2144 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2146 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2147 */
2148static void
2149mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2150{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002151 struct pci_dev *peer=NULL;
2152 unsigned int slot = PCI_SLOT(pdev->devfn);
2153 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 MPT_ADAPTER *ioc_srch;
2155
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002156 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
2157 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002158 ioc->name, pci_name(pdev), pdev->bus->number,
2159 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002160
2161 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2162 if (!peer) {
2163 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2164 if (!peer)
2165 return;
2166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167
2168 list_for_each_entry(ioc_srch, &ioc_list, list) {
2169 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002170 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 /* Paranoia checks */
2172 if (ioc->alt_ioc != NULL) {
2173 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002174 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 break;
2176 } else if (ioc_srch->alt_ioc != NULL) {
2177 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002178 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 break;
2180 }
2181 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002182 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 ioc_srch->alt_ioc = ioc;
2184 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 }
2186 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002187 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188}
2189
2190/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002191/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002193 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 */
2195static void
2196mpt_adapter_disable(MPT_ADAPTER *ioc)
2197{
2198 int sz;
2199 int ret;
2200
2201 if (ioc->cached_fw != NULL) {
2202 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002203 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 printk(KERN_WARNING MYNAM
2205 ": firmware downloadboot failure (%d)!\n", ret);
2206 }
2207 }
2208
2209 /* Disable adapter interrupts! */
2210 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2211 ioc->active = 0;
2212 /* Clear any lingering interrupt */
2213 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2214
2215 if (ioc->alloc != NULL) {
2216 sz = ioc->alloc_sz;
2217 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
2218 ioc->name, ioc->alloc, ioc->alloc_sz));
2219 pci_free_consistent(ioc->pcidev, sz,
2220 ioc->alloc, ioc->alloc_dma);
2221 ioc->reply_frames = NULL;
2222 ioc->req_frames = NULL;
2223 ioc->alloc = NULL;
2224 ioc->alloc_total -= sz;
2225 }
2226
2227 if (ioc->sense_buf_pool != NULL) {
2228 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2229 pci_free_consistent(ioc->pcidev, sz,
2230 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2231 ioc->sense_buf_pool = NULL;
2232 ioc->alloc_total -= sz;
2233 }
2234
2235 if (ioc->events != NULL){
2236 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2237 kfree(ioc->events);
2238 ioc->events = NULL;
2239 ioc->alloc_total -= sz;
2240 }
2241
2242 if (ioc->cached_fw != NULL) {
2243 sz = ioc->facts.FWImageSize;
2244 pci_free_consistent(ioc->pcidev, sz,
2245 ioc->cached_fw, ioc->cached_fw_dma);
2246 ioc->cached_fw = NULL;
2247 ioc->alloc_total -= sz;
2248 }
2249
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002250 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002251 mpt_inactive_raid_list_free(ioc);
2252 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002253 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002254 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002255 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
2257 if (ioc->spi_data.pIocPg4 != NULL) {
2258 sz = ioc->spi_data.IocPg4Sz;
2259 pci_free_consistent(ioc->pcidev, sz,
2260 ioc->spi_data.pIocPg4,
2261 ioc->spi_data.IocPg4_dma);
2262 ioc->spi_data.pIocPg4 = NULL;
2263 ioc->alloc_total -= sz;
2264 }
2265
2266 if (ioc->ReqToChain != NULL) {
2267 kfree(ioc->ReqToChain);
2268 kfree(ioc->RequestNB);
2269 ioc->ReqToChain = NULL;
2270 }
2271
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002272 kfree(ioc->ChainToChain);
2273 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002274
2275 if (ioc->HostPageBuffer != NULL) {
2276 if((ret = mpt_host_page_access_control(ioc,
2277 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2278 printk(KERN_ERR MYNAM
2279 ": %s: host page buffers free failed (%d)!\n",
2280 __FUNCTION__, ret);
2281 }
2282 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2283 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2284 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2285 ioc->HostPageBuffer,
2286 ioc->HostPageBuffer_dma);
2287 ioc->HostPageBuffer = NULL;
2288 ioc->HostPageBuffer_sz = 0;
2289 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291}
2292
2293/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002294/**
2295 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 * @ioc: Pointer to MPT adapter structure
2297 *
2298 * This routine unregisters h/w resources and frees all alloc'd memory
2299 * associated with a MPT adapter structure.
2300 */
2301static void
2302mpt_adapter_dispose(MPT_ADAPTER *ioc)
2303{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002304 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002306 if (ioc == NULL)
2307 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002309 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002311 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002313 if (ioc->pci_irq != -1) {
2314 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002315 if (mpt_msi_enable)
2316 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002317 ioc->pci_irq = -1;
2318 }
2319
2320 if (ioc->memmap != NULL) {
2321 iounmap(ioc->memmap);
2322 ioc->memmap = NULL;
2323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
2325#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002326 if (ioc->mtrr_reg > 0) {
2327 mtrr_del(ioc->mtrr_reg, 0, 0);
2328 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330#endif
2331
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002332 /* Zap the adapter lookup ptr! */
2333 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002335 sz_last = ioc->alloc_total;
2336 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2337 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002338
2339 if (ioc->alt_ioc)
2340 ioc->alt_ioc->alt_ioc = NULL;
2341
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002342 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343}
2344
2345/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002346/**
2347 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 * @ioc: Pointer to MPT adapter structure
2349 */
2350static void
2351MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2352{
2353 int i = 0;
2354
2355 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302356 if (ioc->prod_name)
2357 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 printk("Capabilities={");
2359
2360 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2361 printk("Initiator");
2362 i++;
2363 }
2364
2365 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2366 printk("%sTarget", i ? "," : "");
2367 i++;
2368 }
2369
2370 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2371 printk("%sLAN", i ? "," : "");
2372 i++;
2373 }
2374
2375#if 0
2376 /*
2377 * This would probably evoke more questions than it's worth
2378 */
2379 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2380 printk("%sLogBusAddr", i ? "," : "");
2381 i++;
2382 }
2383#endif
2384
2385 printk("}\n");
2386}
2387
2388/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002389/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2391 * @ioc: Pointer to MPT_ADAPTER structure
2392 * @force: Force hard KickStart of IOC
2393 * @sleepFlag: Specifies whether the process can sleep
2394 *
2395 * Returns:
2396 * 1 - DIAG reset and READY
2397 * 0 - READY initially OR soft reset and READY
2398 * -1 - Any failure on KickStart
2399 * -2 - Msg Unit Reset Failed
2400 * -3 - IO Unit Reset Failed
2401 * -4 - IOC owned by a PEER
2402 */
2403static int
2404MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2405{
2406 u32 ioc_state;
2407 int statefault = 0;
2408 int cntdn;
2409 int hard_reset_done = 0;
2410 int r;
2411 int ii;
2412 int whoinit;
2413
2414 /* Get current [raw] IOC state */
2415 ioc_state = mpt_GetIocState(ioc, 0);
2416 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2417
2418 /*
2419 * Check to see if IOC got left/stuck in doorbell handshake
2420 * grip of death. If so, hard reset the IOC.
2421 */
2422 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2423 statefault = 1;
2424 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2425 ioc->name);
2426 }
2427
2428 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002429 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 return 0;
2431
2432 /*
2433 * Check to see if IOC is in FAULT state.
2434 */
2435 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2436 statefault = 2;
2437 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2438 ioc->name);
2439 printk(KERN_WARNING " FAULT code = %04xh\n",
2440 ioc_state & MPI_DOORBELL_DATA_MASK);
2441 }
2442
2443 /*
2444 * Hmmm... Did it get left operational?
2445 */
2446 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002447 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 ioc->name));
2449
2450 /* Check WhoInit.
2451 * If PCI Peer, exit.
2452 * Else, if no fault conditions are present, issue a MessageUnitReset
2453 * Else, fall through to KickStart case
2454 */
2455 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002456 dinitprintk((KERN_INFO MYNAM
2457 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 whoinit, statefault, force));
2459 if (whoinit == MPI_WHOINIT_PCI_PEER)
2460 return -4;
2461 else {
2462 if ((statefault == 0 ) && (force == 0)) {
2463 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2464 return 0;
2465 }
2466 statefault = 3;
2467 }
2468 }
2469
2470 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2471 if (hard_reset_done < 0)
2472 return -1;
2473
2474 /*
2475 * Loop here waiting for IOC to come READY.
2476 */
2477 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002478 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2481 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2482 /*
2483 * BIOS or previous driver load left IOC in OP state.
2484 * Reset messaging FIFOs.
2485 */
2486 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2487 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2488 return -2;
2489 }
2490 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2491 /*
2492 * Something is wrong. Try to get IOC back
2493 * to a known state.
2494 */
2495 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2496 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2497 return -3;
2498 }
2499 }
2500
2501 ii++; cntdn--;
2502 if (!cntdn) {
2503 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2504 ioc->name, (int)((ii+5)/HZ));
2505 return -ETIME;
2506 }
2507
2508 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002509 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 } else {
2511 mdelay (1); /* 1 msec delay */
2512 }
2513
2514 }
2515
2516 if (statefault < 3) {
2517 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2518 ioc->name,
2519 statefault==1 ? "stuck handshake" : "IOC FAULT");
2520 }
2521
2522 return hard_reset_done;
2523}
2524
2525/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002526/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 * mpt_GetIocState - Get the current state of a MPT adapter.
2528 * @ioc: Pointer to MPT_ADAPTER structure
2529 * @cooked: Request raw or cooked IOC state
2530 *
2531 * Returns all IOC Doorbell register bits if cooked==0, else just the
2532 * Doorbell bits in MPI_IOC_STATE_MASK.
2533 */
2534u32
2535mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2536{
2537 u32 s, sc;
2538
2539 /* Get! */
2540 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2541// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2542 sc = s & MPI_IOC_STATE_MASK;
2543
2544 /* Save! */
2545 ioc->last_state = sc;
2546
2547 return cooked ? sc : s;
2548}
2549
2550/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002551/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 * GetIocFacts - Send IOCFacts request to MPT adapter.
2553 * @ioc: Pointer to MPT_ADAPTER structure
2554 * @sleepFlag: Specifies whether the process can sleep
2555 * @reason: If recovery, only update facts.
2556 *
2557 * Returns 0 for success, non-zero for failure.
2558 */
2559static int
2560GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2561{
2562 IOCFacts_t get_facts;
2563 IOCFactsReply_t *facts;
2564 int r;
2565 int req_sz;
2566 int reply_sz;
2567 int sz;
2568 u32 status, vv;
2569 u8 shiftFactor=1;
2570
2571 /* IOC *must* NOT be in RESET state! */
2572 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2573 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2574 ioc->name,
2575 ioc->last_state );
2576 return -44;
2577 }
2578
2579 facts = &ioc->facts;
2580
2581 /* Destination (reply area)... */
2582 reply_sz = sizeof(*facts);
2583 memset(facts, 0, reply_sz);
2584
2585 /* Request area (get_facts on the stack right now!) */
2586 req_sz = sizeof(get_facts);
2587 memset(&get_facts, 0, req_sz);
2588
2589 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2590 /* Assert: All other get_facts fields are zero! */
2591
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002592 dinitprintk((MYIOC_s_INFO_FMT
2593 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 ioc->name, req_sz, reply_sz));
2595
2596 /* No non-zero fields in the get_facts request are greater than
2597 * 1 byte in size, so we can just fire it off as is.
2598 */
2599 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2600 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2601 if (r != 0)
2602 return r;
2603
2604 /*
2605 * Now byte swap (GRRR) the necessary fields before any further
2606 * inspection of reply contents.
2607 *
2608 * But need to do some sanity checks on MsgLength (byte) field
2609 * to make sure we don't zero IOC's req_sz!
2610 */
2611 /* Did we get a valid reply? */
2612 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2613 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2614 /*
2615 * If not been here, done that, save off first WhoInit value
2616 */
2617 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2618 ioc->FirstWhoInit = facts->WhoInit;
2619 }
2620
2621 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2622 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2623 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2624 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2625 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002626 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 /* CHECKME! IOCStatus, IOCLogInfo */
2628
2629 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2630 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2631
2632 /*
2633 * FC f/w version changed between 1.1 and 1.2
2634 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2635 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2636 */
2637 if (facts->MsgVersion < 0x0102) {
2638 /*
2639 * Handle old FC f/w style, convert to new...
2640 */
2641 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2642 facts->FWVersion.Word =
2643 ((oldv<<12) & 0xFF000000) |
2644 ((oldv<<8) & 0x000FFF00);
2645 } else
2646 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2647
2648 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002649 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2650 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2651 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 facts->CurrentHostMfaHighAddr =
2653 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2654 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2655 facts->CurrentSenseBufferHighAddr =
2656 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2657 facts->CurReplyFrameSize =
2658 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002659 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
2661 /*
2662 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2663 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2664 * to 14 in MPI-1.01.0x.
2665 */
2666 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2667 facts->MsgVersion > 0x0100) {
2668 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2669 }
2670
2671 sz = facts->FWImageSize;
2672 if ( sz & 0x01 )
2673 sz += 1;
2674 if ( sz & 0x02 )
2675 sz += 2;
2676 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002677
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 if (!facts->RequestFrameSize) {
2679 /* Something is wrong! */
2680 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2681 ioc->name);
2682 return -55;
2683 }
2684
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002685 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 vv = ((63 / (sz * 4)) + 1) & 0x03;
2687 ioc->NB_for_64_byte_frame = vv;
2688 while ( sz )
2689 {
2690 shiftFactor++;
2691 sz = sz >> 1;
2692 }
2693 ioc->NBShiftFactor = shiftFactor;
2694 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2695 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002696
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2698 /*
2699 * Set values for this IOC's request & reply frame sizes,
2700 * and request & reply queue depths...
2701 */
2702 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2703 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2704 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2705 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2706
2707 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2708 ioc->name, ioc->reply_sz, ioc->reply_depth));
2709 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2710 ioc->name, ioc->req_sz, ioc->req_depth));
2711
2712 /* Get port facts! */
2713 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2714 return r;
2715 }
2716 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002717 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2719 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2720 RequestFrameSize)/sizeof(u32)));
2721 return -66;
2722 }
2723
2724 return 0;
2725}
2726
2727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002728/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 * GetPortFacts - Send PortFacts request to MPT adapter.
2730 * @ioc: Pointer to MPT_ADAPTER structure
2731 * @portnum: Port number
2732 * @sleepFlag: Specifies whether the process can sleep
2733 *
2734 * Returns 0 for success, non-zero for failure.
2735 */
2736static int
2737GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2738{
2739 PortFacts_t get_pfacts;
2740 PortFactsReply_t *pfacts;
2741 int ii;
2742 int req_sz;
2743 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002744 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
2746 /* IOC *must* NOT be in RESET state! */
2747 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2748 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2749 ioc->name,
2750 ioc->last_state );
2751 return -4;
2752 }
2753
2754 pfacts = &ioc->pfacts[portnum];
2755
2756 /* Destination (reply area)... */
2757 reply_sz = sizeof(*pfacts);
2758 memset(pfacts, 0, reply_sz);
2759
2760 /* Request area (get_pfacts on the stack right now!) */
2761 req_sz = sizeof(get_pfacts);
2762 memset(&get_pfacts, 0, req_sz);
2763
2764 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2765 get_pfacts.PortNumber = portnum;
2766 /* Assert: All other get_pfacts fields are zero! */
2767
2768 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2769 ioc->name, portnum));
2770
2771 /* No non-zero fields in the get_pfacts request are greater than
2772 * 1 byte in size, so we can just fire it off as is.
2773 */
2774 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2775 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2776 if (ii != 0)
2777 return ii;
2778
2779 /* Did we get a valid reply? */
2780
2781 /* Now byte swap the necessary fields in the response. */
2782 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2783 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2784 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2785 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2786 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2787 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2788 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2789 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2790 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2791
Eric Moore793955f2007-01-29 09:42:20 -07002792 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2793 pfacts->MaxDevices;
2794 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2795 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2796
2797 /*
2798 * Place all the devices on channels
2799 *
2800 * (for debuging)
2801 */
2802 if (mpt_channel_mapping) {
2803 ioc->devices_per_bus = 1;
2804 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2805 }
2806
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 return 0;
2808}
2809
2810/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002811/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 * SendIocInit - Send IOCInit request to MPT adapter.
2813 * @ioc: Pointer to MPT_ADAPTER structure
2814 * @sleepFlag: Specifies whether the process can sleep
2815 *
2816 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2817 *
2818 * Returns 0 for success, non-zero for failure.
2819 */
2820static int
2821SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2822{
2823 IOCInit_t ioc_init;
2824 MPIDefaultReply_t init_reply;
2825 u32 state;
2826 int r;
2827 int count;
2828 int cntdn;
2829
2830 memset(&ioc_init, 0, sizeof(ioc_init));
2831 memset(&init_reply, 0, sizeof(init_reply));
2832
2833 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2834 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2835
2836 /* If we are in a recovery mode and we uploaded the FW image,
2837 * then this pointer is not NULL. Skip the upload a second time.
2838 * Set this flag if cached_fw set for either IOC.
2839 */
2840 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2841 ioc->upload_fw = 1;
2842 else
2843 ioc->upload_fw = 0;
2844 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2845 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2846
Eric Moore793955f2007-01-29 09:42:20 -07002847 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2848 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002849 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2850 ioc->name, ioc->facts.MsgVersion));
2851 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2852 // set MsgVersion and HeaderVersion host driver was built with
2853 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2854 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002856 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2857 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2858 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2859 return -99;
2860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2862
2863 if (sizeof(dma_addr_t) == sizeof(u64)) {
2864 /* Save the upper 32-bits of the request
2865 * (reply) and sense buffers.
2866 */
2867 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2868 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2869 } else {
2870 /* Force 32-bit addressing */
2871 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2872 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2873 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002874
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2876 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002877 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2878 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879
2880 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2881 ioc->name, &ioc_init));
2882
2883 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2884 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002885 if (r != 0) {
2886 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889
2890 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002891 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 */
2893
2894 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2895 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002896
2897 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2898 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
2902 /* YIKES! SUPER IMPORTANT!!!
2903 * Poll IocState until _OPERATIONAL while IOC is doing
2904 * LoopInit and TargetDiscovery!
2905 */
2906 count = 0;
2907 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2908 state = mpt_GetIocState(ioc, 1);
2909 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2910 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002911 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 } else {
2913 mdelay(1);
2914 }
2915
2916 if (!cntdn) {
2917 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2918 ioc->name, (int)((count+5)/HZ));
2919 return -9;
2920 }
2921
2922 state = mpt_GetIocState(ioc, 1);
2923 count++;
2924 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002925 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 ioc->name, count));
2927
Eric Mooreba856d32006-07-11 17:34:01 -06002928 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 return r;
2930}
2931
2932/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002933/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 * SendPortEnable - Send PortEnable request to MPT adapter port.
2935 * @ioc: Pointer to MPT_ADAPTER structure
2936 * @portnum: Port number to enable
2937 * @sleepFlag: Specifies whether the process can sleep
2938 *
2939 * Send PortEnable to bring IOC to OPERATIONAL state.
2940 *
2941 * Returns 0 for success, non-zero for failure.
2942 */
2943static int
2944SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2945{
2946 PortEnable_t port_enable;
2947 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002948 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 int req_sz;
2950 int reply_sz;
2951
2952 /* Destination... */
2953 reply_sz = sizeof(MPIDefaultReply_t);
2954 memset(&reply_buf, 0, reply_sz);
2955
2956 req_sz = sizeof(PortEnable_t);
2957 memset(&port_enable, 0, req_sz);
2958
2959 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2960 port_enable.PortNumber = portnum;
2961/* port_enable.ChainOffset = 0; */
2962/* port_enable.MsgFlags = 0; */
2963/* port_enable.MsgContext = 0; */
2964
2965 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2966 ioc->name, portnum, &port_enable));
2967
2968 /* RAID FW may take a long time to enable
2969 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002970 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07002971 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2972 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2973 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002974 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002975 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2976 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2977 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002979 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980}
2981
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002982/**
2983 * mpt_alloc_fw_memory - allocate firmware memory
2984 * @ioc: Pointer to MPT_ADAPTER structure
2985 * @size: total FW bytes
2986 *
2987 * If memory has already been allocated, the same (cached) value
2988 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 */
2990void
2991mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2992{
2993 if (ioc->cached_fw)
2994 return; /* use already allocated memory */
2995 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2996 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2997 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06002998 ioc->alloc_total += size;
2999 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 } else {
3001 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
3002 ioc->alloc_total += size;
3003 }
3004}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003005/**
3006 * mpt_free_fw_memory - free firmware memory
3007 * @ioc: Pointer to MPT_ADAPTER structure
3008 *
3009 * If alt_img is NULL, delete from ioc structure.
3010 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 */
3012void
3013mpt_free_fw_memory(MPT_ADAPTER *ioc)
3014{
3015 int sz;
3016
3017 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003018 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
3020 pci_free_consistent(ioc->pcidev, sz,
3021 ioc->cached_fw, ioc->cached_fw_dma);
3022 ioc->cached_fw = NULL;
3023
3024 return;
3025}
3026
3027
3028/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003029/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3031 * @ioc: Pointer to MPT_ADAPTER structure
3032 * @sleepFlag: Specifies whether the process can sleep
3033 *
3034 * Returns 0 for success, >0 for handshake failure
3035 * <0 for fw upload failure.
3036 *
3037 * Remark: If bound IOC and a successful FWUpload was performed
3038 * on the bound IOC, the second image is discarded
3039 * and memory is free'd. Both channels must upload to prevent
3040 * IOC from running in degraded mode.
3041 */
3042static int
3043mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3044{
3045 u8 request[ioc->req_sz];
3046 u8 reply[sizeof(FWUploadReply_t)];
3047 FWUpload_t *prequest;
3048 FWUploadReply_t *preply;
3049 FWUploadTCSGE_t *ptcsge;
3050 int sgeoffset;
3051 u32 flagsLength;
3052 int ii, sz, reply_sz;
3053 int cmdStatus;
3054
3055 /* If the image size is 0, we are done.
3056 */
3057 if ((sz = ioc->facts.FWImageSize) == 0)
3058 return 0;
3059
3060 mpt_alloc_fw_memory(ioc, sz);
3061
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003062 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003064
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 if (ioc->cached_fw == NULL) {
3066 /* Major Failure.
3067 */
3068 return -ENOMEM;
3069 }
3070
3071 prequest = (FWUpload_t *)&request;
3072 preply = (FWUploadReply_t *)&reply;
3073
3074 /* Destination... */
3075 memset(prequest, 0, ioc->req_sz);
3076
3077 reply_sz = sizeof(reply);
3078 memset(preply, 0, reply_sz);
3079
3080 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3081 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3082
3083 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3084 ptcsge->DetailsLength = 12;
3085 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3086 ptcsge->ImageSize = cpu_to_le32(sz);
3087
3088 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3089
3090 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
3091 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
3092
3093 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003094 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 prequest, sgeoffset));
3096 DBG_DUMP_FW_REQUEST_FRAME(prequest)
3097
3098 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3099 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3100
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003101 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102
3103 cmdStatus = -EFAULT;
3104 if (ii == 0) {
3105 /* Handshake transfer was complete and successful.
3106 * Check the Reply Frame.
3107 */
3108 int status, transfer_sz;
3109 status = le16_to_cpu(preply->IOCStatus);
3110 if (status == MPI_IOCSTATUS_SUCCESS) {
3111 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3112 if (transfer_sz == sz)
3113 cmdStatus = 0;
3114 }
3115 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003116 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 ioc->name, cmdStatus));
3118
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003119
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 if (cmdStatus) {
3121
3122 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
3123 ioc->name));
3124 mpt_free_fw_memory(ioc);
3125 }
3126
3127 return cmdStatus;
3128}
3129
3130/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003131/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 * mpt_downloadboot - DownloadBoot code
3133 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003134 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 * @sleepFlag: Specifies whether the process can sleep
3136 *
3137 * FwDownloadBoot requires Programmed IO access.
3138 *
3139 * Returns 0 for success
3140 * -1 FW Image size is 0
3141 * -2 No valid cached_fw Pointer
3142 * <0 for fw upload failure.
3143 */
3144static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003145mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 MpiExtImageHeader_t *pExtImage;
3148 u32 fwSize;
3149 u32 diag0val;
3150 int count;
3151 u32 *ptrFw;
3152 u32 diagRwData;
3153 u32 nextImage;
3154 u32 load_addr;
3155 u32 ioc_state=0;
3156
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003157 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
3158 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003159
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3161 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3162 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3163 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3164 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3165 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3166
3167 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3168
3169 /* wait 1 msec */
3170 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003171 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 } else {
3173 mdelay (1);
3174 }
3175
3176 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3177 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3178
3179 for (count = 0; count < 30; count ++) {
3180 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3181 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3182 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
3183 ioc->name, count));
3184 break;
3185 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003186 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003188 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003190 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 }
3192 }
3193
3194 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003195 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
3196 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 ioc->name, diag0val));
3198 return -3;
3199 }
3200
3201 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3202 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3203 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3204 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3205 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3206 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3207
3208 /* Set the DiagRwEn and Disable ARM bits */
3209 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3210
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 fwSize = (pFwHeader->ImageSize + 3)/4;
3212 ptrFw = (u32 *) pFwHeader;
3213
3214 /* Write the LoadStartAddress to the DiagRw Address Register
3215 * using Programmed IO
3216 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003217 if (ioc->errata_flag_1064)
3218 pci_enable_io_access(ioc->pcidev);
3219
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
3221 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
3222 ioc->name, pFwHeader->LoadStartAddress));
3223
3224 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
3225 ioc->name, fwSize*4, ptrFw));
3226 while (fwSize--) {
3227 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3228 }
3229
3230 nextImage = pFwHeader->NextImageHeaderOffset;
3231 while (nextImage) {
3232 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3233
3234 load_addr = pExtImage->LoadStartAddress;
3235
3236 fwSize = (pExtImage->ImageSize + 3) >> 2;
3237 ptrFw = (u32 *)pExtImage;
3238
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003239 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
3240 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3242
3243 while (fwSize--) {
3244 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3245 }
3246 nextImage = pExtImage->NextImageHeaderOffset;
3247 }
3248
3249 /* Write the IopResetVectorRegAddr */
3250 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3251 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3252
3253 /* Write the IopResetVectorValue */
3254 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3255 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3256
3257 /* Clear the internal flash bad bit - autoincrementing register,
3258 * so must do two writes.
3259 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003260 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003261 /*
3262 * 1030 and 1035 H/W errata, workaround to access
3263 * the ClearFlashBadSignatureBit
3264 */
3265 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3266 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3267 diagRwData |= 0x40000000;
3268 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3269 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3270
3271 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3272 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3273 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3274 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3275
3276 /* wait 1 msec */
3277 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003278 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003279 } else {
3280 mdelay (1);
3281 }
3282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003284 if (ioc->errata_flag_1064)
3285 pci_disable_io_access(ioc->pcidev);
3286
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003288 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3289 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003291 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3293 ioc->name, diag0val));
3294 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3295
3296 /* Write 0xFF to reset the sequencer */
3297 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3298
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003299 if (ioc->bus_type == SAS) {
3300 ioc_state = mpt_GetIocState(ioc, 0);
3301 if ( (GetIocFacts(ioc, sleepFlag,
3302 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3303 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3304 ioc->name, ioc_state));
3305 return -EFAULT;
3306 }
3307 }
3308
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 for (count=0; count<HZ*20; count++) {
3310 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3311 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3312 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003313 if (ioc->bus_type == SAS) {
3314 return 0;
3315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3317 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3318 ioc->name));
3319 return -EFAULT;
3320 }
3321 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3322 ioc->name));
3323 return 0;
3324 }
3325 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003326 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 } else {
3328 mdelay (10);
3329 }
3330 }
3331 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3332 ioc->name, ioc_state));
3333 return -EFAULT;
3334}
3335
3336/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003337/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 * KickStart - Perform hard reset of MPT adapter.
3339 * @ioc: Pointer to MPT_ADAPTER structure
3340 * @force: Force hard reset
3341 * @sleepFlag: Specifies whether the process can sleep
3342 *
3343 * This routine places MPT adapter in diagnostic mode via the
3344 * WriteSequence register, and then performs a hard reset of adapter
3345 * via the Diagnostic register.
3346 *
3347 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3348 * or NO_SLEEP (interrupt thread, use mdelay)
3349 * force - 1 if doorbell active, board fault state
3350 * board operational, IOC_RECOVERY or
3351 * IOC_BRINGUP and there is an alt_ioc.
3352 * 0 else
3353 *
3354 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003355 * 1 - hard reset, READY
3356 * 0 - no reset due to History bit, READY
3357 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 * OR reset but failed to come READY
3359 * -2 - no reset, could not enter DIAG mode
3360 * -3 - reset but bad FW bit
3361 */
3362static int
3363KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3364{
3365 int hard_reset_done = 0;
3366 u32 ioc_state=0;
3367 int cnt,cntdn;
3368
3369 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003370 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 /* Always issue a Msg Unit Reset first. This will clear some
3372 * SCSI bus hang conditions.
3373 */
3374 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3375
3376 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003377 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 } else {
3379 mdelay (1000);
3380 }
3381 }
3382
3383 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3384 if (hard_reset_done < 0)
3385 return hard_reset_done;
3386
3387 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3388 ioc->name));
3389
3390 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3391 for (cnt=0; cnt<cntdn; cnt++) {
3392 ioc_state = mpt_GetIocState(ioc, 1);
3393 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3394 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3395 ioc->name, cnt));
3396 return hard_reset_done;
3397 }
3398 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003399 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 } else {
3401 mdelay (10);
3402 }
3403 }
3404
3405 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3406 ioc->name, ioc_state);
3407 return -1;
3408}
3409
3410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003411/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 * mpt_diag_reset - Perform hard reset of the adapter.
3413 * @ioc: Pointer to MPT_ADAPTER structure
3414 * @ignore: Set if to honor and clear to ignore
3415 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003416 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 * else set to NO_SLEEP (use mdelay instead)
3418 *
3419 * This routine places the adapter in diagnostic mode via the
3420 * WriteSequence register and then performs a hard reset of adapter
3421 * via the Diagnostic register. Adapter should be in ready state
3422 * upon successful completion.
3423 *
3424 * Returns: 1 hard reset successful
3425 * 0 no reset performed because reset history bit set
3426 * -2 enabling diagnostic mode failed
3427 * -3 diagnostic reset failed
3428 */
3429static int
3430mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3431{
Eric Moore0ccdb002006-07-11 17:33:13 -06003432 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 u32 diag0val;
3434 u32 doorbell;
3435 int hard_reset_done = 0;
3436 int count = 0;
3437#ifdef MPT_DEBUG
3438 u32 diag1val = 0;
3439#endif
3440
Eric Moorecd2c6192007-01-29 09:47:47 -07003441 /* Clear any existing interrupts */
3442 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3443
Eric Moore87cf8982006-06-27 16:09:26 -06003444 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
3445 drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
3446 "address=%p\n", ioc->name, __FUNCTION__,
3447 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3448 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3449 if (sleepFlag == CAN_SLEEP)
3450 msleep(1);
3451 else
3452 mdelay(1);
3453
3454 for (count = 0; count < 60; count ++) {
3455 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3456 doorbell &= MPI_IOC_STATE_MASK;
3457
3458 drsprintk((MYIOC_s_INFO_FMT
3459 "looking for READY STATE: doorbell=%x"
3460 " count=%d\n",
3461 ioc->name, doorbell, count));
3462 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003463 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003464 }
3465
3466 /* wait 1 sec */
3467 if (sleepFlag == CAN_SLEEP)
3468 msleep(1000);
3469 else
3470 mdelay(1000);
3471 }
3472 return -1;
3473 }
3474
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 /* Use "Diagnostic reset" method! (only thing available!) */
3476 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3477
3478#ifdef MPT_DEBUG
3479 if (ioc->alt_ioc)
3480 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3481 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3482 ioc->name, diag0val, diag1val));
3483#endif
3484
3485 /* Do the reset if we are told to ignore the reset history
3486 * or if the reset history is 0
3487 */
3488 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3489 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3490 /* Write magic sequence to WriteSequence register
3491 * Loop until in diagnostic mode
3492 */
3493 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3494 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3495 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3496 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3497 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3498 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3499
3500 /* wait 100 msec */
3501 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003502 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 } else {
3504 mdelay (100);
3505 }
3506
3507 count++;
3508 if (count > 20) {
3509 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3510 ioc->name, diag0val);
3511 return -2;
3512
3513 }
3514
3515 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3516
3517 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3518 ioc->name, diag0val));
3519 }
3520
3521#ifdef MPT_DEBUG
3522 if (ioc->alt_ioc)
3523 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3524 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3525 ioc->name, diag0val, diag1val));
3526#endif
3527 /*
3528 * Disable the ARM (Bug fix)
3529 *
3530 */
3531 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003532 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
3534 /*
3535 * Now hit the reset bit in the Diagnostic register
3536 * (THE BIG HAMMER!) (Clears DRWE bit).
3537 */
3538 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3539 hard_reset_done = 1;
3540 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3541 ioc->name));
3542
3543 /*
3544 * Call each currently registered protocol IOC reset handler
3545 * with pre-reset indication.
3546 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3547 * MptResetHandlers[] registered yet.
3548 */
3549 {
3550 int ii;
3551 int r = 0;
3552
3553 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3554 if (MptResetHandlers[ii]) {
3555 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3556 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003557 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 if (ioc->alt_ioc) {
3559 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3560 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003561 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 }
3563 }
3564 }
3565 /* FIXME? Examine results here? */
3566 }
3567
Eric Moore0ccdb002006-07-11 17:33:13 -06003568 if (ioc->cached_fw)
3569 iocp = ioc;
3570 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3571 iocp = ioc->alt_ioc;
3572 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 /* If the DownloadBoot operation fails, the
3574 * IOC will be left unusable. This is a fatal error
3575 * case. _diag_reset will return < 0
3576 */
3577 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003578 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3580 break;
3581 }
3582
Eric Moore0ccdb002006-07-11 17:33:13 -06003583 dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n",
3584 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 /* wait 1 sec */
3586 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003587 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 } else {
3589 mdelay (1000);
3590 }
3591 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003592 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003593 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 printk(KERN_WARNING MYNAM
3595 ": firmware downloadboot failure (%d)!\n", count);
3596 }
3597
3598 } else {
3599 /* Wait for FW to reload and for board
3600 * to go to the READY state.
3601 * Maximum wait is 60 seconds.
3602 * If fail, no error will check again
3603 * with calling program.
3604 */
3605 for (count = 0; count < 60; count ++) {
3606 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3607 doorbell &= MPI_IOC_STATE_MASK;
3608
3609 if (doorbell == MPI_IOC_STATE_READY) {
3610 break;
3611 }
3612
3613 /* wait 1 sec */
3614 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003615 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 } else {
3617 mdelay (1000);
3618 }
3619 }
3620 }
3621 }
3622
3623 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3624#ifdef MPT_DEBUG
3625 if (ioc->alt_ioc)
3626 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3627 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3628 ioc->name, diag0val, diag1val));
3629#endif
3630
3631 /* Clear RESET_HISTORY bit! Place board in the
3632 * diagnostic mode to update the diag register.
3633 */
3634 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3635 count = 0;
3636 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3637 /* Write magic sequence to WriteSequence register
3638 * Loop until in diagnostic mode
3639 */
3640 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3641 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3642 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3643 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3644 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3645 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3646
3647 /* wait 100 msec */
3648 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003649 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 } else {
3651 mdelay (100);
3652 }
3653
3654 count++;
3655 if (count > 20) {
3656 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3657 ioc->name, diag0val);
3658 break;
3659 }
3660 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3661 }
3662 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3663 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3664 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3665 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3666 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3667 ioc->name);
3668 }
3669
3670 /* Disable Diagnostic Mode
3671 */
3672 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3673
3674 /* Check FW reload status flags.
3675 */
3676 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3677 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3678 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3679 ioc->name, diag0val);
3680 return -3;
3681 }
3682
3683#ifdef MPT_DEBUG
3684 if (ioc->alt_ioc)
3685 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3686 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3687 ioc->name, diag0val, diag1val));
3688#endif
3689
3690 /*
3691 * Reset flag that says we've enabled event notification
3692 */
3693 ioc->facts.EventState = 0;
3694
3695 if (ioc->alt_ioc)
3696 ioc->alt_ioc->facts.EventState = 0;
3697
3698 return hard_reset_done;
3699}
3700
3701/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003702/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 * SendIocReset - Send IOCReset request to MPT adapter.
3704 * @ioc: Pointer to MPT_ADAPTER structure
3705 * @reset_type: reset type, expected values are
3706 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003707 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 *
3709 * Send IOCReset request to the MPT adapter.
3710 *
3711 * Returns 0 for success, non-zero for failure.
3712 */
3713static int
3714SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3715{
3716 int r;
3717 u32 state;
3718 int cntdn, count;
3719
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003720 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 ioc->name, reset_type));
3722 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3723 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3724 return r;
3725
3726 /* FW ACK'd request, wait for READY state
3727 */
3728 count = 0;
3729 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3730
3731 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3732 cntdn--;
3733 count++;
3734 if (!cntdn) {
3735 if (sleepFlag != CAN_SLEEP)
3736 count *= 10;
3737
3738 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3739 ioc->name, (int)((count+5)/HZ));
3740 return -ETIME;
3741 }
3742
3743 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003744 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 } else {
3746 mdelay (1); /* 1 msec delay */
3747 }
3748 }
3749
3750 /* TODO!
3751 * Cleanup all event stuff for this IOC; re-issue EventNotification
3752 * request if needed.
3753 */
3754 if (ioc->facts.Function)
3755 ioc->facts.EventState = 0;
3756
3757 return 0;
3758}
3759
3760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003761/**
3762 * initChainBuffers - Allocate memory for and initialize chain buffers
3763 * @ioc: Pointer to MPT_ADAPTER structure
3764 *
3765 * Allocates memory for and initializes chain buffers,
3766 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 */
3768static int
3769initChainBuffers(MPT_ADAPTER *ioc)
3770{
3771 u8 *mem;
3772 int sz, ii, num_chain;
3773 int scale, num_sge, numSGE;
3774
3775 /* ReqToChain size must equal the req_depth
3776 * index = req_idx
3777 */
3778 if (ioc->ReqToChain == NULL) {
3779 sz = ioc->req_depth * sizeof(int);
3780 mem = kmalloc(sz, GFP_ATOMIC);
3781 if (mem == NULL)
3782 return -1;
3783
3784 ioc->ReqToChain = (int *) mem;
3785 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3786 ioc->name, mem, sz));
3787 mem = kmalloc(sz, GFP_ATOMIC);
3788 if (mem == NULL)
3789 return -1;
3790
3791 ioc->RequestNB = (int *) mem;
3792 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3793 ioc->name, mem, sz));
3794 }
3795 for (ii = 0; ii < ioc->req_depth; ii++) {
3796 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3797 }
3798
3799 /* ChainToChain size must equal the total number
3800 * of chain buffers to be allocated.
3801 * index = chain_idx
3802 *
3803 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003804 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 *
3806 * num_sge = num sge in request frame + last chain buffer
3807 * scale = num sge per chain buffer if no chain element
3808 */
3809 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3810 if (sizeof(dma_addr_t) == sizeof(u64))
3811 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3812 else
3813 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3814
3815 if (sizeof(dma_addr_t) == sizeof(u64)) {
3816 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3817 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3818 } else {
3819 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3820 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3821 }
3822 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3823 ioc->name, num_sge, numSGE));
3824
3825 if ( numSGE > MPT_SCSI_SG_DEPTH )
3826 numSGE = MPT_SCSI_SG_DEPTH;
3827
3828 num_chain = 1;
3829 while (numSGE - num_sge > 0) {
3830 num_chain++;
3831 num_sge += (scale - 1);
3832 }
3833 num_chain++;
3834
3835 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3836 ioc->name, numSGE, num_sge, num_chain));
3837
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003838 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 num_chain *= MPT_SCSI_CAN_QUEUE;
3840 else
3841 num_chain *= MPT_FC_CAN_QUEUE;
3842
3843 ioc->num_chain = num_chain;
3844
3845 sz = num_chain * sizeof(int);
3846 if (ioc->ChainToChain == NULL) {
3847 mem = kmalloc(sz, GFP_ATOMIC);
3848 if (mem == NULL)
3849 return -1;
3850
3851 ioc->ChainToChain = (int *) mem;
3852 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3853 ioc->name, mem, sz));
3854 } else {
3855 mem = (u8 *) ioc->ChainToChain;
3856 }
3857 memset(mem, 0xFF, sz);
3858 return num_chain;
3859}
3860
3861/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003862/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3864 * @ioc: Pointer to MPT_ADAPTER structure
3865 *
3866 * This routine allocates memory for the MPT reply and request frame
3867 * pools (if necessary), and primes the IOC reply FIFO with
3868 * reply frames.
3869 *
3870 * Returns 0 for success, non-zero for failure.
3871 */
3872static int
3873PrimeIocFifos(MPT_ADAPTER *ioc)
3874{
3875 MPT_FRAME_HDR *mf;
3876 unsigned long flags;
3877 dma_addr_t alloc_dma;
3878 u8 *mem;
3879 int i, reply_sz, sz, total_size, num_chain;
3880
3881 /* Prime reply FIFO... */
3882
3883 if (ioc->reply_frames == NULL) {
3884 if ( (num_chain = initChainBuffers(ioc)) < 0)
3885 return -1;
3886
3887 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3888 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3889 ioc->name, ioc->reply_sz, ioc->reply_depth));
3890 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3891 ioc->name, reply_sz, reply_sz));
3892
3893 sz = (ioc->req_sz * ioc->req_depth);
3894 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3895 ioc->name, ioc->req_sz, ioc->req_depth));
3896 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3897 ioc->name, sz, sz));
3898 total_size += sz;
3899
3900 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3901 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3902 ioc->name, ioc->req_sz, num_chain));
3903 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3904 ioc->name, sz, sz, num_chain));
3905
3906 total_size += sz;
3907 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3908 if (mem == NULL) {
3909 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3910 ioc->name);
3911 goto out_fail;
3912 }
3913
3914 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3915 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3916
3917 memset(mem, 0, total_size);
3918 ioc->alloc_total += total_size;
3919 ioc->alloc = mem;
3920 ioc->alloc_dma = alloc_dma;
3921 ioc->alloc_sz = total_size;
3922 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3923 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3924
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003925 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3926 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3927
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 alloc_dma += reply_sz;
3929 mem += reply_sz;
3930
3931 /* Request FIFO - WE manage this! */
3932
3933 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3934 ioc->req_frames_dma = alloc_dma;
3935
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003936 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 ioc->name, mem, (void *)(ulong)alloc_dma));
3938
3939 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3940
3941#if defined(CONFIG_MTRR) && 0
3942 /*
3943 * Enable Write Combining MTRR for IOC's memory region.
3944 * (at least as much as we can; "size and base must be
3945 * multiples of 4 kiB"
3946 */
3947 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3948 sz,
3949 MTRR_TYPE_WRCOMB, 1);
3950 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3951 ioc->name, ioc->req_frames_dma, sz));
3952#endif
3953
3954 for (i = 0; i < ioc->req_depth; i++) {
3955 alloc_dma += ioc->req_sz;
3956 mem += ioc->req_sz;
3957 }
3958
3959 ioc->ChainBuffer = mem;
3960 ioc->ChainBufferDMA = alloc_dma;
3961
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003962 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3964
3965 /* Initialize the free chain Q.
3966 */
3967
3968 INIT_LIST_HEAD(&ioc->FreeChainQ);
3969
3970 /* Post the chain buffers to the FreeChainQ.
3971 */
3972 mem = (u8 *)ioc->ChainBuffer;
3973 for (i=0; i < num_chain; i++) {
3974 mf = (MPT_FRAME_HDR *) mem;
3975 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3976 mem += ioc->req_sz;
3977 }
3978
3979 /* Initialize Request frames linked list
3980 */
3981 alloc_dma = ioc->req_frames_dma;
3982 mem = (u8 *) ioc->req_frames;
3983
3984 spin_lock_irqsave(&ioc->FreeQlock, flags);
3985 INIT_LIST_HEAD(&ioc->FreeQ);
3986 for (i = 0; i < ioc->req_depth; i++) {
3987 mf = (MPT_FRAME_HDR *) mem;
3988
3989 /* Queue REQUESTs *internally*! */
3990 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3991
3992 mem += ioc->req_sz;
3993 }
3994 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3995
3996 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3997 ioc->sense_buf_pool =
3998 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3999 if (ioc->sense_buf_pool == NULL) {
4000 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4001 ioc->name);
4002 goto out_fail;
4003 }
4004
4005 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4006 ioc->alloc_total += sz;
4007 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
4008 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4009
4010 }
4011
4012 /* Post Reply frames to FIFO
4013 */
4014 alloc_dma = ioc->alloc_dma;
4015 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
4016 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4017
4018 for (i = 0; i < ioc->reply_depth; i++) {
4019 /* Write each address to the IOC! */
4020 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4021 alloc_dma += ioc->reply_sz;
4022 }
4023
4024 return 0;
4025
4026out_fail:
4027 if (ioc->alloc != NULL) {
4028 sz = ioc->alloc_sz;
4029 pci_free_consistent(ioc->pcidev,
4030 sz,
4031 ioc->alloc, ioc->alloc_dma);
4032 ioc->reply_frames = NULL;
4033 ioc->req_frames = NULL;
4034 ioc->alloc_total -= sz;
4035 }
4036 if (ioc->sense_buf_pool != NULL) {
4037 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4038 pci_free_consistent(ioc->pcidev,
4039 sz,
4040 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4041 ioc->sense_buf_pool = NULL;
4042 }
4043 return -1;
4044}
4045
4046/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4047/**
4048 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4049 * from IOC via doorbell handshake method.
4050 * @ioc: Pointer to MPT_ADAPTER structure
4051 * @reqBytes: Size of the request in bytes
4052 * @req: Pointer to MPT request frame
4053 * @replyBytes: Expected size of the reply in bytes
4054 * @u16reply: Pointer to area where reply should be written
4055 * @maxwait: Max wait time for a reply (in seconds)
4056 * @sleepFlag: Specifies whether the process can sleep
4057 *
4058 * NOTES: It is the callers responsibility to byte-swap fields in the
4059 * request which are greater than 1 byte in size. It is also the
4060 * callers responsibility to byte-swap response fields which are
4061 * greater than 1 byte in size.
4062 *
4063 * Returns 0 for success, non-zero for failure.
4064 */
4065static int
4066mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004067 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068{
4069 MPIDefaultReply_t *mptReply;
4070 int failcnt = 0;
4071 int t;
4072
4073 /*
4074 * Get ready to cache a handshake reply
4075 */
4076 ioc->hs_reply_idx = 0;
4077 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4078 mptReply->MsgLength = 0;
4079
4080 /*
4081 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4082 * then tell IOC that we want to handshake a request of N words.
4083 * (WRITE u32val to Doorbell reg).
4084 */
4085 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4086 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4087 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4088 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4089
4090 /*
4091 * Wait for IOC's doorbell handshake int
4092 */
4093 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4094 failcnt++;
4095
4096 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
4097 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4098
4099 /* Read doorbell and check for active bit */
4100 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4101 return -1;
4102
4103 /*
4104 * Clear doorbell int (WRITE 0 to IntStatus reg),
4105 * then wait for IOC to ACKnowledge that it's ready for
4106 * our handshake request.
4107 */
4108 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4109 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4110 failcnt++;
4111
4112 if (!failcnt) {
4113 int ii;
4114 u8 *req_as_bytes = (u8 *) req;
4115
4116 /*
4117 * Stuff request words via doorbell handshake,
4118 * with ACK from IOC for each.
4119 */
4120 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4121 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4122 (req_as_bytes[(ii*4) + 1] << 8) |
4123 (req_as_bytes[(ii*4) + 2] << 16) |
4124 (req_as_bytes[(ii*4) + 3] << 24));
4125
4126 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4127 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4128 failcnt++;
4129 }
4130
4131 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
4132 DBG_DUMP_REQUEST_FRAME_HDR(req)
4133
4134 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
4135 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4136
4137 /*
4138 * Wait for completion of doorbell handshake reply from the IOC
4139 */
4140 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4141 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004142
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
4144 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4145
4146 /*
4147 * Copy out the cached reply...
4148 */
4149 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4150 u16reply[ii] = ioc->hs_reply[ii];
4151 } else {
4152 return -99;
4153 }
4154
4155 return -failcnt;
4156}
4157
4158/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004159/**
4160 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 * @ioc: Pointer to MPT_ADAPTER structure
4162 * @howlong: How long to wait (in seconds)
4163 * @sleepFlag: Specifies whether the process can sleep
4164 *
4165 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004166 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4167 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 *
4169 * Returns a negative value on failure, else wait loop count.
4170 */
4171static int
4172WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4173{
4174 int cntdn;
4175 int count = 0;
4176 u32 intstat=0;
4177
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004178 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179
4180 if (sleepFlag == CAN_SLEEP) {
4181 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004182 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4184 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4185 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 count++;
4187 }
4188 } else {
4189 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004190 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4192 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4193 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 count++;
4195 }
4196 }
4197
4198 if (cntdn) {
4199 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
4200 ioc->name, count));
4201 return count;
4202 }
4203
4204 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4205 ioc->name, count, intstat);
4206 return -1;
4207}
4208
4209/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004210/**
4211 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 * @ioc: Pointer to MPT_ADAPTER structure
4213 * @howlong: How long to wait (in seconds)
4214 * @sleepFlag: Specifies whether the process can sleep
4215 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004216 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4217 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 *
4219 * Returns a negative value on failure, else wait loop count.
4220 */
4221static int
4222WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4223{
4224 int cntdn;
4225 int count = 0;
4226 u32 intstat=0;
4227
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004228 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 if (sleepFlag == CAN_SLEEP) {
4230 while (--cntdn) {
4231 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4232 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4233 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004234 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 count++;
4236 }
4237 } else {
4238 while (--cntdn) {
4239 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4240 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4241 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004242 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 count++;
4244 }
4245 }
4246
4247 if (cntdn) {
4248 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
4249 ioc->name, count, howlong));
4250 return count;
4251 }
4252
4253 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4254 ioc->name, count, intstat);
4255 return -1;
4256}
4257
4258/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004259/**
4260 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 * @ioc: Pointer to MPT_ADAPTER structure
4262 * @howlong: How long to wait (in seconds)
4263 * @sleepFlag: Specifies whether the process can sleep
4264 *
4265 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4266 * Reply is cached to IOC private area large enough to hold a maximum
4267 * of 128 bytes of reply data.
4268 *
4269 * Returns a negative value on failure, else size of reply in WORDS.
4270 */
4271static int
4272WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4273{
4274 int u16cnt = 0;
4275 int failcnt = 0;
4276 int t;
4277 u16 *hs_reply = ioc->hs_reply;
4278 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4279 u16 hword;
4280
4281 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4282
4283 /*
4284 * Get first two u16's so we can look at IOC's intended reply MsgLength
4285 */
4286 u16cnt=0;
4287 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4288 failcnt++;
4289 } else {
4290 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4291 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4292 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4293 failcnt++;
4294 else {
4295 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4296 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4297 }
4298 }
4299
4300 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004301 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4303
4304 /*
4305 * If no error (and IOC said MsgLength is > 0), piece together
4306 * reply 16 bits at a time.
4307 */
4308 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4309 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4310 failcnt++;
4311 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4312 /* don't overflow our IOC hs_reply[] buffer! */
4313 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4314 hs_reply[u16cnt] = hword;
4315 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4316 }
4317
4318 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4319 failcnt++;
4320 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4321
4322 if (failcnt) {
4323 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4324 ioc->name);
4325 return -failcnt;
4326 }
4327#if 0
4328 else if (u16cnt != (2 * mptReply->MsgLength)) {
4329 return -101;
4330 }
4331 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4332 return -102;
4333 }
4334#endif
4335
4336 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4337 DBG_DUMP_REPLY_FRAME(mptReply)
4338
4339 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4340 ioc->name, t, u16cnt/2));
4341 return u16cnt/2;
4342}
4343
4344/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004345/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 * GetLanConfigPages - Fetch LANConfig pages.
4347 * @ioc: Pointer to MPT_ADAPTER structure
4348 *
4349 * Return: 0 for success
4350 * -ENOMEM if no memory available
4351 * -EPERM if not allowed due to ISR context
4352 * -EAGAIN if no msg frames currently available
4353 * -EFAULT for non-successful reply or no reply (timeout)
4354 */
4355static int
4356GetLanConfigPages(MPT_ADAPTER *ioc)
4357{
4358 ConfigPageHeader_t hdr;
4359 CONFIGPARMS cfg;
4360 LANPage0_t *ppage0_alloc;
4361 dma_addr_t page0_dma;
4362 LANPage1_t *ppage1_alloc;
4363 dma_addr_t page1_dma;
4364 int rc = 0;
4365 int data_sz;
4366 int copy_sz;
4367
4368 /* Get LAN Page 0 header */
4369 hdr.PageVersion = 0;
4370 hdr.PageLength = 0;
4371 hdr.PageNumber = 0;
4372 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004373 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 cfg.physAddr = -1;
4375 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4376 cfg.dir = 0;
4377 cfg.pageAddr = 0;
4378 cfg.timeout = 0;
4379
4380 if ((rc = mpt_config(ioc, &cfg)) != 0)
4381 return rc;
4382
4383 if (hdr.PageLength > 0) {
4384 data_sz = hdr.PageLength * 4;
4385 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4386 rc = -ENOMEM;
4387 if (ppage0_alloc) {
4388 memset((u8 *)ppage0_alloc, 0, data_sz);
4389 cfg.physAddr = page0_dma;
4390 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4391
4392 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4393 /* save the data */
4394 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4395 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4396
4397 }
4398
4399 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4400
4401 /* FIXME!
4402 * Normalize endianness of structure data,
4403 * by byte-swapping all > 1 byte fields!
4404 */
4405
4406 }
4407
4408 if (rc)
4409 return rc;
4410 }
4411
4412 /* Get LAN Page 1 header */
4413 hdr.PageVersion = 0;
4414 hdr.PageLength = 0;
4415 hdr.PageNumber = 1;
4416 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004417 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 cfg.physAddr = -1;
4419 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4420 cfg.dir = 0;
4421 cfg.pageAddr = 0;
4422
4423 if ((rc = mpt_config(ioc, &cfg)) != 0)
4424 return rc;
4425
4426 if (hdr.PageLength == 0)
4427 return 0;
4428
4429 data_sz = hdr.PageLength * 4;
4430 rc = -ENOMEM;
4431 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4432 if (ppage1_alloc) {
4433 memset((u8 *)ppage1_alloc, 0, data_sz);
4434 cfg.physAddr = page1_dma;
4435 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4436
4437 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4438 /* save the data */
4439 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4440 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4441 }
4442
4443 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4444
4445 /* FIXME!
4446 * Normalize endianness of structure data,
4447 * by byte-swapping all > 1 byte fields!
4448 */
4449
4450 }
4451
4452 return rc;
4453}
4454
4455/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004456/**
4457 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004458 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004459 * @persist_opcode: see below
4460 *
4461 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4462 * devices not currently present.
4463 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4464 *
4465 * NOTE: Don't use not this function during interrupt time.
4466 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004467 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004468 */
4469
4470/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4471int
4472mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4473{
4474 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4475 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4476 MPT_FRAME_HDR *mf = NULL;
4477 MPIHeader_t *mpi_hdr;
4478
4479
4480 /* insure garbage is not sent to fw */
4481 switch(persist_opcode) {
4482
4483 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4484 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4485 break;
4486
4487 default:
4488 return -1;
4489 break;
4490 }
4491
4492 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4493
4494 /* Get a MF for this command.
4495 */
4496 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4497 printk("%s: no msg frames!\n",__FUNCTION__);
4498 return -1;
4499 }
4500
4501 mpi_hdr = (MPIHeader_t *) mf;
4502 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4503 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4504 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4505 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4506 sasIoUnitCntrReq->Operation = persist_opcode;
4507
4508 init_timer(&ioc->persist_timer);
4509 ioc->persist_timer.data = (unsigned long) ioc;
4510 ioc->persist_timer.function = mpt_timer_expired;
4511 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4512 ioc->persist_wait_done=0;
4513 add_timer(&ioc->persist_timer);
4514 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4515 wait_event(mpt_waitq, ioc->persist_wait_done);
4516
4517 sasIoUnitCntrReply =
4518 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4519 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4520 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4521 __FUNCTION__,
4522 sasIoUnitCntrReply->IOCStatus,
4523 sasIoUnitCntrReply->IOCLogInfo);
4524 return -1;
4525 }
4526
4527 printk("%s: success\n",__FUNCTION__);
4528 return 0;
4529}
4530
4531/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004532
4533static void
4534mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4535 MpiEventDataRaid_t * pRaidEventData)
4536{
4537 int volume;
4538 int reason;
4539 int disk;
4540 int status;
4541 int flags;
4542 int state;
4543
4544 volume = pRaidEventData->VolumeID;
4545 reason = pRaidEventData->ReasonCode;
4546 disk = pRaidEventData->PhysDiskNum;
4547 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4548 flags = (status >> 0) & 0xff;
4549 state = (status >> 8) & 0xff;
4550
4551 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4552 return;
4553 }
4554
4555 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4556 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4557 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004558 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4559 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004560 } else {
4561 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4562 ioc->name, volume);
4563 }
4564
4565 switch(reason) {
4566 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4567 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4568 ioc->name);
4569 break;
4570
4571 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4572
4573 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4574 ioc->name);
4575 break;
4576
4577 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4578 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4579 ioc->name);
4580 break;
4581
4582 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4583 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4584 ioc->name,
4585 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4586 ? "optimal"
4587 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4588 ? "degraded"
4589 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4590 ? "failed"
4591 : "state unknown",
4592 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4593 ? ", enabled" : "",
4594 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4595 ? ", quiesced" : "",
4596 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4597 ? ", resync in progress" : "" );
4598 break;
4599
4600 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4601 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4602 ioc->name, disk);
4603 break;
4604
4605 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4606 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4607 ioc->name);
4608 break;
4609
4610 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4611 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4612 ioc->name);
4613 break;
4614
4615 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4616 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4617 ioc->name);
4618 break;
4619
4620 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4621 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4622 ioc->name,
4623 state == MPI_PHYSDISK0_STATUS_ONLINE
4624 ? "online"
4625 : state == MPI_PHYSDISK0_STATUS_MISSING
4626 ? "missing"
4627 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4628 ? "not compatible"
4629 : state == MPI_PHYSDISK0_STATUS_FAILED
4630 ? "failed"
4631 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4632 ? "initializing"
4633 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4634 ? "offline requested"
4635 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4636 ? "failed requested"
4637 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4638 ? "offline"
4639 : "state unknown",
4640 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4641 ? ", out of sync" : "",
4642 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4643 ? ", quiesced" : "" );
4644 break;
4645
4646 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4647 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4648 ioc->name, disk);
4649 break;
4650
4651 case MPI_EVENT_RAID_RC_SMART_DATA:
4652 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4653 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4654 break;
4655
4656 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4657 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4658 ioc->name, disk);
4659 break;
4660 }
4661}
4662
4663/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004664/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4666 * @ioc: Pointer to MPT_ADAPTER structure
4667 *
4668 * Returns: 0 for success
4669 * -ENOMEM if no memory available
4670 * -EPERM if not allowed due to ISR context
4671 * -EAGAIN if no msg frames currently available
4672 * -EFAULT for non-successful reply or no reply (timeout)
4673 */
4674static int
4675GetIoUnitPage2(MPT_ADAPTER *ioc)
4676{
4677 ConfigPageHeader_t hdr;
4678 CONFIGPARMS cfg;
4679 IOUnitPage2_t *ppage_alloc;
4680 dma_addr_t page_dma;
4681 int data_sz;
4682 int rc;
4683
4684 /* Get the page header */
4685 hdr.PageVersion = 0;
4686 hdr.PageLength = 0;
4687 hdr.PageNumber = 2;
4688 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004689 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 cfg.physAddr = -1;
4691 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4692 cfg.dir = 0;
4693 cfg.pageAddr = 0;
4694 cfg.timeout = 0;
4695
4696 if ((rc = mpt_config(ioc, &cfg)) != 0)
4697 return rc;
4698
4699 if (hdr.PageLength == 0)
4700 return 0;
4701
4702 /* Read the config page */
4703 data_sz = hdr.PageLength * 4;
4704 rc = -ENOMEM;
4705 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4706 if (ppage_alloc) {
4707 memset((u8 *)ppage_alloc, 0, data_sz);
4708 cfg.physAddr = page_dma;
4709 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4710
4711 /* If Good, save data */
4712 if ((rc = mpt_config(ioc, &cfg)) == 0)
4713 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4714
4715 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4716 }
4717
4718 return rc;
4719}
4720
4721/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004722/**
4723 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 * @ioc: Pointer to a Adapter Strucutre
4725 * @portnum: IOC port number
4726 *
4727 * Return: -EFAULT if read of config page header fails
4728 * or if no nvram
4729 * If read of SCSI Port Page 0 fails,
4730 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4731 * Adapter settings: async, narrow
4732 * Return 1
4733 * If read of SCSI Port Page 2 fails,
4734 * Adapter settings valid
4735 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4736 * Return 1
4737 * Else
4738 * Both valid
4739 * Return 0
4740 * CHECK - what type of locking mechanisms should be used????
4741 */
4742static int
4743mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4744{
4745 u8 *pbuf;
4746 dma_addr_t buf_dma;
4747 CONFIGPARMS cfg;
4748 ConfigPageHeader_t header;
4749 int ii;
4750 int data, rc = 0;
4751
4752 /* Allocate memory
4753 */
4754 if (!ioc->spi_data.nvram) {
4755 int sz;
4756 u8 *mem;
4757 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4758 mem = kmalloc(sz, GFP_ATOMIC);
4759 if (mem == NULL)
4760 return -EFAULT;
4761
4762 ioc->spi_data.nvram = (int *) mem;
4763
4764 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4765 ioc->name, ioc->spi_data.nvram, sz));
4766 }
4767
4768 /* Invalidate NVRAM information
4769 */
4770 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4771 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4772 }
4773
4774 /* Read SPP0 header, allocate memory, then read page.
4775 */
4776 header.PageVersion = 0;
4777 header.PageLength = 0;
4778 header.PageNumber = 0;
4779 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004780 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 cfg.physAddr = -1;
4782 cfg.pageAddr = portnum;
4783 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4784 cfg.dir = 0;
4785 cfg.timeout = 0; /* use default */
4786 if (mpt_config(ioc, &cfg) != 0)
4787 return -EFAULT;
4788
4789 if (header.PageLength > 0) {
4790 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4791 if (pbuf) {
4792 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4793 cfg.physAddr = buf_dma;
4794 if (mpt_config(ioc, &cfg) != 0) {
4795 ioc->spi_data.maxBusWidth = MPT_NARROW;
4796 ioc->spi_data.maxSyncOffset = 0;
4797 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4798 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4799 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004800 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4801 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 } else {
4803 /* Save the Port Page 0 data
4804 */
4805 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4806 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4807 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4808
4809 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4810 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004811 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 ioc->name, pPP0->Capabilities));
4813 }
4814 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4815 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4816 if (data) {
4817 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4818 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4819 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004820 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4821 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 } else {
4823 ioc->spi_data.maxSyncOffset = 0;
4824 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4825 }
4826
4827 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4828
4829 /* Update the minSyncFactor based on bus type.
4830 */
4831 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4832 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4833
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004834 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004836 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4837 ioc->name, ioc->spi_data.minSyncFactor));
4838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 }
4840 }
4841 if (pbuf) {
4842 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4843 }
4844 }
4845 }
4846
4847 /* SCSI Port Page 2 - Read the header then the page.
4848 */
4849 header.PageVersion = 0;
4850 header.PageLength = 0;
4851 header.PageNumber = 2;
4852 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004853 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 cfg.physAddr = -1;
4855 cfg.pageAddr = portnum;
4856 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4857 cfg.dir = 0;
4858 if (mpt_config(ioc, &cfg) != 0)
4859 return -EFAULT;
4860
4861 if (header.PageLength > 0) {
4862 /* Allocate memory and read SCSI Port Page 2
4863 */
4864 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4865 if (pbuf) {
4866 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4867 cfg.physAddr = buf_dma;
4868 if (mpt_config(ioc, &cfg) != 0) {
4869 /* Nvram data is left with INVALID mark
4870 */
4871 rc = 1;
4872 } else {
4873 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4874 MpiDeviceInfo_t *pdevice = NULL;
4875
Moore, Ericd8e925d2006-01-16 18:53:06 -07004876 /*
4877 * Save "Set to Avoid SCSI Bus Resets" flag
4878 */
4879 ioc->spi_data.bus_reset =
4880 (le32_to_cpu(pPP2->PortFlags) &
4881 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4882 0 : 1 ;
4883
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 /* Save the Port Page 2 data
4885 * (reformat into a 32bit quantity)
4886 */
4887 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4888 ioc->spi_data.PortFlags = data;
4889 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4890 pdevice = &pPP2->DeviceSettings[ii];
4891 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4892 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4893 ioc->spi_data.nvram[ii] = data;
4894 }
4895 }
4896
4897 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4898 }
4899 }
4900
4901 /* Update Adapter limits with those from NVRAM
4902 * Comment: Don't need to do this. Target performance
4903 * parameters will never exceed the adapters limits.
4904 */
4905
4906 return rc;
4907}
4908
4909/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004910/**
4911 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 * @ioc: Pointer to a Adapter Strucutre
4913 * @portnum: IOC port number
4914 *
4915 * Return: -EFAULT if read of config page header fails
4916 * or 0 if success.
4917 */
4918static int
4919mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4920{
4921 CONFIGPARMS cfg;
4922 ConfigPageHeader_t header;
4923
4924 /* Read the SCSI Device Page 1 header
4925 */
4926 header.PageVersion = 0;
4927 header.PageLength = 0;
4928 header.PageNumber = 1;
4929 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004930 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 cfg.physAddr = -1;
4932 cfg.pageAddr = portnum;
4933 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4934 cfg.dir = 0;
4935 cfg.timeout = 0;
4936 if (mpt_config(ioc, &cfg) != 0)
4937 return -EFAULT;
4938
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004939 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4940 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941
4942 header.PageVersion = 0;
4943 header.PageLength = 0;
4944 header.PageNumber = 0;
4945 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4946 if (mpt_config(ioc, &cfg) != 0)
4947 return -EFAULT;
4948
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004949 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4950 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951
4952 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4953 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4954
4955 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4956 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4957 return 0;
4958}
4959
Eric Mooreb506ade2007-01-29 09:45:37 -07004960/**
Randy Dunlap1544d672007-02-20 11:17:03 -08004961 * mpt_inactive_raid_list_free - This clears this link list.
4962 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07004963 **/
4964static void
4965mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
4966{
4967 struct inactive_raid_component_info *component_info, *pNext;
4968
4969 if (list_empty(&ioc->raid_data.inactive_list))
4970 return;
4971
4972 down(&ioc->raid_data.inactive_list_mutex);
4973 list_for_each_entry_safe(component_info, pNext,
4974 &ioc->raid_data.inactive_list, list) {
4975 list_del(&component_info->list);
4976 kfree(component_info);
4977 }
4978 up(&ioc->raid_data.inactive_list_mutex);
4979}
4980
4981/**
Randy Dunlap1544d672007-02-20 11:17:03 -08004982 * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
Eric Mooreb506ade2007-01-29 09:45:37 -07004983 *
Randy Dunlap1544d672007-02-20 11:17:03 -08004984 * @ioc : pointer to per adapter structure
4985 * @channel : volume channel
4986 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07004987 **/
4988static void
4989mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
4990{
4991 CONFIGPARMS cfg;
4992 ConfigPageHeader_t hdr;
4993 dma_addr_t dma_handle;
4994 pRaidVolumePage0_t buffer = NULL;
4995 int i;
4996 RaidPhysDiskPage0_t phys_disk;
4997 struct inactive_raid_component_info *component_info;
4998 int handle_inactive_volumes;
4999
5000 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5001 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5002 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5003 cfg.pageAddr = (channel << 8) + id;
5004 cfg.cfghdr.hdr = &hdr;
5005 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5006
5007 if (mpt_config(ioc, &cfg) != 0)
5008 goto out;
5009
5010 if (!hdr.PageLength)
5011 goto out;
5012
5013 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5014 &dma_handle);
5015
5016 if (!buffer)
5017 goto out;
5018
5019 cfg.physAddr = dma_handle;
5020 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5021
5022 if (mpt_config(ioc, &cfg) != 0)
5023 goto out;
5024
5025 if (!buffer->NumPhysDisks)
5026 goto out;
5027
5028 handle_inactive_volumes =
5029 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5030 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5031 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5032 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5033
5034 if (!handle_inactive_volumes)
5035 goto out;
5036
5037 down(&ioc->raid_data.inactive_list_mutex);
5038 for (i = 0; i < buffer->NumPhysDisks; i++) {
5039 if(mpt_raid_phys_disk_pg0(ioc,
5040 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5041 continue;
5042
5043 if ((component_info = kmalloc(sizeof (*component_info),
5044 GFP_KERNEL)) == NULL)
5045 continue;
5046
5047 component_info->volumeID = id;
5048 component_info->volumeBus = channel;
5049 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5050 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5051 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5052 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5053
5054 list_add_tail(&component_info->list,
5055 &ioc->raid_data.inactive_list);
5056 }
5057 up(&ioc->raid_data.inactive_list_mutex);
5058
5059 out:
5060 if (buffer)
5061 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5062 dma_handle);
5063}
5064
5065/**
5066 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5067 * @ioc: Pointer to a Adapter Structure
5068 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5069 * @phys_disk: requested payload data returned
5070 *
5071 * Return:
5072 * 0 on success
5073 * -EFAULT if read of config page header fails or data pointer not NULL
5074 * -ENOMEM if pci_alloc failed
5075 **/
5076int
5077mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5078{
5079 CONFIGPARMS cfg;
5080 ConfigPageHeader_t hdr;
5081 dma_addr_t dma_handle;
5082 pRaidPhysDiskPage0_t buffer = NULL;
5083 int rc;
5084
5085 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5086 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5087
5088 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5089 cfg.cfghdr.hdr = &hdr;
5090 cfg.physAddr = -1;
5091 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5092
5093 if (mpt_config(ioc, &cfg) != 0) {
5094 rc = -EFAULT;
5095 goto out;
5096 }
5097
5098 if (!hdr.PageLength) {
5099 rc = -EFAULT;
5100 goto out;
5101 }
5102
5103 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5104 &dma_handle);
5105
5106 if (!buffer) {
5107 rc = -ENOMEM;
5108 goto out;
5109 }
5110
5111 cfg.physAddr = dma_handle;
5112 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5113 cfg.pageAddr = phys_disk_num;
5114
5115 if (mpt_config(ioc, &cfg) != 0) {
5116 rc = -EFAULT;
5117 goto out;
5118 }
5119
5120 rc = 0;
5121 memcpy(phys_disk, buffer, sizeof(*buffer));
5122 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5123
5124 out:
5125
5126 if (buffer)
5127 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5128 dma_handle);
5129
5130 return rc;
5131}
5132
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133/**
5134 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5135 * @ioc: Pointer to a Adapter Strucutre
5136 * @portnum: IOC port number
5137 *
5138 * Return:
5139 * 0 on success
5140 * -EFAULT if read of config page header fails or data pointer not NULL
5141 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005142 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143int
5144mpt_findImVolumes(MPT_ADAPTER *ioc)
5145{
5146 IOCPage2_t *pIoc2;
5147 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 dma_addr_t ioc2_dma;
5149 CONFIGPARMS cfg;
5150 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 int rc = 0;
5152 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005153 int i;
5154
5155 if (!ioc->ir_firmware)
5156 return 0;
5157
5158 /* Free the old page
5159 */
5160 kfree(ioc->raid_data.pIocPg2);
5161 ioc->raid_data.pIocPg2 = NULL;
5162 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163
5164 /* Read IOCP2 header then the page.
5165 */
5166 header.PageVersion = 0;
5167 header.PageLength = 0;
5168 header.PageNumber = 2;
5169 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005170 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 cfg.physAddr = -1;
5172 cfg.pageAddr = 0;
5173 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5174 cfg.dir = 0;
5175 cfg.timeout = 0;
5176 if (mpt_config(ioc, &cfg) != 0)
5177 return -EFAULT;
5178
5179 if (header.PageLength == 0)
5180 return -EFAULT;
5181
5182 iocpage2sz = header.PageLength * 4;
5183 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5184 if (!pIoc2)
5185 return -ENOMEM;
5186
5187 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5188 cfg.physAddr = ioc2_dma;
5189 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005190 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191
Eric Mooreb506ade2007-01-29 09:45:37 -07005192 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5193 if (!mem)
5194 goto out;
5195
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005197 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198
Eric Mooreb506ade2007-01-29 09:45:37 -07005199 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200
Eric Mooreb506ade2007-01-29 09:45:37 -07005201 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5202 mpt_inactive_raid_volumes(ioc,
5203 pIoc2->RaidVolume[i].VolumeBus,
5204 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205
Eric Mooreb506ade2007-01-29 09:45:37 -07005206 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5208
5209 return rc;
5210}
5211
Moore, Ericc972c702006-03-14 09:14:06 -07005212static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5214{
5215 IOCPage3_t *pIoc3;
5216 u8 *mem;
5217 CONFIGPARMS cfg;
5218 ConfigPageHeader_t header;
5219 dma_addr_t ioc3_dma;
5220 int iocpage3sz = 0;
5221
5222 /* Free the old page
5223 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005224 kfree(ioc->raid_data.pIocPg3);
5225 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226
5227 /* There is at least one physical disk.
5228 * Read and save IOC Page 3
5229 */
5230 header.PageVersion = 0;
5231 header.PageLength = 0;
5232 header.PageNumber = 3;
5233 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005234 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 cfg.physAddr = -1;
5236 cfg.pageAddr = 0;
5237 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5238 cfg.dir = 0;
5239 cfg.timeout = 0;
5240 if (mpt_config(ioc, &cfg) != 0)
5241 return 0;
5242
5243 if (header.PageLength == 0)
5244 return 0;
5245
5246 /* Read Header good, alloc memory
5247 */
5248 iocpage3sz = header.PageLength * 4;
5249 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5250 if (!pIoc3)
5251 return 0;
5252
5253 /* Read the Page and save the data
5254 * into malloc'd memory.
5255 */
5256 cfg.physAddr = ioc3_dma;
5257 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5258 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005259 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 if (mem) {
5261 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005262 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 }
5264 }
5265
5266 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5267
5268 return 0;
5269}
5270
5271static void
5272mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5273{
5274 IOCPage4_t *pIoc4;
5275 CONFIGPARMS cfg;
5276 ConfigPageHeader_t header;
5277 dma_addr_t ioc4_dma;
5278 int iocpage4sz;
5279
5280 /* Read and save IOC Page 4
5281 */
5282 header.PageVersion = 0;
5283 header.PageLength = 0;
5284 header.PageNumber = 4;
5285 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005286 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 cfg.physAddr = -1;
5288 cfg.pageAddr = 0;
5289 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5290 cfg.dir = 0;
5291 cfg.timeout = 0;
5292 if (mpt_config(ioc, &cfg) != 0)
5293 return;
5294
5295 if (header.PageLength == 0)
5296 return;
5297
5298 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5299 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5300 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5301 if (!pIoc4)
5302 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005303 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 } else {
5305 ioc4_dma = ioc->spi_data.IocPg4_dma;
5306 iocpage4sz = ioc->spi_data.IocPg4Sz;
5307 }
5308
5309 /* Read the Page into dma memory.
5310 */
5311 cfg.physAddr = ioc4_dma;
5312 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5313 if (mpt_config(ioc, &cfg) == 0) {
5314 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5315 ioc->spi_data.IocPg4_dma = ioc4_dma;
5316 ioc->spi_data.IocPg4Sz = iocpage4sz;
5317 } else {
5318 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5319 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005320 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 }
5322}
5323
5324static void
5325mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5326{
5327 IOCPage1_t *pIoc1;
5328 CONFIGPARMS cfg;
5329 ConfigPageHeader_t header;
5330 dma_addr_t ioc1_dma;
5331 int iocpage1sz = 0;
5332 u32 tmp;
5333
5334 /* Check the Coalescing Timeout in IOC Page 1
5335 */
5336 header.PageVersion = 0;
5337 header.PageLength = 0;
5338 header.PageNumber = 1;
5339 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005340 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 cfg.physAddr = -1;
5342 cfg.pageAddr = 0;
5343 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5344 cfg.dir = 0;
5345 cfg.timeout = 0;
5346 if (mpt_config(ioc, &cfg) != 0)
5347 return;
5348
5349 if (header.PageLength == 0)
5350 return;
5351
5352 /* Read Header good, alloc memory
5353 */
5354 iocpage1sz = header.PageLength * 4;
5355 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5356 if (!pIoc1)
5357 return;
5358
5359 /* Read the Page and check coalescing timeout
5360 */
5361 cfg.physAddr = ioc1_dma;
5362 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5363 if (mpt_config(ioc, &cfg) == 0) {
5364
5365 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5366 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5367 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5368
5369 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5370 ioc->name, tmp));
5371
5372 if (tmp > MPT_COALESCING_TIMEOUT) {
5373 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5374
5375 /* Write NVRAM and current
5376 */
5377 cfg.dir = 1;
5378 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5379 if (mpt_config(ioc, &cfg) == 0) {
5380 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5381 ioc->name, MPT_COALESCING_TIMEOUT));
5382
5383 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5384 if (mpt_config(ioc, &cfg) == 0) {
5385 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5386 ioc->name, MPT_COALESCING_TIMEOUT));
5387 } else {
5388 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5389 ioc->name));
5390 }
5391
5392 } else {
5393 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5394 ioc->name));
5395 }
5396 }
5397
5398 } else {
5399 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5400 }
5401 }
5402
5403 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5404
5405 return;
5406}
5407
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305408static void
5409mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5410{
5411 CONFIGPARMS cfg;
5412 ConfigPageHeader_t hdr;
5413 dma_addr_t buf_dma;
5414 ManufacturingPage0_t *pbuf = NULL;
5415
5416 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5417 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5418
5419 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5420 cfg.cfghdr.hdr = &hdr;
5421 cfg.physAddr = -1;
5422 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5423 cfg.timeout = 10;
5424
5425 if (mpt_config(ioc, &cfg) != 0)
5426 goto out;
5427
5428 if (!cfg.cfghdr.hdr->PageLength)
5429 goto out;
5430
5431 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5432 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5433 if (!pbuf)
5434 goto out;
5435
5436 cfg.physAddr = buf_dma;
5437
5438 if (mpt_config(ioc, &cfg) != 0)
5439 goto out;
5440
5441 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5442 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5443 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5444
5445 out:
5446
5447 if (pbuf)
5448 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5449}
5450
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005452/**
5453 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 * @ioc: Pointer to MPT_ADAPTER structure
5455 * @EvSwitch: Event switch flags
5456 */
5457static int
5458SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5459{
5460 EventNotification_t *evnp;
5461
5462 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5463 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005464 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 ioc->name));
5466 return 0;
5467 }
5468 memset(evnp, 0, sizeof(*evnp));
5469
Moore, Eric3a892be2006-03-14 09:14:03 -07005470 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471
5472 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5473 evnp->ChainOffset = 0;
5474 evnp->MsgFlags = 0;
5475 evnp->Switch = EvSwitch;
5476
5477 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5478
5479 return 0;
5480}
5481
5482/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5483/**
5484 * SendEventAck - Send EventAck request to MPT adapter.
5485 * @ioc: Pointer to MPT_ADAPTER structure
5486 * @evnp: Pointer to original EventNotification request
5487 */
5488static int
5489SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5490{
5491 EventAck_t *pAck;
5492
5493 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Eric Moore4f766dc2006-07-11 17:24:07 -06005494 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
5495 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 return -1;
5497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498
Eric Moore4f766dc2006-07-11 17:24:07 -06005499 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500
5501 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5502 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005503 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005505 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 pAck->Event = evnp->Event;
5507 pAck->EventContext = evnp->EventContext;
5508
5509 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5510
5511 return 0;
5512}
5513
5514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5515/**
5516 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005517 * @ioc: Pointer to an adapter structure
5518 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 * action, page address, direction, physical address
5520 * and pointer to a configuration page header
5521 * Page header is updated.
5522 *
5523 * Returns 0 for success
5524 * -EPERM if not allowed due to ISR context
5525 * -EAGAIN if no msg frames currently available
5526 * -EFAULT for non-successful reply or no reply (timeout)
5527 */
5528int
5529mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5530{
5531 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005532 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 MPT_FRAME_HDR *mf;
5534 unsigned long flags;
5535 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005536 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 int in_isr;
5538
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005539 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 * to be in ISR context, because that is fatal!
5541 */
5542 in_isr = in_interrupt();
5543 if (in_isr) {
5544 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5545 ioc->name));
5546 return -EPERM;
5547 }
5548
5549 /* Get and Populate a free Frame
5550 */
5551 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5552 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5553 ioc->name));
5554 return -EAGAIN;
5555 }
5556 pReq = (Config_t *)mf;
5557 pReq->Action = pCfg->action;
5558 pReq->Reserved = 0;
5559 pReq->ChainOffset = 0;
5560 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005561
5562 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 pReq->ExtPageLength = 0;
5564 pReq->ExtPageType = 0;
5565 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005566
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 for (ii=0; ii < 8; ii++)
5568 pReq->Reserved2[ii] = 0;
5569
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005570 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5571 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5572 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5573 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5574
5575 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5576 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5577 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5578 pReq->ExtPageType = pExtHdr->ExtPageType;
5579 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5580
5581 /* Page Length must be treated as a reserved field for the extended header. */
5582 pReq->Header.PageLength = 0;
5583 }
5584
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5586
5587 /* Add a SGE to the config request.
5588 */
5589 if (pCfg->dir)
5590 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5591 else
5592 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5593
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005594 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5595 flagsLength |= pExtHdr->ExtPageLength * 4;
5596
5597 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5598 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5599 }
5600 else {
5601 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5602
5603 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5604 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606
5607 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5608
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 /* Append pCfg pointer to end of mf
5610 */
5611 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5612
5613 /* Initalize the timer
5614 */
5615 init_timer(&pCfg->timer);
5616 pCfg->timer.data = (unsigned long) ioc;
5617 pCfg->timer.function = mpt_timer_expired;
5618 pCfg->wait_done = 0;
5619
5620 /* Set the timer; ensure 10 second minimum */
5621 if (pCfg->timeout < 10)
5622 pCfg->timer.expires = jiffies + HZ*10;
5623 else
5624 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5625
5626 /* Add to end of Q, set timer and then issue this command */
5627 spin_lock_irqsave(&ioc->FreeQlock, flags);
5628 list_add_tail(&pCfg->linkage, &ioc->configQ);
5629 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5630
5631 add_timer(&pCfg->timer);
5632 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5633 wait_event(mpt_waitq, pCfg->wait_done);
5634
5635 /* mf has been freed - do not access */
5636
5637 rc = pCfg->status;
5638
5639 return rc;
5640}
5641
5642/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005643/**
5644 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 * Used only internal config functionality.
5646 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5647 */
5648static void
5649mpt_timer_expired(unsigned long data)
5650{
5651 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5652
5653 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5654
5655 /* Perform a FW reload */
5656 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5657 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5658
5659 /* No more processing.
5660 * Hard reset clean-up will wake up
5661 * process and free all resources.
5662 */
5663 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5664
5665 return;
5666}
5667
5668/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005669/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 * mpt_ioc_reset - Base cleanup for hard reset
5671 * @ioc: Pointer to the adapter structure
5672 * @reset_phase: Indicates pre- or post-reset functionality
5673 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005674 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 */
5676static int
5677mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5678{
5679 CONFIGPARMS *pCfg;
5680 unsigned long flags;
5681
5682 dprintk((KERN_WARNING MYNAM
5683 ": IOC %s_reset routed to MPT base driver!\n",
5684 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5685 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5686
5687 if (reset_phase == MPT_IOC_SETUP_RESET) {
5688 ;
5689 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5690 /* If the internal config Q is not empty -
5691 * delete timer. MF resources will be freed when
5692 * the FIFO's are primed.
5693 */
5694 spin_lock_irqsave(&ioc->FreeQlock, flags);
5695 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5696 del_timer(&pCfg->timer);
5697 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5698
5699 } else {
5700 CONFIGPARMS *pNext;
5701
5702 /* Search the configQ for internal commands.
5703 * Flush the Q, and wake up all suspended threads.
5704 */
5705 spin_lock_irqsave(&ioc->FreeQlock, flags);
5706 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5707 list_del(&pCfg->linkage);
5708
5709 pCfg->status = MPT_CONFIG_ERROR;
5710 pCfg->wait_done = 1;
5711 wake_up(&mpt_waitq);
5712 }
5713 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5714 }
5715
5716 return 1; /* currently means nothing really */
5717}
5718
5719
5720#ifdef CONFIG_PROC_FS /* { */
5721/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5722/*
5723 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5724 */
5725/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005726/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5728 *
5729 * Returns 0 for success, non-zero for failure.
5730 */
5731static int
5732procmpt_create(void)
5733{
5734 struct proc_dir_entry *ent;
5735
5736 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5737 if (mpt_proc_root_dir == NULL)
5738 return -ENOTDIR;
5739
5740 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5741 if (ent)
5742 ent->read_proc = procmpt_summary_read;
5743
5744 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5745 if (ent)
5746 ent->read_proc = procmpt_version_read;
5747
5748 return 0;
5749}
5750
5751/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005752/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5754 *
5755 * Returns 0 for success, non-zero for failure.
5756 */
5757static void
5758procmpt_destroy(void)
5759{
5760 remove_proc_entry("version", mpt_proc_root_dir);
5761 remove_proc_entry("summary", mpt_proc_root_dir);
5762 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5763}
5764
5765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005766/**
5767 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 * @buf: Pointer to area to write information
5769 * @start: Pointer to start pointer
5770 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005771 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772 * @eof: Pointer to EOF integer
5773 * @data: Pointer
5774 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005775 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 * Returns number of characters written to process performing the read.
5777 */
5778static int
5779procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5780{
5781 MPT_ADAPTER *ioc;
5782 char *out = buf;
5783 int len;
5784
5785 if (data) {
5786 int more = 0;
5787
5788 ioc = data;
5789 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5790
5791 out += more;
5792 } else {
5793 list_for_each_entry(ioc, &ioc_list, list) {
5794 int more = 0;
5795
5796 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5797
5798 out += more;
5799 if ((out-buf) >= request)
5800 break;
5801 }
5802 }
5803
5804 len = out - buf;
5805
5806 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5807}
5808
5809/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005810/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 * procmpt_version_read - Handle read request from /proc/mpt/version.
5812 * @buf: Pointer to area to write information
5813 * @start: Pointer to start pointer
5814 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005815 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816 * @eof: Pointer to EOF integer
5817 * @data: Pointer
5818 *
5819 * Returns number of characters written to process performing the read.
5820 */
5821static int
5822procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5823{
5824 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005825 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 char *drvname;
5827 int len;
5828
5829 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5830 len += sprintf(buf+len, " Fusion MPT base driver\n");
5831
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005832 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5834 drvname = NULL;
5835 if (MptCallbacks[ii]) {
5836 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005837 case MPTSPI_DRIVER:
5838 if (!scsi++) drvname = "SPI host";
5839 break;
5840 case MPTFC_DRIVER:
5841 if (!fc++) drvname = "FC host";
5842 break;
5843 case MPTSAS_DRIVER:
5844 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845 break;
5846 case MPTLAN_DRIVER:
5847 if (!lan++) drvname = "LAN";
5848 break;
5849 case MPTSTM_DRIVER:
5850 if (!targ++) drvname = "SCSI target";
5851 break;
5852 case MPTCTL_DRIVER:
5853 if (!ctl++) drvname = "ioctl";
5854 break;
5855 }
5856
5857 if (drvname)
5858 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5859 }
5860 }
5861
5862 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5863}
5864
5865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005866/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5868 * @buf: Pointer to area to write information
5869 * @start: Pointer to start pointer
5870 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005871 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872 * @eof: Pointer to EOF integer
5873 * @data: Pointer
5874 *
5875 * Returns number of characters written to process performing the read.
5876 */
5877static int
5878procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5879{
5880 MPT_ADAPTER *ioc = data;
5881 int len;
5882 char expVer[32];
5883 int sz;
5884 int p;
5885
5886 mpt_get_fw_exp_ver(expVer, ioc);
5887
5888 len = sprintf(buf, "%s:", ioc->name);
5889 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5890 len += sprintf(buf+len, " (f/w download boot flag set)");
5891// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5892// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5893
5894 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5895 ioc->facts.ProductID,
5896 ioc->prod_name);
5897 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5898 if (ioc->facts.FWImageSize)
5899 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5900 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5901 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5902 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5903
5904 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5905 ioc->facts.CurrentHostMfaHighAddr);
5906 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5907 ioc->facts.CurrentSenseBufferHighAddr);
5908
5909 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5910 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5911
5912 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5913 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5914 /*
5915 * Rounding UP to nearest 4-kB boundary here...
5916 */
5917 sz = (ioc->req_sz * ioc->req_depth) + 128;
5918 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5919 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5920 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5921 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5922 4*ioc->facts.RequestFrameSize,
5923 ioc->facts.GlobalCredits);
5924
5925 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5926 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5927 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5928 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5929 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5930 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5931 ioc->facts.CurReplyFrameSize,
5932 ioc->facts.ReplyQueueDepth);
5933
5934 len += sprintf(buf+len, " MaxDevices = %d\n",
5935 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5936 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5937
5938 /* per-port info */
5939 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5940 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5941 p+1,
5942 ioc->facts.NumberOfPorts);
5943 if (ioc->bus_type == FC) {
5944 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5945 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5946 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5947 a[5], a[4], a[3], a[2], a[1], a[0]);
5948 }
5949 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5950 ioc->fc_port_page0[p].WWNN.High,
5951 ioc->fc_port_page0[p].WWNN.Low,
5952 ioc->fc_port_page0[p].WWPN.High,
5953 ioc->fc_port_page0[p].WWPN.Low);
5954 }
5955 }
5956
5957 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5958}
5959
5960#endif /* CONFIG_PROC_FS } */
5961
5962/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5963static void
5964mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5965{
5966 buf[0] ='\0';
5967 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5968 sprintf(buf, " (Exp %02d%02d)",
5969 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5970 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5971
5972 /* insider hack! */
5973 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5974 strcat(buf, " [MDBG]");
5975 }
5976}
5977
5978/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5979/**
5980 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5981 * @ioc: Pointer to MPT_ADAPTER structure
5982 * @buffer: Pointer to buffer where IOC summary info should be written
5983 * @size: Pointer to number of bytes we wrote (set by this routine)
5984 * @len: Offset at which to start writing in buffer
5985 * @showlan: Display LAN stuff?
5986 *
5987 * This routine writes (english readable) ASCII text, which represents
5988 * a summary of IOC information, to a buffer.
5989 */
5990void
5991mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5992{
5993 char expVer[32];
5994 int y;
5995
5996 mpt_get_fw_exp_ver(expVer, ioc);
5997
5998 /*
5999 * Shorter summary of attached ioc's...
6000 */
6001 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6002 ioc->name,
6003 ioc->prod_name,
6004 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6005 ioc->facts.FWVersion.Word,
6006 expVer,
6007 ioc->facts.NumberOfPorts,
6008 ioc->req_depth);
6009
6010 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6011 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6012 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6013 a[5], a[4], a[3], a[2], a[1], a[0]);
6014 }
6015
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017
6018 if (!ioc->active)
6019 y += sprintf(buffer+len+y, " (disabled)");
6020
6021 y += sprintf(buffer+len+y, "\n");
6022
6023 *size = y;
6024}
6025
6026/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6027/*
6028 * Reset Handling
6029 */
6030/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6031/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006032 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033 * @ioc: Pointer to MPT_ADAPTER structure
6034 * @sleepFlag: Indicates if sleep or schedule must be called.
6035 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006036 * Issues SCSI Task Management call based on input arg values.
6037 * If TaskMgmt fails, returns associated SCSI request.
6038 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6040 * or a non-interrupt thread. In the former, must not call schedule().
6041 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006042 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043 * FW reload/initialization failed.
6044 *
6045 * Returns 0 for SUCCESS or -1 if FAILED.
6046 */
6047int
6048mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6049{
6050 int rc;
6051 unsigned long flags;
6052
6053 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
6054#ifdef MFCNT
6055 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6056 printk("MF count 0x%x !\n", ioc->mfcnt);
6057#endif
6058
6059 /* Reset the adapter. Prevent more than 1 call to
6060 * mpt_do_ioc_recovery at any instant in time.
6061 */
6062 spin_lock_irqsave(&ioc->diagLock, flags);
6063 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6064 spin_unlock_irqrestore(&ioc->diagLock, flags);
6065 return 0;
6066 } else {
6067 ioc->diagPending = 1;
6068 }
6069 spin_unlock_irqrestore(&ioc->diagLock, flags);
6070
6071 /* FIXME: If do_ioc_recovery fails, repeat....
6072 */
6073
6074 /* The SCSI driver needs to adjust timeouts on all current
6075 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006076 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 * For all other protocol drivers, this is a no-op.
6078 */
6079 {
6080 int ii;
6081 int r = 0;
6082
6083 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6084 if (MptResetHandlers[ii]) {
6085 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
6086 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05006087 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 if (ioc->alt_ioc) {
6089 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
6090 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05006091 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092 }
6093 }
6094 }
6095 }
6096
6097 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
6098 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
6099 rc, ioc->name);
6100 }
6101 ioc->reload_fw = 0;
6102 if (ioc->alt_ioc)
6103 ioc->alt_ioc->reload_fw = 0;
6104
6105 spin_lock_irqsave(&ioc->diagLock, flags);
6106 ioc->diagPending = 0;
6107 if (ioc->alt_ioc)
6108 ioc->alt_ioc->diagPending = 0;
6109 spin_unlock_irqrestore(&ioc->diagLock, flags);
6110
6111 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
6112
6113 return rc;
6114}
6115
6116/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006117static void
6118EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119{
Eric Moore509e5e52006-04-26 13:22:37 -06006120 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006121
6122 switch(event) {
6123 case MPI_EVENT_NONE:
6124 ds = "None";
6125 break;
6126 case MPI_EVENT_LOG_DATA:
6127 ds = "Log Data";
6128 break;
6129 case MPI_EVENT_STATE_CHANGE:
6130 ds = "State Change";
6131 break;
6132 case MPI_EVENT_UNIT_ATTENTION:
6133 ds = "Unit Attention";
6134 break;
6135 case MPI_EVENT_IOC_BUS_RESET:
6136 ds = "IOC Bus Reset";
6137 break;
6138 case MPI_EVENT_EXT_BUS_RESET:
6139 ds = "External Bus Reset";
6140 break;
6141 case MPI_EVENT_RESCAN:
6142 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006143 break;
6144 case MPI_EVENT_LINK_STATUS_CHANGE:
6145 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6146 ds = "Link Status(FAILURE) Change";
6147 else
6148 ds = "Link Status(ACTIVE) Change";
6149 break;
6150 case MPI_EVENT_LOOP_STATE_CHANGE:
6151 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6152 ds = "Loop State(LIP) Change";
6153 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006154 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155 else
Eric Moore509e5e52006-04-26 13:22:37 -06006156 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 break;
6158 case MPI_EVENT_LOGOUT:
6159 ds = "Logout";
6160 break;
6161 case MPI_EVENT_EVENT_CHANGE:
6162 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006163 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006164 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006165 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166 break;
6167 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006168 {
6169 u8 ReasonCode = (u8)(evData0 >> 16);
6170 switch (ReasonCode) {
6171 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6172 ds = "Integrated Raid: Volume Created";
6173 break;
6174 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6175 ds = "Integrated Raid: Volume Deleted";
6176 break;
6177 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6178 ds = "Integrated Raid: Volume Settings Changed";
6179 break;
6180 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6181 ds = "Integrated Raid: Volume Status Changed";
6182 break;
6183 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6184 ds = "Integrated Raid: Volume Physdisk Changed";
6185 break;
6186 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6187 ds = "Integrated Raid: Physdisk Created";
6188 break;
6189 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6190 ds = "Integrated Raid: Physdisk Deleted";
6191 break;
6192 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6193 ds = "Integrated Raid: Physdisk Settings Changed";
6194 break;
6195 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6196 ds = "Integrated Raid: Physdisk Status Changed";
6197 break;
6198 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6199 ds = "Integrated Raid: Domain Validation Needed";
6200 break;
6201 case MPI_EVENT_RAID_RC_SMART_DATA :
6202 ds = "Integrated Raid; Smart Data";
6203 break;
6204 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6205 ds = "Integrated Raid: Replace Action Started";
6206 break;
6207 default:
6208 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006210 }
6211 break;
6212 }
6213 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6214 ds = "SCSI Device Status Change";
6215 break;
6216 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6217 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006218 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006219 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006220 u8 ReasonCode = (u8)(evData0 >> 16);
6221 switch (ReasonCode) {
6222 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006223 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006224 "SAS Device Status Change: Added: "
6225 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006226 break;
6227 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006228 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006229 "SAS Device Status Change: Deleted: "
6230 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006231 break;
6232 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006233 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006234 "SAS Device Status Change: SMART Data: "
6235 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006236 break;
6237 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006238 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006239 "SAS Device Status Change: No Persistancy: "
6240 "id=%d channel=%d", id, channel);
6241 break;
6242 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6243 snprintf(evStr, EVENT_DESCR_STR_SZ,
6244 "SAS Device Status Change: Unsupported Device "
6245 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006246 break;
6247 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6248 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006249 "SAS Device Status Change: Internal Device "
6250 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006251 break;
6252 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6253 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006254 "SAS Device Status Change: Internal Task "
6255 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006256 break;
6257 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6258 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006259 "SAS Device Status Change: Internal Abort "
6260 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006261 break;
6262 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6263 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006264 "SAS Device Status Change: Internal Clear "
6265 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006266 break;
6267 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6268 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006269 "SAS Device Status Change: Internal Query "
6270 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006271 break;
6272 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006273 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006274 "SAS Device Status Change: Unknown: "
6275 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006276 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006277 }
6278 break;
6279 }
6280 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6281 ds = "Bus Timer Expired";
6282 break;
6283 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006284 {
6285 u16 curr_depth = (u16)(evData0 >> 16);
6286 u8 channel = (u8)(evData0 >> 8);
6287 u8 id = (u8)(evData0);
6288
6289 snprintf(evStr, EVENT_DESCR_STR_SZ,
6290 "Queue Full: channel=%d id=%d depth=%d",
6291 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006292 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006293 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006294 case MPI_EVENT_SAS_SES:
6295 ds = "SAS SES Event";
6296 break;
6297 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6298 ds = "Persistent Table Full";
6299 break;
6300 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006301 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006302 u8 LinkRates = (u8)(evData0 >> 8);
6303 u8 PhyNumber = (u8)(evData0);
6304 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6305 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6306 switch (LinkRates) {
6307 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006308 snprintf(evStr, EVENT_DESCR_STR_SZ,
6309 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006310 " Rate Unknown",PhyNumber);
6311 break;
6312 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006313 snprintf(evStr, EVENT_DESCR_STR_SZ,
6314 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006315 " Phy Disabled",PhyNumber);
6316 break;
6317 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006318 snprintf(evStr, EVENT_DESCR_STR_SZ,
6319 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006320 " Failed Speed Nego",PhyNumber);
6321 break;
6322 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006323 snprintf(evStr, EVENT_DESCR_STR_SZ,
6324 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006325 " Sata OOB Completed",PhyNumber);
6326 break;
6327 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006328 snprintf(evStr, EVENT_DESCR_STR_SZ,
6329 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006330 " Rate 1.5 Gbps",PhyNumber);
6331 break;
6332 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006333 snprintf(evStr, EVENT_DESCR_STR_SZ,
6334 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006335 " Rate 3.0 Gpbs",PhyNumber);
6336 break;
6337 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006338 snprintf(evStr, EVENT_DESCR_STR_SZ,
6339 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006340 break;
6341 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006342 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006343 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006344 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6345 ds = "SAS Discovery Error";
6346 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006347 case MPI_EVENT_IR_RESYNC_UPDATE:
6348 {
6349 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006350 snprintf(evStr, EVENT_DESCR_STR_SZ,
6351 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006352 break;
6353 }
6354 case MPI_EVENT_IR2:
6355 {
6356 u8 ReasonCode = (u8)(evData0 >> 16);
6357 switch (ReasonCode) {
6358 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6359 ds = "IR2: LD State Changed";
6360 break;
6361 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6362 ds = "IR2: PD State Changed";
6363 break;
6364 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6365 ds = "IR2: Bad Block Table Full";
6366 break;
6367 case MPI_EVENT_IR2_RC_PD_INSERTED:
6368 ds = "IR2: PD Inserted";
6369 break;
6370 case MPI_EVENT_IR2_RC_PD_REMOVED:
6371 ds = "IR2: PD Removed";
6372 break;
6373 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6374 ds = "IR2: Foreign CFG Detected";
6375 break;
6376 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6377 ds = "IR2: Rebuild Medium Error";
6378 break;
6379 default:
6380 ds = "IR2";
6381 break;
6382 }
6383 break;
6384 }
6385 case MPI_EVENT_SAS_DISCOVERY:
6386 {
6387 if (evData0)
6388 ds = "SAS Discovery: Start";
6389 else
6390 ds = "SAS Discovery: Stop";
6391 break;
6392 }
6393 case MPI_EVENT_LOG_ENTRY_ADDED:
6394 ds = "SAS Log Entry Added";
6395 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006396
Eric Moorec6c727a2007-01-29 09:44:54 -07006397 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6398 {
6399 u8 phy_num = (u8)(evData0);
6400 u8 port_num = (u8)(evData0 >> 8);
6401 u8 port_width = (u8)(evData0 >> 16);
6402 u8 primative = (u8)(evData0 >> 24);
6403 snprintf(evStr, EVENT_DESCR_STR_SZ,
6404 "SAS Broadcase Primative: phy=%d port=%d "
6405 "width=%d primative=0x%02x",
6406 phy_num, port_num, port_width, primative);
6407 break;
6408 }
6409
6410 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6411 {
6412 u8 reason = (u8)(evData0);
6413 u8 port_num = (u8)(evData0 >> 8);
6414 u16 handle = le16_to_cpu(evData0 >> 16);
6415
6416 snprintf(evStr, EVENT_DESCR_STR_SZ,
6417 "SAS Initiator Device Status Change: reason=0x%02x "
6418 "port=%d handle=0x%04x",
6419 reason, port_num, handle);
6420 break;
6421 }
6422
6423 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6424 {
6425 u8 max_init = (u8)(evData0);
6426 u8 current_init = (u8)(evData0 >> 8);
6427
6428 snprintf(evStr, EVENT_DESCR_STR_SZ,
6429 "SAS Initiator Device Table Overflow: max initiators=%02d "
6430 "current initators=%02d",
6431 max_init, current_init);
6432 break;
6433 }
6434 case MPI_EVENT_SAS_SMP_ERROR:
6435 {
6436 u8 status = (u8)(evData0);
6437 u8 port_num = (u8)(evData0 >> 8);
6438 u8 result = (u8)(evData0 >> 16);
6439
6440 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6441 snprintf(evStr, EVENT_DESCR_STR_SZ,
6442 "SAS SMP Error: port=%d result=0x%02x",
6443 port_num, result);
6444 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6445 snprintf(evStr, EVENT_DESCR_STR_SZ,
6446 "SAS SMP Error: port=%d : CRC Error",
6447 port_num);
6448 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6449 snprintf(evStr, EVENT_DESCR_STR_SZ,
6450 "SAS SMP Error: port=%d : Timeout",
6451 port_num);
6452 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6453 snprintf(evStr, EVENT_DESCR_STR_SZ,
6454 "SAS SMP Error: port=%d : No Destination",
6455 port_num);
6456 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6457 snprintf(evStr, EVENT_DESCR_STR_SZ,
6458 "SAS SMP Error: port=%d : Bad Destination",
6459 port_num);
6460 else
6461 snprintf(evStr, EVENT_DESCR_STR_SZ,
6462 "SAS SMP Error: port=%d : status=0x%02x",
6463 port_num, status);
6464 break;
6465 }
6466
Linus Torvalds1da177e2005-04-16 15:20:36 -07006467 /*
6468 * MPT base "custom" events may be added here...
6469 */
6470 default:
6471 ds = "Unknown";
6472 break;
6473 }
Eric Moore509e5e52006-04-26 13:22:37 -06006474 if (ds)
6475 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476}
6477
6478/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006479/**
6480 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006481 * @ioc: Pointer to MPT_ADAPTER structure
6482 * @pEventReply: Pointer to EventNotification reply frame
6483 * @evHandlers: Pointer to integer, number of event handlers
6484 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006485 * Routes a received EventNotificationReply to all currently registered
6486 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006487 * Returns sum of event handlers return values.
6488 */
6489static int
6490ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6491{
6492 u16 evDataLen;
6493 u32 evData0 = 0;
6494// u32 evCtx;
6495 int ii;
6496 int r = 0;
6497 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006498 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006499 u8 event;
6500
6501 /*
6502 * Do platform normalization of values
6503 */
6504 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6505// evCtx = le32_to_cpu(pEventReply->EventContext);
6506 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6507 if (evDataLen) {
6508 evData0 = le32_to_cpu(pEventReply->Data[0]);
6509 }
6510
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006511 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07006512 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006513 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006514 event,
6515 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516
Moore, Eric3a892be2006-03-14 09:14:03 -07006517#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6519 for (ii = 0; ii < evDataLen; ii++)
6520 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6521 printk("\n");
6522#endif
6523
6524 /*
6525 * Do general / base driver event processing
6526 */
6527 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006528 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6529 if (evDataLen) {
6530 u8 evState = evData0 & 0xFF;
6531
6532 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6533
6534 /* Update EventState field in cached IocFacts */
6535 if (ioc->facts.Function) {
6536 ioc->facts.EventState = evState;
6537 }
6538 }
6539 break;
Moore, Ericece50912006-01-16 18:53:19 -07006540 case MPI_EVENT_INTEGRATED_RAID:
6541 mptbase_raid_process_event_data(ioc,
6542 (MpiEventDataRaid_t *)pEventReply->Data);
6543 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006544 default:
6545 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006546 }
6547
6548 /*
6549 * Should this event be logged? Events are written sequentially.
6550 * When buffer is full, start again at the top.
6551 */
6552 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6553 int idx;
6554
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006555 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006556
6557 ioc->events[idx].event = event;
6558 ioc->events[idx].eventContext = ioc->eventContext;
6559
6560 for (ii = 0; ii < 2; ii++) {
6561 if (ii < evDataLen)
6562 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6563 else
6564 ioc->events[idx].data[ii] = 0;
6565 }
6566
6567 ioc->eventContext++;
6568 }
6569
6570
6571 /*
6572 * Call each currently registered protocol event handler.
6573 */
6574 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6575 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006576 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577 ioc->name, ii));
6578 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6579 handlers++;
6580 }
6581 }
6582 /* FIXME? Examine results here? */
6583
6584 /*
6585 * If needed, send (a single) EventAck.
6586 */
6587 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006588 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006589 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006591 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006592 ioc->name, ii));
6593 }
6594 }
6595
6596 *evHandlers = handlers;
6597 return r;
6598}
6599
6600/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006601/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006602 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6603 * @ioc: Pointer to MPT_ADAPTER structure
6604 * @log_info: U32 LogInfo reply word from the IOC
6605 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006606 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006607 */
6608static void
6609mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6610{
Eric Moore7c431e52007-06-13 16:34:36 -06006611 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006612
Eric Moore7c431e52007-06-13 16:34:36 -06006613 switch (log_info & 0xFF000000) {
6614 case MPI_IOCLOGINFO_FC_INIT_BASE:
6615 desc = "FCP Initiator";
6616 break;
6617 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6618 desc = "FCP Target";
6619 break;
6620 case MPI_IOCLOGINFO_FC_LAN_BASE:
6621 desc = "LAN";
6622 break;
6623 case MPI_IOCLOGINFO_FC_MSG_BASE:
6624 desc = "MPI Message Layer";
6625 break;
6626 case MPI_IOCLOGINFO_FC_LINK_BASE:
6627 desc = "FC Link";
6628 break;
6629 case MPI_IOCLOGINFO_FC_CTX_BASE:
6630 desc = "Context Manager";
6631 break;
6632 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6633 desc = "Invalid Field Offset";
6634 break;
6635 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6636 desc = "State Change Info";
6637 break;
6638 }
6639
6640 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6641 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642}
6643
6644/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006645/**
Moore, Eric335a9412006-01-17 17:06:23 -07006646 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006647 * @ioc: Pointer to MPT_ADAPTER structure
6648 * @mr: Pointer to MPT reply frame
6649 * @log_info: U32 LogInfo word from the IOC
6650 *
6651 * Refer to lsi/sp_log.h.
6652 */
6653static void
Moore, Eric335a9412006-01-17 17:06:23 -07006654mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006655{
6656 u32 info = log_info & 0x00FF0000;
6657 char *desc = "unknown";
6658
6659 switch (info) {
6660 case 0x00010000:
6661 desc = "bug! MID not found";
6662 if (ioc->reload_fw == 0)
6663 ioc->reload_fw++;
6664 break;
6665
6666 case 0x00020000:
6667 desc = "Parity Error";
6668 break;
6669
6670 case 0x00030000:
6671 desc = "ASYNC Outbound Overrun";
6672 break;
6673
6674 case 0x00040000:
6675 desc = "SYNC Offset Error";
6676 break;
6677
6678 case 0x00050000:
6679 desc = "BM Change";
6680 break;
6681
6682 case 0x00060000:
6683 desc = "Msg In Overflow";
6684 break;
6685
6686 case 0x00070000:
6687 desc = "DMA Error";
6688 break;
6689
6690 case 0x00080000:
6691 desc = "Outbound DMA Overrun";
6692 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006693
Linus Torvalds1da177e2005-04-16 15:20:36 -07006694 case 0x00090000:
6695 desc = "Task Management";
6696 break;
6697
6698 case 0x000A0000:
6699 desc = "Device Problem";
6700 break;
6701
6702 case 0x000B0000:
6703 desc = "Invalid Phase Change";
6704 break;
6705
6706 case 0x000C0000:
6707 desc = "Untagged Table Size";
6708 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006709
Linus Torvalds1da177e2005-04-16 15:20:36 -07006710 }
6711
6712 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6713}
6714
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006715/* strings for sas loginfo */
6716 static char *originator_str[] = {
6717 "IOP", /* 00h */
6718 "PL", /* 01h */
6719 "IR" /* 02h */
6720 };
6721 static char *iop_code_str[] = {
6722 NULL, /* 00h */
6723 "Invalid SAS Address", /* 01h */
6724 NULL, /* 02h */
6725 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006726 "Diag Message Error", /* 04h */
6727 "Task Terminated", /* 05h */
6728 "Enclosure Management", /* 06h */
6729 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006730 };
6731 static char *pl_code_str[] = {
6732 NULL, /* 00h */
6733 "Open Failure", /* 01h */
6734 "Invalid Scatter Gather List", /* 02h */
6735 "Wrong Relative Offset or Frame Length", /* 03h */
6736 "Frame Transfer Error", /* 04h */
6737 "Transmit Frame Connected Low", /* 05h */
6738 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6739 "SATA Read Log Receive Data Error", /* 07h */
6740 "SATA NCQ Fail All Commands After Error", /* 08h */
6741 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6742 "Receive Frame Invalid Message", /* 0Ah */
6743 "Receive Context Message Valid Error", /* 0Bh */
6744 "Receive Frame Current Frame Error", /* 0Ch */
6745 "SATA Link Down", /* 0Dh */
6746 "Discovery SATA Init W IOS", /* 0Eh */
6747 "Config Invalid Page", /* 0Fh */
6748 "Discovery SATA Init Timeout", /* 10h */
6749 "Reset", /* 11h */
6750 "Abort", /* 12h */
6751 "IO Not Yet Executed", /* 13h */
6752 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006753 "Persistent Reservation Out Not Affiliation "
6754 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006755 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006756 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006757 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006758 NULL, /* 19h */
6759 NULL, /* 1Ah */
6760 NULL, /* 1Bh */
6761 NULL, /* 1Ch */
6762 NULL, /* 1Dh */
6763 NULL, /* 1Eh */
6764 NULL, /* 1Fh */
6765 "Enclosure Management" /* 20h */
6766 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006767 static char *ir_code_str[] = {
6768 "Raid Action Error", /* 00h */
6769 NULL, /* 00h */
6770 NULL, /* 01h */
6771 NULL, /* 02h */
6772 NULL, /* 03h */
6773 NULL, /* 04h */
6774 NULL, /* 05h */
6775 NULL, /* 06h */
6776 NULL /* 07h */
6777 };
6778 static char *raid_sub_code_str[] = {
6779 NULL, /* 00h */
6780 "Volume Creation Failed: Data Passed too "
6781 "Large", /* 01h */
6782 "Volume Creation Failed: Duplicate Volumes "
6783 "Attempted", /* 02h */
6784 "Volume Creation Failed: Max Number "
6785 "Supported Volumes Exceeded", /* 03h */
6786 "Volume Creation Failed: DMA Error", /* 04h */
6787 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6788 "Volume Creation Failed: Error Reading "
6789 "MFG Page 4", /* 06h */
6790 "Volume Creation Failed: Creating Internal "
6791 "Structures", /* 07h */
6792 NULL, /* 08h */
6793 NULL, /* 09h */
6794 NULL, /* 0Ah */
6795 NULL, /* 0Bh */
6796 NULL, /* 0Ch */
6797 NULL, /* 0Dh */
6798 NULL, /* 0Eh */
6799 NULL, /* 0Fh */
6800 "Activation failed: Already Active Volume", /* 10h */
6801 "Activation failed: Unsupported Volume Type", /* 11h */
6802 "Activation failed: Too Many Active Volumes", /* 12h */
6803 "Activation failed: Volume ID in Use", /* 13h */
6804 "Activation failed: Reported Failure", /* 14h */
6805 "Activation failed: Importing a Volume", /* 15h */
6806 NULL, /* 16h */
6807 NULL, /* 17h */
6808 NULL, /* 18h */
6809 NULL, /* 19h */
6810 NULL, /* 1Ah */
6811 NULL, /* 1Bh */
6812 NULL, /* 1Ch */
6813 NULL, /* 1Dh */
6814 NULL, /* 1Eh */
6815 NULL, /* 1Fh */
6816 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6817 "Phys Disk failed: Data Passed too Large", /* 21h */
6818 "Phys Disk failed: DMA Error", /* 22h */
6819 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6820 "Phys Disk failed: Creating Phys Disk Config "
6821 "Page", /* 24h */
6822 NULL, /* 25h */
6823 NULL, /* 26h */
6824 NULL, /* 27h */
6825 NULL, /* 28h */
6826 NULL, /* 29h */
6827 NULL, /* 2Ah */
6828 NULL, /* 2Bh */
6829 NULL, /* 2Ch */
6830 NULL, /* 2Dh */
6831 NULL, /* 2Eh */
6832 NULL, /* 2Fh */
6833 "Compatibility Error: IR Disabled", /* 30h */
6834 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6835 "Compatibility Error: Device not Direct Access "
6836 "Device ", /* 32h */
6837 "Compatibility Error: Removable Device Found", /* 33h */
6838 "Compatibility Error: Device SCSI Version not "
6839 "2 or Higher", /* 34h */
6840 "Compatibility Error: SATA Device, 48 BIT LBA "
6841 "not Supported", /* 35h */
6842 "Compatibility Error: Device doesn't have "
6843 "512 Byte Block Sizes", /* 36h */
6844 "Compatibility Error: Volume Type Check Failed", /* 37h */
6845 "Compatibility Error: Volume Type is "
6846 "Unsupported by FW", /* 38h */
6847 "Compatibility Error: Disk Drive too Small for "
6848 "use in Volume", /* 39h */
6849 "Compatibility Error: Phys Disk for Create "
6850 "Volume not Found", /* 3Ah */
6851 "Compatibility Error: Too Many or too Few "
6852 "Disks for Volume Type", /* 3Bh */
6853 "Compatibility Error: Disk stripe Sizes "
6854 "Must be 64KB", /* 3Ch */
6855 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6856 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006857
6858/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006859/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006860 * mpt_sas_log_info - Log information returned from SAS IOC.
6861 * @ioc: Pointer to MPT_ADAPTER structure
6862 * @log_info: U32 LogInfo reply word from the IOC
6863 *
6864 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006865 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006866static void
6867mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6868{
6869union loginfo_type {
6870 u32 loginfo;
6871 struct {
6872 u32 subcode:16;
6873 u32 code:8;
6874 u32 originator:4;
6875 u32 bus_type:4;
6876 }dw;
6877};
6878 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006879 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006880 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07006881 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006882
6883 sas_loginfo.loginfo = log_info;
6884 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6885 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6886 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07006887
6888 originator_desc = originator_str[sas_loginfo.dw.originator];
6889
6890 switch (sas_loginfo.dw.originator) {
6891
6892 case 0: /* IOP */
6893 if (sas_loginfo.dw.code <
6894 sizeof(iop_code_str)/sizeof(char*))
6895 code_desc = iop_code_str[sas_loginfo.dw.code];
6896 break;
6897 case 1: /* PL */
6898 if (sas_loginfo.dw.code <
6899 sizeof(pl_code_str)/sizeof(char*))
6900 code_desc = pl_code_str[sas_loginfo.dw.code];
6901 break;
6902 case 2: /* IR */
6903 if (sas_loginfo.dw.code >=
6904 sizeof(ir_code_str)/sizeof(char*))
6905 break;
6906 code_desc = ir_code_str[sas_loginfo.dw.code];
6907 if (sas_loginfo.dw.subcode >=
6908 sizeof(raid_sub_code_str)/sizeof(char*))
6909 break;
6910 if (sas_loginfo.dw.code == 0)
6911 sub_code_desc =
6912 raid_sub_code_str[sas_loginfo.dw.subcode];
6913 break;
6914 default:
6915 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006916 }
6917
Eric Moorec6c727a2007-01-29 09:44:54 -07006918 if (sub_code_desc != NULL)
6919 printk(MYIOC_s_INFO_FMT
6920 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6921 " SubCode={%s}\n",
6922 ioc->name, log_info, originator_desc, code_desc,
6923 sub_code_desc);
6924 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006925 printk(MYIOC_s_INFO_FMT
6926 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6927 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07006928 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006929 sas_loginfo.dw.subcode);
6930 else
6931 printk(MYIOC_s_INFO_FMT
6932 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6933 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07006934 ioc->name, log_info, originator_desc,
6935 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006936}
6937
Eric Moorec6c727a2007-01-29 09:44:54 -07006938#ifdef MPT_DEBUG_REPLY
Linus Torvalds1da177e2005-04-16 15:20:36 -07006939/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006940/**
Eric Moorec6c727a2007-01-29 09:44:54 -07006941 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
6942 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08006943 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07006944 * @mf: Pointer to MPT request frame
6945 *
6946 * Refer to lsi/mpi.h.
6947 **/
6948static void
6949mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6950{
6951 Config_t *pReq = (Config_t *)mf;
6952 char extend_desc[EVENT_DESCR_STR_SZ];
6953 char *desc = NULL;
6954 u32 form;
6955 u8 page_type;
6956
6957 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
6958 page_type = pReq->ExtPageType;
6959 else
6960 page_type = pReq->Header.PageType;
6961
6962 /*
6963 * ignore invalid page messages for GET_NEXT_HANDLE
6964 */
6965 form = le32_to_cpu(pReq->PageAddress);
6966 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
6967 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
6968 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
6969 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
6970 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
6971 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
6972 return;
6973 }
6974 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
6975 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
6976 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
6977 return;
6978 }
6979
6980 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
6981 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
6982 page_type, pReq->Header.PageNumber, pReq->Action, form);
6983
6984 switch (ioc_status) {
6985
6986 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6987 desc = "Config Page Invalid Action";
6988 break;
6989
6990 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6991 desc = "Config Page Invalid Type";
6992 break;
6993
6994 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6995 desc = "Config Page Invalid Page";
6996 break;
6997
6998 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6999 desc = "Config Page Invalid Data";
7000 break;
7001
7002 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7003 desc = "Config Page No Defaults";
7004 break;
7005
7006 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7007 desc = "Config Page Can't Commit";
7008 break;
7009 }
7010
7011 if (!desc)
7012 return;
7013
7014 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
7015 ioc->name, ioc_status, desc, extend_desc);
7016}
7017
7018/**
7019 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007020 * @ioc: Pointer to MPT_ADAPTER structure
7021 * @ioc_status: U32 IOCStatus word from IOC
7022 * @mf: Pointer to MPT request frame
7023 *
7024 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007025 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007026static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007027mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007028{
7029 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007030 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007031
7032 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007033
7034/****************************************************************************/
7035/* Common IOCStatus values for all replies */
7036/****************************************************************************/
7037
Linus Torvalds1da177e2005-04-16 15:20:36 -07007038 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7039 desc = "Invalid Function";
7040 break;
7041
7042 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7043 desc = "Busy";
7044 break;
7045
7046 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7047 desc = "Invalid SGL";
7048 break;
7049
7050 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7051 desc = "Internal Error";
7052 break;
7053
7054 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7055 desc = "Reserved";
7056 break;
7057
7058 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7059 desc = "Insufficient Resources";
7060 break;
7061
7062 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7063 desc = "Invalid Field";
7064 break;
7065
7066 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7067 desc = "Invalid State";
7068 break;
7069
Eric Moorec6c727a2007-01-29 09:44:54 -07007070/****************************************************************************/
7071/* Config IOCStatus values */
7072/****************************************************************************/
7073
Linus Torvalds1da177e2005-04-16 15:20:36 -07007074 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7075 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7076 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7077 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7078 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7079 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007080 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007081 break;
7082
Eric Moorec6c727a2007-01-29 09:44:54 -07007083/****************************************************************************/
7084/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7085/* */
7086/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7087/* */
7088/****************************************************************************/
7089
Linus Torvalds1da177e2005-04-16 15:20:36 -07007090 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007091 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007092 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7093 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7094 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7095 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007096 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007097 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007098 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007099 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007100 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007102 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007103 break;
7104
Eric Moorec6c727a2007-01-29 09:44:54 -07007105/****************************************************************************/
7106/* SCSI Target values */
7107/****************************************************************************/
7108
7109 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7110 desc = "Target: Priority IO";
7111 break;
7112
7113 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7114 desc = "Target: Invalid Port";
7115 break;
7116
7117 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7118 desc = "Target Invalid IO Index:";
7119 break;
7120
7121 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7122 desc = "Target: Aborted";
7123 break;
7124
7125 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7126 desc = "Target: No Conn Retryable";
7127 break;
7128
7129 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7130 desc = "Target: No Connection";
7131 break;
7132
7133 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7134 desc = "Target: Transfer Count Mismatch";
7135 break;
7136
7137 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7138 desc = "Target: STS Data not Sent";
7139 break;
7140
7141 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7142 desc = "Target: Data Offset Error";
7143 break;
7144
7145 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7146 desc = "Target: Too Much Write Data";
7147 break;
7148
7149 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7150 desc = "Target: IU Too Short";
7151 break;
7152
7153 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7154 desc = "Target: ACK NAK Timeout";
7155 break;
7156
7157 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7158 desc = "Target: Nak Received";
7159 break;
7160
7161/****************************************************************************/
7162/* Fibre Channel Direct Access values */
7163/****************************************************************************/
7164
7165 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7166 desc = "FC: Aborted";
7167 break;
7168
7169 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7170 desc = "FC: RX ID Invalid";
7171 break;
7172
7173 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7174 desc = "FC: DID Invalid";
7175 break;
7176
7177 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7178 desc = "FC: Node Logged Out";
7179 break;
7180
7181 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7182 desc = "FC: Exchange Canceled";
7183 break;
7184
7185/****************************************************************************/
7186/* LAN values */
7187/****************************************************************************/
7188
7189 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7190 desc = "LAN: Device not Found";
7191 break;
7192
7193 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7194 desc = "LAN: Device Failure";
7195 break;
7196
7197 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7198 desc = "LAN: Transmit Error";
7199 break;
7200
7201 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7202 desc = "LAN: Transmit Aborted";
7203 break;
7204
7205 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7206 desc = "LAN: Receive Error";
7207 break;
7208
7209 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7210 desc = "LAN: Receive Aborted";
7211 break;
7212
7213 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7214 desc = "LAN: Partial Packet";
7215 break;
7216
7217 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7218 desc = "LAN: Canceled";
7219 break;
7220
7221/****************************************************************************/
7222/* Serial Attached SCSI values */
7223/****************************************************************************/
7224
7225 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7226 desc = "SAS: SMP Request Failed";
7227 break;
7228
7229 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7230 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007231 break;
7232
7233 default:
7234 desc = "Others";
7235 break;
7236 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007237
7238 if (!desc)
7239 return;
7240
7241 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007242}
Eric Moorec6c727a2007-01-29 09:44:54 -07007243#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244
7245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007246EXPORT_SYMBOL(mpt_attach);
7247EXPORT_SYMBOL(mpt_detach);
7248#ifdef CONFIG_PM
7249EXPORT_SYMBOL(mpt_resume);
7250EXPORT_SYMBOL(mpt_suspend);
7251#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007252EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007253EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007254EXPORT_SYMBOL(mpt_register);
7255EXPORT_SYMBOL(mpt_deregister);
7256EXPORT_SYMBOL(mpt_event_register);
7257EXPORT_SYMBOL(mpt_event_deregister);
7258EXPORT_SYMBOL(mpt_reset_register);
7259EXPORT_SYMBOL(mpt_reset_deregister);
7260EXPORT_SYMBOL(mpt_device_driver_register);
7261EXPORT_SYMBOL(mpt_device_driver_deregister);
7262EXPORT_SYMBOL(mpt_get_msg_frame);
7263EXPORT_SYMBOL(mpt_put_msg_frame);
7264EXPORT_SYMBOL(mpt_free_msg_frame);
7265EXPORT_SYMBOL(mpt_add_sge);
7266EXPORT_SYMBOL(mpt_send_handshake_request);
7267EXPORT_SYMBOL(mpt_verify_adapter);
7268EXPORT_SYMBOL(mpt_GetIocState);
7269EXPORT_SYMBOL(mpt_print_ioc_summary);
7270EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007271EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007272EXPORT_SYMBOL(mpt_HardResetHandler);
7273EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007274EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007275EXPORT_SYMBOL(mpt_alloc_fw_memory);
7276EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007277EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007278EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007279
Linus Torvalds1da177e2005-04-16 15:20:36 -07007280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007281/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007282 * fusion_init - Fusion MPT base driver initialization routine.
7283 *
7284 * Returns 0 for success, non-zero for failure.
7285 */
7286static int __init
7287fusion_init(void)
7288{
7289 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290
7291 show_mptmod_ver(my_NAME, my_VERSION);
7292 printk(KERN_INFO COPYRIGHT "\n");
7293
7294 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
7295 MptCallbacks[i] = NULL;
7296 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
7297 MptEvHandlers[i] = NULL;
7298 MptResetHandlers[i] = NULL;
7299 }
7300
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007301 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007302 * EventNotification handling.
7303 */
7304 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7305
7306 /* Register for hard reset handling callbacks.
7307 */
7308 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
7309 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
7310 } else {
7311 /* FIXME! */
7312 }
7313
7314#ifdef CONFIG_PROC_FS
7315 (void) procmpt_create();
7316#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007317 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007318}
7319
7320/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007321/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007322 * fusion_exit - Perform driver unload cleanup.
7323 *
7324 * This routine frees all resources associated with each MPT adapter
7325 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7326 */
7327static void __exit
7328fusion_exit(void)
7329{
7330
7331 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
7332
Linus Torvalds1da177e2005-04-16 15:20:36 -07007333 mpt_reset_deregister(mpt_base_index);
7334
7335#ifdef CONFIG_PROC_FS
7336 procmpt_destroy();
7337#endif
7338}
7339
Linus Torvalds1da177e2005-04-16 15:20:36 -07007340module_init(fusion_init);
7341module_exit(fusion_exit);