blob: 9080853fe283554c986f6636b34ee3bc42008b43 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
7 *
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * (mailto:mpt_linux_developer@lsil.com)
10 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
49#include <linux/config.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/kernel.h>
51#include <linux/module.h>
52#include <linux/errno.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/types.h>
56#include <linux/pci.h>
57#include <linux/kdev_t.h>
58#include <linux/blkdev.h>
59#include <linux/delay.h>
60#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040061#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/io.h>
63#ifdef CONFIG_MTRR
64#include <asm/mtrr.h>
65#endif
66#ifdef __sparc__
67#include <asm/irq.h> /* needed for __irq_itoa() proto */
68#endif
69
70#include "mptbase.h"
71
72/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73#define my_NAME "Fusion MPT base driver"
74#define my_VERSION MPT_LINUX_VERSION_COMMON
75#define MYNAM "mptbase"
76
77MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
80
81/*
82 * cmd line parameters
83 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000084static int mpt_msi_enable;
85module_param(mpt_msi_enable, int, 0);
86MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#ifdef MFCNT
89static int mfcounter = 0;
90#define PRINT_MF_COUNT 20000
91#endif
92
93/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
94/*
95 * Public data...
96 */
97int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080098int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Linus Torvaldsf7473072005-11-29 14:21:57 -0800100struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102#define WHOINIT_UNKNOWN 0xAA
103
104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
105/*
106 * Private data...
107 */
108 /* Adapter link list */
109LIST_HEAD(ioc_list);
110 /* Callback lookup table */
111static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
112 /* Protocol driver class lookup table */
113static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
114 /* Event handler lookup table */
115static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
116 /* Reset handler lookup table */
117static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
118static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
119
120static int mpt_base_index = -1;
121static int last_drv_idx = -1;
122
123static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
124
125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
126/*
127 * Forward protos...
128 */
129static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
130static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
131static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
132 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
133 int sleepFlag);
134static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
135static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
136static void mpt_adapter_disable(MPT_ADAPTER *ioc);
137static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
138
139static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
140static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
142static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
143static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
144static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
145static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200146static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
148static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
149static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
150static int PrimeIocFifos(MPT_ADAPTER *ioc);
151static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
152static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
153static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
154static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200156int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
158static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
159static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
160static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
161static void mpt_timer_expired(unsigned long data);
162static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
163static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200164static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
165static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167#ifdef CONFIG_PROC_FS
168static int procmpt_summary_read(char *buf, char **start, off_t offset,
169 int request, int *eof, void *data);
170static int procmpt_version_read(char *buf, char **start, off_t offset,
171 int request, int *eof, void *data);
172static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
173 int request, int *eof, void *data);
174#endif
175static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
176
177//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
178static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
179static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
180static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700181static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600182static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700183static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186static int __init fusion_init (void);
187static void __exit fusion_exit (void);
188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189#define CHIPREG_READ32(addr) readl_relaxed(addr)
190#define CHIPREG_READ32_dmasync(addr) readl(addr)
191#define CHIPREG_WRITE32(addr,val) writel(val, addr)
192#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
193#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
194
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600195static void
196pci_disable_io_access(struct pci_dev *pdev)
197{
198 u16 command_reg;
199
200 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
201 command_reg &= ~1;
202 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
203}
204
205static void
206pci_enable_io_access(struct pci_dev *pdev)
207{
208 u16 command_reg;
209
210 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
211 command_reg |= 1;
212 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
213}
214
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600215/*
216 * Process turbo (context) reply...
217 */
218static void
219mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
220{
221 MPT_FRAME_HDR *mf = NULL;
222 MPT_FRAME_HDR *mr = NULL;
223 int req_idx = 0;
224 int cb_idx;
225
226 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
227 ioc->name, pa));
228
229 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
230 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
231 req_idx = pa & 0x0000FFFF;
232 cb_idx = (pa & 0x00FF0000) >> 16;
233 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
234 break;
235 case MPI_CONTEXT_REPLY_TYPE_LAN:
236 cb_idx = mpt_lan_index;
237 /*
238 * Blind set of mf to NULL here was fatal
239 * after lan_reply says "freeme"
240 * Fix sort of combined with an optimization here;
241 * added explicit check for case where lan_reply
242 * was just returning 1 and doing nothing else.
243 * For this case skip the callback, but set up
244 * proper mf value first here:-)
245 */
246 if ((pa & 0x58000000) == 0x58000000) {
247 req_idx = pa & 0x0000FFFF;
248 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
249 mpt_free_msg_frame(ioc, mf);
250 mb();
251 return;
252 break;
253 }
254 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
255 break;
256 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
257 cb_idx = mpt_stm_index;
258 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
259 break;
260 default:
261 cb_idx = 0;
262 BUG();
263 }
264
265 /* Check for (valid) IO callback! */
266 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
267 MptCallbacks[cb_idx] == NULL) {
268 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
269 __FUNCTION__, ioc->name, cb_idx);
270 goto out;
271 }
272
273 if (MptCallbacks[cb_idx](ioc, mf, mr))
274 mpt_free_msg_frame(ioc, mf);
275 out:
276 mb();
277}
278
279static void
280mpt_reply(MPT_ADAPTER *ioc, u32 pa)
281{
282 MPT_FRAME_HDR *mf;
283 MPT_FRAME_HDR *mr;
284 int req_idx;
285 int cb_idx;
286 int freeme;
287
288 u32 reply_dma_low;
289 u16 ioc_stat;
290
291 /* non-TURBO reply! Hmmm, something may be up...
292 * Newest turbo reply mechanism; get address
293 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
294 */
295
296 /* Map DMA address of reply header to cpu address.
297 * pa is 32 bits - but the dma address may be 32 or 64 bits
298 * get offset based only only the low addresses
299 */
300
301 reply_dma_low = (pa <<= 1);
302 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
303 (reply_dma_low - ioc->reply_frames_low_dma));
304
305 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
306 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
307 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
308
309 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
310 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
311 DBG_DUMP_REPLY_FRAME(mr)
312
313 /* Check/log IOC log info
314 */
315 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
316 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
317 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
318 if (ioc->bus_type == FC)
319 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700320 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700321 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600322 else if (ioc->bus_type == SAS)
323 mpt_sas_log_info(ioc, log_info);
324 }
325 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700326 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600327 cb_idx != mpt_stm_index &&
328 cb_idx != mpt_lan_index)
329 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
330 }
331
332
333 /* Check for (valid) IO callback! */
334 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
335 MptCallbacks[cb_idx] == NULL) {
336 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
337 __FUNCTION__, ioc->name, cb_idx);
338 freeme = 0;
339 goto out;
340 }
341
342 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
343
344 out:
345 /* Flush (non-TURBO) reply with a WRITE! */
346 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
347
348 if (freeme)
349 mpt_free_msg_frame(ioc, mf);
350 mb();
351}
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
354/*
355 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
356 * @irq: irq number (not used)
357 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
358 * @r: pt_regs pointer (not used)
359 *
360 * This routine is registered via the request_irq() kernel API call,
361 * and handles all interrupts generated from a specific MPT adapter
362 * (also referred to as a IO Controller or IOC).
363 * This routine must clear the interrupt from the adapter and does
364 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200365 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 *
367 * This routine handles register-level access of the adapter but
368 * dispatches (calls) a protocol-specific callback routine to handle
369 * the protocol-specific details of the MPT request completion.
370 */
371static irqreturn_t
372mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
373{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600374 MPT_ADAPTER *ioc = bus_id;
375 u32 pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 /*
378 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 */
380 while (1) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600381 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
382 if (pa == 0xFFFFFFFF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 return IRQ_HANDLED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600384 else if (pa & MPI_ADDRESS_REPLY_A_BIT)
385 mpt_reply(ioc, pa);
386 else
387 mpt_turbo_reply(ioc, pa);
388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390 return IRQ_HANDLED;
391}
392
393/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
394/*
395 * mpt_base_reply - MPT base driver's callback routine; all base driver
396 * "internal" request/reply processing is routed here.
397 * Currently used for EventNotification and EventAck handling.
398 * @ioc: Pointer to MPT_ADAPTER structure
399 * @mf: Pointer to original MPT request frame
400 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
401 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200402 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 * should be freed, or 0 if it shouldn't.
404 */
405static int
406mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
407{
408 int freereq = 1;
409 u8 func;
410
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200411 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200413#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
415 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
416 DBG_DUMP_REQUEST_FRAME_HDR(mf)
417 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200418#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
420 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200421 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 ioc->name, func));
423
424 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
425 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
426 int evHandlers = 0;
427 int results;
428
429 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
430 if (results != evHandlers) {
431 /* CHECKME! Any special handling needed here? */
Moore, Eric3a892be2006-03-14 09:14:03 -0700432 devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 ioc->name, evHandlers, results));
434 }
435
436 /*
437 * Hmmm... It seems that EventNotificationReply is an exception
438 * to the rule of one reply per request.
439 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200440 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 freereq = 0;
Moore, Eric3a892be2006-03-14 09:14:03 -0700442 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200443 ioc->name, pEvReply));
444 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700445 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200446 ioc->name, pEvReply));
447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449#ifdef CONFIG_PROC_FS
450// LogEvent(ioc, pEvReply);
451#endif
452
453 } else if (func == MPI_FUNCTION_EVENT_ACK) {
454 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
455 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700456 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 CONFIGPARMS *pCfg;
458 unsigned long flags;
459
460 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
461 ioc->name, mf, reply));
462
463 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
464
465 if (pCfg) {
466 /* disable timer and remove from linked list */
467 del_timer(&pCfg->timer);
468
469 spin_lock_irqsave(&ioc->FreeQlock, flags);
470 list_del(&pCfg->linkage);
471 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
472
473 /*
474 * If IOC Status is SUCCESS, save the header
475 * and set the status code to GOOD.
476 */
477 pCfg->status = MPT_CONFIG_ERROR;
478 if (reply) {
479 ConfigReply_t *pReply = (ConfigReply_t *)reply;
480 u16 status;
481
482 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
483 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
484 status, le32_to_cpu(pReply->IOCLogInfo)));
485
486 pCfg->status = status;
487 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200488 if ((pReply->Header.PageType &
489 MPI_CONFIG_PAGETYPE_MASK) ==
490 MPI_CONFIG_PAGETYPE_EXTENDED) {
491 pCfg->cfghdr.ehdr->ExtPageLength =
492 le16_to_cpu(pReply->ExtPageLength);
493 pCfg->cfghdr.ehdr->ExtPageType =
494 pReply->ExtPageType;
495 }
496 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
497
498 /* If this is a regular header, save PageLength. */
499 /* LMP Do this better so not using a reserved field! */
500 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
501 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
502 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 }
504 }
505
506 /*
507 * Wake up the original calling thread
508 */
509 pCfg->wait_done = 1;
510 wake_up(&mpt_waitq);
511 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200512 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
513 /* we should be always getting a reply frame */
514 memcpy(ioc->persist_reply_frame, reply,
515 min(MPT_DEFAULT_FRAME_SIZE,
516 4*reply->u.reply.MsgLength));
517 del_timer(&ioc->persist_timer);
518 ioc->persist_wait_done = 1;
519 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 } else {
521 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
522 ioc->name, func);
523 }
524
525 /*
526 * Conditionally tell caller to free the original
527 * EventNotification/EventAck/unexpected request frame!
528 */
529 return freereq;
530}
531
532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
533/**
534 * mpt_register - Register protocol-specific main callback handler.
535 * @cbfunc: callback function pointer
536 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
537 *
538 * This routine is called by a protocol-specific driver (SCSI host,
539 * LAN, SCSI target) to register it's reply callback routine. Each
540 * protocol-specific driver must do this before it will be able to
541 * use any IOC resources, such as obtaining request frames.
542 *
543 * NOTES: The SCSI protocol driver currently calls this routine thrice
544 * in order to register separate callbacks; one for "normal" SCSI IO;
545 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
546 *
547 * Returns a positive integer valued "handle" in the
548 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
549 * Any non-positive return value (including zero!) should be considered
550 * an error by the caller.
551 */
552int
553mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
554{
555 int i;
556
557 last_drv_idx = -1;
558
559 /*
560 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
561 * (slot/handle 0 is reserved!)
562 */
563 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
564 if (MptCallbacks[i] == NULL) {
565 MptCallbacks[i] = cbfunc;
566 MptDriverClass[i] = dclass;
567 MptEvHandlers[i] = NULL;
568 last_drv_idx = i;
569 break;
570 }
571 }
572
573 return last_drv_idx;
574}
575
576/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
577/**
578 * mpt_deregister - Deregister a protocol drivers resources.
579 * @cb_idx: previously registered callback handle
580 *
581 * Each protocol-specific driver should call this routine when it's
582 * module is unloaded.
583 */
584void
585mpt_deregister(int cb_idx)
586{
587 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
588 MptCallbacks[cb_idx] = NULL;
589 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
590 MptEvHandlers[cb_idx] = NULL;
591
592 last_drv_idx++;
593 }
594}
595
596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
597/**
598 * mpt_event_register - Register protocol-specific event callback
599 * handler.
600 * @cb_idx: previously registered (via mpt_register) callback handle
601 * @ev_cbfunc: callback function
602 *
603 * This routine can be called by one or more protocol-specific drivers
604 * if/when they choose to be notified of MPT events.
605 *
606 * Returns 0 for success.
607 */
608int
609mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
610{
611 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
612 return -1;
613
614 MptEvHandlers[cb_idx] = ev_cbfunc;
615 return 0;
616}
617
618/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
619/**
620 * mpt_event_deregister - Deregister protocol-specific event callback
621 * handler.
622 * @cb_idx: previously registered callback handle
623 *
624 * Each protocol-specific driver should call this routine
625 * when it does not (or can no longer) handle events,
626 * or when it's module is unloaded.
627 */
628void
629mpt_event_deregister(int cb_idx)
630{
631 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
632 return;
633
634 MptEvHandlers[cb_idx] = NULL;
635}
636
637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
638/**
639 * mpt_reset_register - Register protocol-specific IOC reset handler.
640 * @cb_idx: previously registered (via mpt_register) callback handle
641 * @reset_func: reset function
642 *
643 * This routine can be called by one or more protocol-specific drivers
644 * if/when they choose to be notified of IOC resets.
645 *
646 * Returns 0 for success.
647 */
648int
649mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
650{
651 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
652 return -1;
653
654 MptResetHandlers[cb_idx] = reset_func;
655 return 0;
656}
657
658/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
659/**
660 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
661 * @cb_idx: previously registered callback handle
662 *
663 * Each protocol-specific driver should call this routine
664 * when it does not (or can no longer) handle IOC reset handling,
665 * or when it's module is unloaded.
666 */
667void
668mpt_reset_deregister(int cb_idx)
669{
670 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
671 return;
672
673 MptResetHandlers[cb_idx] = NULL;
674}
675
676/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
677/**
678 * mpt_device_driver_register - Register device driver hooks
679 */
680int
681mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
682{
683 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400686 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688
689 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
690
691 /* call per pci device probe entry point */
692 list_for_each_entry(ioc, &ioc_list, list) {
693 if(dd_cbfunc->probe) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400694 dd_cbfunc->probe(ioc->pcidev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 ioc->pcidev->driver->id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 }
697 }
698
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400699 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
702/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
703/**
704 * mpt_device_driver_deregister - DeRegister device driver hooks
705 */
706void
707mpt_device_driver_deregister(int cb_idx)
708{
709 struct mpt_pci_driver *dd_cbfunc;
710 MPT_ADAPTER *ioc;
711
712 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
713 return;
714
715 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
716
717 list_for_each_entry(ioc, &ioc_list, list) {
718 if (dd_cbfunc->remove)
719 dd_cbfunc->remove(ioc->pcidev);
720 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 MptDeviceDriverHandlers[cb_idx] = NULL;
723}
724
725
726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
727/**
728 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
729 * allocated per MPT adapter.
730 * @handle: Handle of registered MPT protocol driver
731 * @ioc: Pointer to MPT adapter structure
732 *
733 * Returns pointer to a MPT request frame or %NULL if none are available
734 * or IOC is not active.
735 */
736MPT_FRAME_HDR*
737mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
738{
739 MPT_FRAME_HDR *mf;
740 unsigned long flags;
741 u16 req_idx; /* Request index */
742
743 /* validate handle and ioc identifier */
744
745#ifdef MFCNT
746 if (!ioc->active)
747 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
748#endif
749
750 /* If interrupts are not attached, do not return a request frame */
751 if (!ioc->active)
752 return NULL;
753
754 spin_lock_irqsave(&ioc->FreeQlock, flags);
755 if (!list_empty(&ioc->FreeQ)) {
756 int req_offset;
757
758 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
759 u.frame.linkage.list);
760 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200761 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
763 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
764 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500765 req_idx = req_offset / ioc->req_sz;
766 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
768 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
769#ifdef MFCNT
770 ioc->mfcnt++;
771#endif
772 }
773 else
774 mf = NULL;
775 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
776
777#ifdef MFCNT
778 if (mf == NULL)
779 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
780 mfcounter++;
781 if (mfcounter == PRINT_MF_COUNT)
782 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
783#endif
784
785 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
786 ioc->name, handle, ioc->id, mf));
787 return mf;
788}
789
790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
791/**
792 * mpt_put_msg_frame - Send a protocol specific MPT request frame
793 * to a IOC.
794 * @handle: Handle of registered MPT protocol driver
795 * @ioc: Pointer to MPT adapter structure
796 * @mf: Pointer to MPT request frame
797 *
798 * This routine posts a MPT request frame to the request post FIFO of a
799 * specific MPT adapter.
800 */
801void
802mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
803{
804 u32 mf_dma_addr;
805 int req_offset;
806 u16 req_idx; /* Request index */
807
808 /* ensure values are reset properly! */
809 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
810 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
811 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500812 req_idx = req_offset / ioc->req_sz;
813 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
815
816#ifdef MPT_DEBUG_MSG_FRAME
817 {
818 u32 *m = mf->u.frame.hwhdr.__hdr;
819 int ii, n;
820
821 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
822 ioc->name, m);
823 n = ioc->req_sz/4 - 1;
824 while (m[n] == 0)
825 n--;
826 for (ii=0; ii<=n; ii++) {
827 if (ii && ((ii%8)==0))
828 printk("\n" KERN_INFO " ");
829 printk(" %08x", le32_to_cpu(m[ii]));
830 }
831 printk("\n");
832 }
833#endif
834
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200835 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
837 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
838}
839
840/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
841/**
842 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
843 * @handle: Handle of registered MPT protocol driver
844 * @ioc: Pointer to MPT adapter structure
845 * @mf: Pointer to MPT request frame
846 *
847 * This routine places a MPT request frame back on the MPT adapter's
848 * FreeQ.
849 */
850void
851mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
852{
853 unsigned long flags;
854
855 /* Put Request back on FreeQ! */
856 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200857 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
859#ifdef MFCNT
860 ioc->mfcnt--;
861#endif
862 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
863}
864
865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
866/**
867 * mpt_add_sge - Place a simple SGE at address pAddr.
868 * @pAddr: virtual address for SGE
869 * @flagslength: SGE flags and data transfer length
870 * @dma_addr: Physical address
871 *
872 * This routine places a MPT request frame back on the MPT adapter's
873 * FreeQ.
874 */
875void
876mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
877{
878 if (sizeof(dma_addr_t) == sizeof(u64)) {
879 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
880 u32 tmp = dma_addr & 0xFFFFFFFF;
881
882 pSge->FlagsLength = cpu_to_le32(flagslength);
883 pSge->Address.Low = cpu_to_le32(tmp);
884 tmp = (u32) ((u64)dma_addr >> 32);
885 pSge->Address.High = cpu_to_le32(tmp);
886
887 } else {
888 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
889 pSge->FlagsLength = cpu_to_le32(flagslength);
890 pSge->Address = cpu_to_le32(dma_addr);
891 }
892}
893
894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
895/**
896 * mpt_send_handshake_request - Send MPT request via doorbell
897 * handshake method.
898 * @handle: Handle of registered MPT protocol driver
899 * @ioc: Pointer to MPT adapter structure
900 * @reqBytes: Size of the request in bytes
901 * @req: Pointer to MPT request frame
902 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
903 *
904 * This routine is used exclusively to send MptScsiTaskMgmt
905 * requests since they are required to be sent via doorbell handshake.
906 *
907 * NOTE: It is the callers responsibility to byte-swap fields in the
908 * request which are greater than 1 byte in size.
909 *
910 * Returns 0 for success, non-zero for failure.
911 */
912int
913mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
914{
915 int r = 0;
916 u8 *req_as_bytes;
917 int ii;
918
919 /* State is known to be good upon entering
920 * this function so issue the bus reset
921 * request.
922 */
923
924 /*
925 * Emulate what mpt_put_msg_frame() does /wrt to sanity
926 * setting cb_idx/req_idx. But ONLY if this request
927 * is in proper (pre-alloc'd) request buffer range...
928 */
929 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
930 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
931 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
932 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
933 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
934 }
935
936 /* Make sure there are no doorbells */
937 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 CHIPREG_WRITE32(&ioc->chip->Doorbell,
940 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
941 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
942
943 /* Wait for IOC doorbell int */
944 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
945 return ii;
946 }
947
948 /* Read doorbell and check for active bit */
949 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
950 return -5;
951
952 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200953 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
956
957 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
958 return -2;
959 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 /* Send request via doorbell handshake */
962 req_as_bytes = (u8 *) req;
963 for (ii = 0; ii < reqBytes/4; ii++) {
964 u32 word;
965
966 word = ((req_as_bytes[(ii*4) + 0] << 0) |
967 (req_as_bytes[(ii*4) + 1] << 8) |
968 (req_as_bytes[(ii*4) + 2] << 16) |
969 (req_as_bytes[(ii*4) + 3] << 24));
970 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
971 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
972 r = -3;
973 break;
974 }
975 }
976
977 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
978 r = 0;
979 else
980 r = -4;
981
982 /* Make sure there are no doorbells */
983 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return r;
986}
987
988/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
989/**
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200990 * mpt_host_page_access_control - provides mechanism for the host
991 * driver to control the IOC's Host Page Buffer access.
992 * @ioc: Pointer to MPT adapter structure
993 * @access_control_value: define bits below
994 *
995 * Access Control Value - bits[15:12]
996 * 0h Reserved
997 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
998 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
999 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1000 *
1001 * Returns 0 for success, non-zero for failure.
1002 */
1003
1004static int
1005mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1006{
1007 int r = 0;
1008
1009 /* return if in use */
1010 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1011 & MPI_DOORBELL_ACTIVE)
1012 return -1;
1013
1014 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1015
1016 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1017 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1018 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1019 (access_control_value<<12)));
1020
1021 /* Wait for IOC to clear Doorbell Status bit */
1022 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1023 return -2;
1024 }else
1025 return 0;
1026}
1027
1028/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1029/**
1030 * mpt_host_page_alloc - allocate system memory for the fw
1031 * If we already allocated memory in past, then resend the same pointer.
1032 * ioc@: Pointer to pointer to IOC adapter
1033 * ioc_init@: Pointer to ioc init config page
1034 *
1035 * Returns 0 for success, non-zero for failure.
1036 */
1037static int
1038mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1039{
1040 char *psge;
1041 int flags_length;
1042 u32 host_page_buffer_sz=0;
1043
1044 if(!ioc->HostPageBuffer) {
1045
1046 host_page_buffer_sz =
1047 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1048
1049 if(!host_page_buffer_sz)
1050 return 0; /* fw doesn't need any host buffers */
1051
1052 /* spin till we get enough memory */
1053 while(host_page_buffer_sz > 0) {
1054
1055 if((ioc->HostPageBuffer = pci_alloc_consistent(
1056 ioc->pcidev,
1057 host_page_buffer_sz,
1058 &ioc->HostPageBuffer_dma)) != NULL) {
1059
1060 dinitprintk((MYIOC_s_INFO_FMT
1061 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
1062 ioc->name,
1063 ioc->HostPageBuffer,
1064 ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001065 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001066 ioc->alloc_total += host_page_buffer_sz;
1067 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1068 break;
1069 }
1070
1071 host_page_buffer_sz -= (4*1024);
1072 }
1073 }
1074
1075 if(!ioc->HostPageBuffer) {
1076 printk(MYIOC_s_ERR_FMT
1077 "Failed to alloc memory for host_page_buffer!\n",
1078 ioc->name);
1079 return -999;
1080 }
1081
1082 psge = (char *)&ioc_init->HostPageBufferSGE;
1083 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1084 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1085 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1086 MPI_SGE_FLAGS_HOST_TO_IOC |
1087 MPI_SGE_FLAGS_END_OF_BUFFER;
1088 if (sizeof(dma_addr_t) == sizeof(u64)) {
1089 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1090 }
1091 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1092 flags_length |= ioc->HostPageBuffer_sz;
1093 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1094 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1095
1096return 0;
1097}
1098
1099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1100/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
1102 * the associated MPT adapter structure.
1103 * @iocid: IOC unique identifier (integer)
1104 * @iocpp: Pointer to pointer to IOC adapter
1105 *
1106 * Returns iocid and sets iocpp.
1107 */
1108int
1109mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1110{
1111 MPT_ADAPTER *ioc;
1112
1113 list_for_each_entry(ioc,&ioc_list,list) {
1114 if (ioc->id == iocid) {
1115 *iocpp =ioc;
1116 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 *iocpp = NULL;
1121 return -1;
1122}
1123
1124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1125/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001126 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 * @pdev: Pointer to pci_dev structure
1128 *
1129 * This routine performs all the steps necessary to bring the IOC of
1130 * a MPT adapter to a OPERATIONAL state. This includes registering
1131 * memory regions, registering the interrupt, and allocating request
1132 * and reply memory pools.
1133 *
1134 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1135 * MPT adapter.
1136 *
1137 * Returns 0 for success, non-zero for failure.
1138 *
1139 * TODO: Add support for polled controllers
1140 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001141int
1142mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
1144 MPT_ADAPTER *ioc;
1145 u8 __iomem *mem;
1146 unsigned long mem_phys;
1147 unsigned long port;
1148 u32 msize;
1149 u32 psize;
1150 int ii;
1151 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 u8 revision;
1153 u8 pcixcmd;
1154 static int mpt_ids = 0;
1155#ifdef CONFIG_PROC_FS
1156 struct proc_dir_entry *dent, *ent;
1157#endif
1158
1159 if (pci_enable_device(pdev))
1160 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001163
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001164 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 dprintk((KERN_INFO MYNAM
1166 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001167 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1169 return r;
1170 }
1171
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001172 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 dprintk((KERN_INFO MYNAM
1174 ": Using 64 bit consistent mask\n"));
1175 else
1176 dprintk((KERN_INFO MYNAM
1177 ": Not using 64 bit consistent mask\n"));
1178
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001179 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 if (ioc == NULL) {
1181 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1182 return -ENOMEM;
1183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 ioc->alloc_total = sizeof(MPT_ADAPTER);
1185 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1186 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 ioc->pcidev = pdev;
1189 ioc->diagPending = 0;
1190 spin_lock_init(&ioc->diagLock);
Michael Reed05e8ec12006-01-13 14:31:54 -06001191 spin_lock_init(&ioc->fc_rescan_work_lock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001192 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
1194 /* Initialize the event logging.
1195 */
1196 ioc->eventTypes = 0; /* None */
1197 ioc->eventContext = 0;
1198 ioc->eventLogSize = 0;
1199 ioc->events = NULL;
1200
1201#ifdef MFCNT
1202 ioc->mfcnt = 0;
1203#endif
1204
1205 ioc->cached_fw = NULL;
1206
1207 /* Initilize SCSI Config Data structure
1208 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001209 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211 /* Initialize the running configQ head.
1212 */
1213 INIT_LIST_HEAD(&ioc->configQ);
1214
Michael Reed05e8ec12006-01-13 14:31:54 -06001215 /* Initialize the fc rport list head.
1216 */
1217 INIT_LIST_HEAD(&ioc->fc_rports);
1218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 /* Find lookup slot. */
1220 INIT_LIST_HEAD(&ioc->list);
1221 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 mem_phys = msize = 0;
1224 port = psize = 0;
1225 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1226 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1227 /* Get I/O space! */
1228 port = pci_resource_start(pdev, ii);
1229 psize = pci_resource_len(pdev,ii);
1230 } else {
1231 /* Get memmap */
1232 mem_phys = pci_resource_start(pdev, ii);
1233 msize = pci_resource_len(pdev,ii);
1234 break;
1235 }
1236 }
1237 ioc->mem_size = msize;
1238
1239 if (ii == DEVICE_COUNT_RESOURCE) {
1240 printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
1241 kfree(ioc);
1242 return -EINVAL;
1243 }
1244
1245 dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
1246 dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
1247
1248 mem = NULL;
1249 /* Get logical ptr for PciMem0 space */
1250 /*mem = ioremap(mem_phys, msize);*/
1251 mem = ioremap(mem_phys, 0x100);
1252 if (mem == NULL) {
1253 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1254 kfree(ioc);
1255 return -EINVAL;
1256 }
1257 ioc->memmap = mem;
1258 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1259
1260 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1261 &ioc->facts, &ioc->pfacts[0]));
1262
1263 ioc->mem_phys = mem_phys;
1264 ioc->chip = (SYSIF_REGS __iomem *)mem;
1265
1266 /* Save Port IO values in case we need to do downloadboot */
1267 {
1268 u8 *pmem = (u8*)port;
1269 ioc->pio_mem_phys = port;
1270 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1271 }
1272
1273 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1274 ioc->prod_name = "LSIFC909";
1275 ioc->bus_type = FC;
1276 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001277 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 ioc->prod_name = "LSIFC929";
1279 ioc->bus_type = FC;
1280 }
1281 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1282 ioc->prod_name = "LSIFC919";
1283 ioc->bus_type = FC;
1284 }
1285 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1286 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1287 ioc->bus_type = FC;
1288 if (revision < XL_929) {
1289 ioc->prod_name = "LSIFC929X";
1290 /* 929X Chip Fix. Set Split transactions level
1291 * for PCIX. Set MOST bits to zero.
1292 */
1293 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1294 pcixcmd &= 0x8F;
1295 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1296 } else {
1297 ioc->prod_name = "LSIFC929XL";
1298 /* 929XL Chip Fix. Set MMRBC to 0x08.
1299 */
1300 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1301 pcixcmd |= 0x08;
1302 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1303 }
1304 }
1305 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1306 ioc->prod_name = "LSIFC919X";
1307 ioc->bus_type = FC;
1308 /* 919X Chip Fix. Set Split transactions level
1309 * for PCIX. Set MOST bits to zero.
1310 */
1311 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1312 pcixcmd &= 0x8F;
1313 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1314 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001315 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1316 ioc->prod_name = "LSIFC939X";
1317 ioc->bus_type = FC;
1318 ioc->errata_flag_1064 = 1;
1319 }
1320 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1321 ioc->prod_name = "LSIFC949X";
1322 ioc->bus_type = FC;
1323 ioc->errata_flag_1064 = 1;
1324 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001325 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1326 ioc->prod_name = "LSIFC949E";
1327 ioc->bus_type = FC;
1328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1330 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001331 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 /* 1030 Chip Fix. Disable Split transactions
1333 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1334 */
1335 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1336 if (revision < C0_1030) {
1337 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1338 pcixcmd &= 0x8F;
1339 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1340 }
1341 }
1342 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1343 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001344 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001346 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1347 ioc->prod_name = "LSISAS1064";
1348 ioc->bus_type = SAS;
1349 ioc->errata_flag_1064 = 1;
1350 }
1351 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) {
1352 ioc->prod_name = "LSISAS1066";
1353 ioc->bus_type = SAS;
1354 ioc->errata_flag_1064 = 1;
1355 }
1356 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1357 ioc->prod_name = "LSISAS1068";
1358 ioc->bus_type = SAS;
1359 ioc->errata_flag_1064 = 1;
1360 }
1361 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1362 ioc->prod_name = "LSISAS1064E";
1363 ioc->bus_type = SAS;
1364 }
1365 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) {
1366 ioc->prod_name = "LSISAS1066E";
1367 ioc->bus_type = SAS;
1368 }
1369 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1370 ioc->prod_name = "LSISAS1068E";
1371 ioc->bus_type = SAS;
1372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001374 if (ioc->errata_flag_1064)
1375 pci_disable_io_access(pdev);
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 sprintf(ioc->name, "ioc%d", ioc->id);
1378
1379 spin_lock_init(&ioc->FreeQlock);
1380
1381 /* Disable all! */
1382 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1383 ioc->active = 0;
1384 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1385
1386 /* Set lookup ptr. */
1387 list_add_tail(&ioc->list, &ioc_list);
1388
1389 ioc->pci_irq = -1;
1390 if (pdev->irq) {
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001391 if (mpt_msi_enable && !pci_enable_msi(pdev))
1392 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", ioc->name);
1393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
1395
1396 if (r < 0) {
1397#ifndef __sparc__
1398 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
1399 ioc->name, pdev->irq);
1400#else
1401 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
1402 ioc->name, __irq_itoa(pdev->irq));
1403#endif
1404 list_del(&ioc->list);
1405 iounmap(mem);
1406 kfree(ioc);
1407 return -EBUSY;
1408 }
1409
1410 ioc->pci_irq = pdev->irq;
1411
1412 pci_set_master(pdev); /* ?? */
1413 pci_set_drvdata(pdev, ioc);
1414
1415#ifndef __sparc__
1416 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
1417#else
1418 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
1419#endif
1420 }
1421
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001422 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 */
1424 mpt_detect_bound_ports(ioc, pdev);
1425
James Bottomleyc92f2222006-03-01 09:02:49 -06001426 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1427 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 printk(KERN_WARNING MYNAM
1429 ": WARNING - %s did not initialize properly! (%d)\n",
1430 ioc->name, r);
1431
1432 list_del(&ioc->list);
1433 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001434 if (mpt_msi_enable)
1435 pci_disable_msi(pdev);
Moore, Eric335a9412006-01-17 17:06:23 -07001436 if (ioc->alt_ioc)
1437 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 iounmap(mem);
1439 kfree(ioc);
1440 pci_set_drvdata(pdev, NULL);
1441 return r;
1442 }
1443
1444 /* call per device driver probe entry point */
1445 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1446 if(MptDeviceDriverHandlers[ii] &&
1447 MptDeviceDriverHandlers[ii]->probe) {
1448 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1449 }
1450 }
1451
1452#ifdef CONFIG_PROC_FS
1453 /*
1454 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1455 */
1456 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1457 if (dent) {
1458 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1459 if (ent) {
1460 ent->read_proc = procmpt_iocinfo_read;
1461 ent->data = ioc;
1462 }
1463 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1464 if (ent) {
1465 ent->read_proc = procmpt_summary_read;
1466 ent->data = ioc;
1467 }
1468 }
1469#endif
1470
1471 return 0;
1472}
1473
1474/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1475/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001476 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 * @pdev: Pointer to pci_dev structure
1478 *
1479 */
1480
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001481void
1482mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
1484 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1485 char pname[32];
1486 int ii;
1487
1488 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1489 remove_proc_entry(pname, NULL);
1490 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1491 remove_proc_entry(pname, NULL);
1492 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1493 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001494
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 /* call per device driver remove entry point */
1496 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1497 if(MptDeviceDriverHandlers[ii] &&
1498 MptDeviceDriverHandlers[ii]->remove) {
1499 MptDeviceDriverHandlers[ii]->remove(pdev);
1500 }
1501 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001502
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 /* Disable interrupts! */
1504 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1505
1506 ioc->active = 0;
1507 synchronize_irq(pdev->irq);
1508
1509 /* Clear any lingering interrupt */
1510 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1511
1512 CHIPREG_READ32(&ioc->chip->IntStatus);
1513
1514 mpt_adapter_dispose(ioc);
1515
1516 pci_set_drvdata(pdev, NULL);
1517}
1518
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519/**************************************************************************
1520 * Power Management
1521 */
1522#ifdef CONFIG_PM
1523/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1524/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001525 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 *
1527 *
1528 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001529int
1530mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531{
1532 u32 device_state;
1533 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
Pavel Machek2a569572005-07-07 17:56:40 -07001535 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 printk(MYIOC_s_INFO_FMT
1538 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1539 ioc->name, pdev, pci_name(pdev), device_state);
1540
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 pci_save_state(pdev);
1542
1543 /* put ioc into READY_STATE */
1544 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1545 printk(MYIOC_s_ERR_FMT
1546 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1547 }
1548
1549 /* disable interrupts */
1550 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1551 ioc->active = 0;
1552
1553 /* Clear any lingering interrupt */
1554 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1555
1556 pci_disable_device(pdev);
1557 pci_set_power_state(pdev, device_state);
1558
1559 return 0;
1560}
1561
1562/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1563/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001564 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 *
1566 *
1567 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001568int
1569mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570{
1571 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1572 u32 device_state = pdev->current_state;
1573 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 printk(MYIOC_s_INFO_FMT
1576 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1577 ioc->name, pdev, pci_name(pdev), device_state);
1578
1579 pci_set_power_state(pdev, 0);
1580 pci_restore_state(pdev);
1581 pci_enable_device(pdev);
1582
1583 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001584 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 ioc->active = 1;
1586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 printk(MYIOC_s_INFO_FMT
1588 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1589 ioc->name,
1590 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1591 CHIPREG_READ32(&ioc->chip->Doorbell));
1592
1593 /* bring ioc to operational state */
1594 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1595 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1596 printk(MYIOC_s_INFO_FMT
1597 "pci-resume: Cannot recover, error:[%x]\n",
1598 ioc->name, recovery_state);
1599 } else {
1600 printk(MYIOC_s_INFO_FMT
1601 "pci-resume: success\n", ioc->name);
1602 }
1603
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 return 0;
1605}
1606#endif
1607
1608/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1609/*
1610 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1611 * @ioc: Pointer to MPT adapter structure
1612 * @reason: Event word / reason
1613 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1614 *
1615 * This routine performs all the steps necessary to bring the IOC
1616 * to a OPERATIONAL state.
1617 *
1618 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1619 * MPT adapter.
1620 *
1621 * Returns:
1622 * 0 for success
1623 * -1 if failed to get board READY
1624 * -2 if READY but IOCFacts Failed
1625 * -3 if READY but PrimeIOCFifos Failed
1626 * -4 if READY but IOCInit Failed
1627 */
1628static int
1629mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1630{
1631 int hard_reset_done = 0;
1632 int alt_ioc_ready = 0;
1633 int hard;
1634 int rc=0;
1635 int ii;
1636 int handlers;
1637 int ret = 0;
1638 int reset_alt_ioc_active = 0;
1639
1640 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1641 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1642
1643 /* Disable reply interrupts (also blocks FreeQ) */
1644 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1645 ioc->active = 0;
1646
1647 if (ioc->alt_ioc) {
1648 if (ioc->alt_ioc->active)
1649 reset_alt_ioc_active = 1;
1650
1651 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1652 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1653 ioc->alt_ioc->active = 0;
1654 }
1655
1656 hard = 1;
1657 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1658 hard = 0;
1659
1660 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1661 if (hard_reset_done == -4) {
1662 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1663 ioc->name);
1664
1665 if (reset_alt_ioc_active && ioc->alt_ioc) {
1666 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1667 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1668 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001669 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 ioc->alt_ioc->active = 1;
1671 }
1672
1673 } else {
1674 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1675 ioc->name);
1676 }
1677 return -1;
1678 }
1679
1680 /* hard_reset_done = 0 if a soft reset was performed
1681 * and 1 if a hard reset was performed.
1682 */
1683 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1684 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1685 alt_ioc_ready = 1;
1686 else
1687 printk(KERN_WARNING MYNAM
1688 ": alt-%s: Not ready WARNING!\n",
1689 ioc->alt_ioc->name);
1690 }
1691
1692 for (ii=0; ii<5; ii++) {
1693 /* Get IOC facts! Allow 5 retries */
1694 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1695 break;
1696 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 if (ii == 5) {
1700 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1701 ret = -2;
1702 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1703 MptDisplayIocCapabilities(ioc);
1704 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001705
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 if (alt_ioc_ready) {
1707 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1708 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1709 /* Retry - alt IOC was initialized once
1710 */
1711 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1712 }
1713 if (rc) {
1714 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1715 alt_ioc_ready = 0;
1716 reset_alt_ioc_active = 0;
1717 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1718 MptDisplayIocCapabilities(ioc->alt_ioc);
1719 }
1720 }
1721
1722 /* Prime reply & request queues!
1723 * (mucho alloc's) Must be done prior to
1724 * init as upper addresses are needed for init.
1725 * If fails, continue with alt-ioc processing
1726 */
1727 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1728 ret = -3;
1729
1730 /* May need to check/upload firmware & data here!
1731 * If fails, continue with alt-ioc processing
1732 */
1733 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1734 ret = -4;
1735// NEW!
1736 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1737 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1738 ioc->alt_ioc->name, rc);
1739 alt_ioc_ready = 0;
1740 reset_alt_ioc_active = 0;
1741 }
1742
1743 if (alt_ioc_ready) {
1744 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1745 alt_ioc_ready = 0;
1746 reset_alt_ioc_active = 0;
1747 printk(KERN_WARNING MYNAM
1748 ": alt-%s: (%d) init failure WARNING!\n",
1749 ioc->alt_ioc->name, rc);
1750 }
1751 }
1752
1753 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1754 if (ioc->upload_fw) {
1755 ddlprintk((MYIOC_s_INFO_FMT
1756 "firmware upload required!\n", ioc->name));
1757
1758 /* Controller is not operational, cannot do upload
1759 */
1760 if (ret == 0) {
1761 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001762 if (rc == 0) {
1763 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1764 /*
1765 * Maintain only one pointer to FW memory
1766 * so there will not be two attempt to
1767 * downloadboot onboard dual function
1768 * chips (mpt_adapter_disable,
1769 * mpt_diag_reset)
1770 */
1771 ioc->cached_fw = NULL;
1772 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1773 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1774 }
1775 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001777 ret = -5;
1778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 }
1780 }
1781 }
1782
1783 if (ret == 0) {
1784 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001785 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 ioc->active = 1;
1787 }
1788
1789 if (reset_alt_ioc_active && ioc->alt_ioc) {
1790 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001791 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001793 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 ioc->alt_ioc->active = 1;
1795 }
1796
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001797 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 * and EventAck handling.
1799 */
1800 if ((ret == 0) && (!ioc->facts.EventState))
1801 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1802
1803 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1804 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1805
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001806 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1808 * recursive scenario; GetLanConfigPages times out, timer expired
1809 * routine calls HardResetHandler, which calls into here again,
1810 * and we try GetLanConfigPages again...
1811 */
1812 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001813 if (ioc->bus_type == SAS) {
1814
1815 /* clear persistency table */
1816 if(ioc->facts.IOCExceptions &
1817 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1818 ret = mptbase_sas_persist_operation(ioc,
1819 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1820 if(ret != 0)
1821 return -1;
1822 }
1823
1824 /* Find IM volumes
1825 */
1826 mpt_findImVolumes(ioc);
1827
1828 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 /*
1830 * Pre-fetch FC port WWN and stuff...
1831 * (FCPortPage0_t stuff)
1832 */
1833 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
Michael Reed05e8ec12006-01-13 14:31:54 -06001834 (void) mptbase_GetFcPortPage0(ioc, ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 }
1836
1837 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1838 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1839 /*
1840 * Pre-fetch the ports LAN MAC address!
1841 * (LANPage1_t stuff)
1842 */
1843 (void) GetLanConfigPages(ioc);
1844#ifdef MPT_DEBUG
1845 {
1846 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1847 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1848 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1849 }
1850#endif
1851 }
1852 } else {
1853 /* Get NVRAM and adapter maximums from SPP 0 and 2
1854 */
1855 mpt_GetScsiPortSettings(ioc, 0);
1856
1857 /* Get version and length of SDP 1
1858 */
1859 mpt_readScsiDevicePageHeaders(ioc, 0);
1860
1861 /* Find IM volumes
1862 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001863 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 mpt_findImVolumes(ioc);
1865
1866 /* Check, and possibly reset, the coalescing value
1867 */
1868 mpt_read_ioc_pg_1(ioc);
1869
1870 mpt_read_ioc_pg_4(ioc);
1871 }
1872
1873 GetIoUnitPage2(ioc);
1874 }
1875
1876 /*
1877 * Call each currently registered protocol IOC reset handler
1878 * with post-reset indication.
1879 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1880 * MptResetHandlers[] registered yet.
1881 */
1882 if (hard_reset_done) {
1883 rc = handlers = 0;
1884 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1885 if ((ret == 0) && MptResetHandlers[ii]) {
1886 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1887 ioc->name, ii));
1888 rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
1889 handlers++;
1890 }
1891
1892 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001893 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 ioc->name, ioc->alt_ioc->name, ii));
1895 rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
1896 handlers++;
1897 }
1898 }
1899 /* FIXME? Examine results here? */
1900 }
1901
1902 return ret;
1903}
1904
1905/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1906/*
1907 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1908 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1909 * 929X, 1030 or 1035.
1910 * @ioc: Pointer to MPT adapter structure
1911 * @pdev: Pointer to (struct pci_dev) structure
1912 *
1913 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1914 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1915 */
1916static void
1917mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1918{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001919 struct pci_dev *peer=NULL;
1920 unsigned int slot = PCI_SLOT(pdev->devfn);
1921 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 MPT_ADAPTER *ioc_srch;
1923
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001924 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1925 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001926 ioc->name, pci_name(pdev), pdev->bus->number,
1927 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001928
1929 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1930 if (!peer) {
1931 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1932 if (!peer)
1933 return;
1934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
1936 list_for_each_entry(ioc_srch, &ioc_list, list) {
1937 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001938 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 /* Paranoia checks */
1940 if (ioc->alt_ioc != NULL) {
1941 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001942 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 break;
1944 } else if (ioc_srch->alt_ioc != NULL) {
1945 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001946 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 break;
1948 }
1949 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001950 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 ioc_srch->alt_ioc = ioc;
1952 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 }
1954 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001955 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956}
1957
1958/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1959/*
1960 * mpt_adapter_disable - Disable misbehaving MPT adapter.
1961 * @this: Pointer to MPT adapter structure
1962 */
1963static void
1964mpt_adapter_disable(MPT_ADAPTER *ioc)
1965{
1966 int sz;
1967 int ret;
1968
1969 if (ioc->cached_fw != NULL) {
1970 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001971 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 printk(KERN_WARNING MYNAM
1973 ": firmware downloadboot failure (%d)!\n", ret);
1974 }
1975 }
1976
1977 /* Disable adapter interrupts! */
1978 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1979 ioc->active = 0;
1980 /* Clear any lingering interrupt */
1981 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1982
1983 if (ioc->alloc != NULL) {
1984 sz = ioc->alloc_sz;
1985 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1986 ioc->name, ioc->alloc, ioc->alloc_sz));
1987 pci_free_consistent(ioc->pcidev, sz,
1988 ioc->alloc, ioc->alloc_dma);
1989 ioc->reply_frames = NULL;
1990 ioc->req_frames = NULL;
1991 ioc->alloc = NULL;
1992 ioc->alloc_total -= sz;
1993 }
1994
1995 if (ioc->sense_buf_pool != NULL) {
1996 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
1997 pci_free_consistent(ioc->pcidev, sz,
1998 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
1999 ioc->sense_buf_pool = NULL;
2000 ioc->alloc_total -= sz;
2001 }
2002
2003 if (ioc->events != NULL){
2004 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2005 kfree(ioc->events);
2006 ioc->events = NULL;
2007 ioc->alloc_total -= sz;
2008 }
2009
2010 if (ioc->cached_fw != NULL) {
2011 sz = ioc->facts.FWImageSize;
2012 pci_free_consistent(ioc->pcidev, sz,
2013 ioc->cached_fw, ioc->cached_fw_dma);
2014 ioc->cached_fw = NULL;
2015 ioc->alloc_total -= sz;
2016 }
2017
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002018 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002019 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002020 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002021 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
2023 if (ioc->spi_data.pIocPg4 != NULL) {
2024 sz = ioc->spi_data.IocPg4Sz;
2025 pci_free_consistent(ioc->pcidev, sz,
2026 ioc->spi_data.pIocPg4,
2027 ioc->spi_data.IocPg4_dma);
2028 ioc->spi_data.pIocPg4 = NULL;
2029 ioc->alloc_total -= sz;
2030 }
2031
2032 if (ioc->ReqToChain != NULL) {
2033 kfree(ioc->ReqToChain);
2034 kfree(ioc->RequestNB);
2035 ioc->ReqToChain = NULL;
2036 }
2037
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002038 kfree(ioc->ChainToChain);
2039 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002040
2041 if (ioc->HostPageBuffer != NULL) {
2042 if((ret = mpt_host_page_access_control(ioc,
2043 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2044 printk(KERN_ERR MYNAM
2045 ": %s: host page buffers free failed (%d)!\n",
2046 __FUNCTION__, ret);
2047 }
2048 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2049 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2050 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2051 ioc->HostPageBuffer,
2052 ioc->HostPageBuffer_dma);
2053 ioc->HostPageBuffer = NULL;
2054 ioc->HostPageBuffer_sz = 0;
2055 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057}
2058
2059/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2060/*
2061 * mpt_adapter_dispose - Free all resources associated with a MPT
2062 * adapter.
2063 * @ioc: Pointer to MPT adapter structure
2064 *
2065 * This routine unregisters h/w resources and frees all alloc'd memory
2066 * associated with a MPT adapter structure.
2067 */
2068static void
2069mpt_adapter_dispose(MPT_ADAPTER *ioc)
2070{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002071 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002073 if (ioc == NULL)
2074 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002076 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002078 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002080 if (ioc->pci_irq != -1) {
2081 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002082 if (mpt_msi_enable)
2083 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002084 ioc->pci_irq = -1;
2085 }
2086
2087 if (ioc->memmap != NULL) {
2088 iounmap(ioc->memmap);
2089 ioc->memmap = NULL;
2090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091
2092#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002093 if (ioc->mtrr_reg > 0) {
2094 mtrr_del(ioc->mtrr_reg, 0, 0);
2095 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097#endif
2098
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002099 /* Zap the adapter lookup ptr! */
2100 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002102 sz_last = ioc->alloc_total;
2103 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2104 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002105
2106 if (ioc->alt_ioc)
2107 ioc->alt_ioc->alt_ioc = NULL;
2108
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002109 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110}
2111
2112/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2113/*
2114 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2115 * @ioc: Pointer to MPT adapter structure
2116 */
2117static void
2118MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2119{
2120 int i = 0;
2121
2122 printk(KERN_INFO "%s: ", ioc->name);
2123 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2124 printk("%s: ", ioc->prod_name+3);
2125 printk("Capabilities={");
2126
2127 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2128 printk("Initiator");
2129 i++;
2130 }
2131
2132 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2133 printk("%sTarget", i ? "," : "");
2134 i++;
2135 }
2136
2137 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2138 printk("%sLAN", i ? "," : "");
2139 i++;
2140 }
2141
2142#if 0
2143 /*
2144 * This would probably evoke more questions than it's worth
2145 */
2146 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2147 printk("%sLogBusAddr", i ? "," : "");
2148 i++;
2149 }
2150#endif
2151
2152 printk("}\n");
2153}
2154
2155/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2156/*
2157 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2158 * @ioc: Pointer to MPT_ADAPTER structure
2159 * @force: Force hard KickStart of IOC
2160 * @sleepFlag: Specifies whether the process can sleep
2161 *
2162 * Returns:
2163 * 1 - DIAG reset and READY
2164 * 0 - READY initially OR soft reset and READY
2165 * -1 - Any failure on KickStart
2166 * -2 - Msg Unit Reset Failed
2167 * -3 - IO Unit Reset Failed
2168 * -4 - IOC owned by a PEER
2169 */
2170static int
2171MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2172{
2173 u32 ioc_state;
2174 int statefault = 0;
2175 int cntdn;
2176 int hard_reset_done = 0;
2177 int r;
2178 int ii;
2179 int whoinit;
2180
2181 /* Get current [raw] IOC state */
2182 ioc_state = mpt_GetIocState(ioc, 0);
2183 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2184
2185 /*
2186 * Check to see if IOC got left/stuck in doorbell handshake
2187 * grip of death. If so, hard reset the IOC.
2188 */
2189 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2190 statefault = 1;
2191 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2192 ioc->name);
2193 }
2194
2195 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002196 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 return 0;
2198
2199 /*
2200 * Check to see if IOC is in FAULT state.
2201 */
2202 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2203 statefault = 2;
2204 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2205 ioc->name);
2206 printk(KERN_WARNING " FAULT code = %04xh\n",
2207 ioc_state & MPI_DOORBELL_DATA_MASK);
2208 }
2209
2210 /*
2211 * Hmmm... Did it get left operational?
2212 */
2213 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002214 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 ioc->name));
2216
2217 /* Check WhoInit.
2218 * If PCI Peer, exit.
2219 * Else, if no fault conditions are present, issue a MessageUnitReset
2220 * Else, fall through to KickStart case
2221 */
2222 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002223 dinitprintk((KERN_INFO MYNAM
2224 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 whoinit, statefault, force));
2226 if (whoinit == MPI_WHOINIT_PCI_PEER)
2227 return -4;
2228 else {
2229 if ((statefault == 0 ) && (force == 0)) {
2230 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2231 return 0;
2232 }
2233 statefault = 3;
2234 }
2235 }
2236
2237 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2238 if (hard_reset_done < 0)
2239 return -1;
2240
2241 /*
2242 * Loop here waiting for IOC to come READY.
2243 */
2244 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002245 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
2247 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2248 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2249 /*
2250 * BIOS or previous driver load left IOC in OP state.
2251 * Reset messaging FIFOs.
2252 */
2253 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2254 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2255 return -2;
2256 }
2257 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2258 /*
2259 * Something is wrong. Try to get IOC back
2260 * to a known state.
2261 */
2262 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2263 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2264 return -3;
2265 }
2266 }
2267
2268 ii++; cntdn--;
2269 if (!cntdn) {
2270 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2271 ioc->name, (int)((ii+5)/HZ));
2272 return -ETIME;
2273 }
2274
2275 if (sleepFlag == CAN_SLEEP) {
2276 msleep_interruptible(1);
2277 } else {
2278 mdelay (1); /* 1 msec delay */
2279 }
2280
2281 }
2282
2283 if (statefault < 3) {
2284 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2285 ioc->name,
2286 statefault==1 ? "stuck handshake" : "IOC FAULT");
2287 }
2288
2289 return hard_reset_done;
2290}
2291
2292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2293/*
2294 * mpt_GetIocState - Get the current state of a MPT adapter.
2295 * @ioc: Pointer to MPT_ADAPTER structure
2296 * @cooked: Request raw or cooked IOC state
2297 *
2298 * Returns all IOC Doorbell register bits if cooked==0, else just the
2299 * Doorbell bits in MPI_IOC_STATE_MASK.
2300 */
2301u32
2302mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2303{
2304 u32 s, sc;
2305
2306 /* Get! */
2307 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2308// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2309 sc = s & MPI_IOC_STATE_MASK;
2310
2311 /* Save! */
2312 ioc->last_state = sc;
2313
2314 return cooked ? sc : s;
2315}
2316
2317/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2318/*
2319 * GetIocFacts - Send IOCFacts request to MPT adapter.
2320 * @ioc: Pointer to MPT_ADAPTER structure
2321 * @sleepFlag: Specifies whether the process can sleep
2322 * @reason: If recovery, only update facts.
2323 *
2324 * Returns 0 for success, non-zero for failure.
2325 */
2326static int
2327GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2328{
2329 IOCFacts_t get_facts;
2330 IOCFactsReply_t *facts;
2331 int r;
2332 int req_sz;
2333 int reply_sz;
2334 int sz;
2335 u32 status, vv;
2336 u8 shiftFactor=1;
2337
2338 /* IOC *must* NOT be in RESET state! */
2339 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2340 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2341 ioc->name,
2342 ioc->last_state );
2343 return -44;
2344 }
2345
2346 facts = &ioc->facts;
2347
2348 /* Destination (reply area)... */
2349 reply_sz = sizeof(*facts);
2350 memset(facts, 0, reply_sz);
2351
2352 /* Request area (get_facts on the stack right now!) */
2353 req_sz = sizeof(get_facts);
2354 memset(&get_facts, 0, req_sz);
2355
2356 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2357 /* Assert: All other get_facts fields are zero! */
2358
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002359 dinitprintk((MYIOC_s_INFO_FMT
2360 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 ioc->name, req_sz, reply_sz));
2362
2363 /* No non-zero fields in the get_facts request are greater than
2364 * 1 byte in size, so we can just fire it off as is.
2365 */
2366 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2367 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2368 if (r != 0)
2369 return r;
2370
2371 /*
2372 * Now byte swap (GRRR) the necessary fields before any further
2373 * inspection of reply contents.
2374 *
2375 * But need to do some sanity checks on MsgLength (byte) field
2376 * to make sure we don't zero IOC's req_sz!
2377 */
2378 /* Did we get a valid reply? */
2379 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2380 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2381 /*
2382 * If not been here, done that, save off first WhoInit value
2383 */
2384 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2385 ioc->FirstWhoInit = facts->WhoInit;
2386 }
2387
2388 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2389 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2390 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2391 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2392 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002393 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 /* CHECKME! IOCStatus, IOCLogInfo */
2395
2396 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2397 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2398
2399 /*
2400 * FC f/w version changed between 1.1 and 1.2
2401 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2402 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2403 */
2404 if (facts->MsgVersion < 0x0102) {
2405 /*
2406 * Handle old FC f/w style, convert to new...
2407 */
2408 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2409 facts->FWVersion.Word =
2410 ((oldv<<12) & 0xFF000000) |
2411 ((oldv<<8) & 0x000FFF00);
2412 } else
2413 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2414
2415 facts->ProductID = le16_to_cpu(facts->ProductID);
2416 facts->CurrentHostMfaHighAddr =
2417 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2418 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2419 facts->CurrentSenseBufferHighAddr =
2420 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2421 facts->CurReplyFrameSize =
2422 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002423 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 /*
2426 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2427 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2428 * to 14 in MPI-1.01.0x.
2429 */
2430 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2431 facts->MsgVersion > 0x0100) {
2432 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2433 }
2434
2435 sz = facts->FWImageSize;
2436 if ( sz & 0x01 )
2437 sz += 1;
2438 if ( sz & 0x02 )
2439 sz += 2;
2440 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002441
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 if (!facts->RequestFrameSize) {
2443 /* Something is wrong! */
2444 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2445 ioc->name);
2446 return -55;
2447 }
2448
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002449 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 vv = ((63 / (sz * 4)) + 1) & 0x03;
2451 ioc->NB_for_64_byte_frame = vv;
2452 while ( sz )
2453 {
2454 shiftFactor++;
2455 sz = sz >> 1;
2456 }
2457 ioc->NBShiftFactor = shiftFactor;
2458 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2459 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002460
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2462 /*
2463 * Set values for this IOC's request & reply frame sizes,
2464 * and request & reply queue depths...
2465 */
2466 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2467 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2468 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2469 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2470
2471 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2472 ioc->name, ioc->reply_sz, ioc->reply_depth));
2473 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2474 ioc->name, ioc->req_sz, ioc->req_depth));
2475
2476 /* Get port facts! */
2477 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2478 return r;
2479 }
2480 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002481 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2483 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2484 RequestFrameSize)/sizeof(u32)));
2485 return -66;
2486 }
2487
2488 return 0;
2489}
2490
2491/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2492/*
2493 * GetPortFacts - Send PortFacts request to MPT adapter.
2494 * @ioc: Pointer to MPT_ADAPTER structure
2495 * @portnum: Port number
2496 * @sleepFlag: Specifies whether the process can sleep
2497 *
2498 * Returns 0 for success, non-zero for failure.
2499 */
2500static int
2501GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2502{
2503 PortFacts_t get_pfacts;
2504 PortFactsReply_t *pfacts;
2505 int ii;
2506 int req_sz;
2507 int reply_sz;
2508
2509 /* IOC *must* NOT be in RESET state! */
2510 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2511 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2512 ioc->name,
2513 ioc->last_state );
2514 return -4;
2515 }
2516
2517 pfacts = &ioc->pfacts[portnum];
2518
2519 /* Destination (reply area)... */
2520 reply_sz = sizeof(*pfacts);
2521 memset(pfacts, 0, reply_sz);
2522
2523 /* Request area (get_pfacts on the stack right now!) */
2524 req_sz = sizeof(get_pfacts);
2525 memset(&get_pfacts, 0, req_sz);
2526
2527 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2528 get_pfacts.PortNumber = portnum;
2529 /* Assert: All other get_pfacts fields are zero! */
2530
2531 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2532 ioc->name, portnum));
2533
2534 /* No non-zero fields in the get_pfacts request are greater than
2535 * 1 byte in size, so we can just fire it off as is.
2536 */
2537 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2538 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2539 if (ii != 0)
2540 return ii;
2541
2542 /* Did we get a valid reply? */
2543
2544 /* Now byte swap the necessary fields in the response. */
2545 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2546 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2547 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2548 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2549 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2550 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2551 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2552 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2553 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2554
2555 return 0;
2556}
2557
2558/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2559/*
2560 * SendIocInit - Send IOCInit request to MPT adapter.
2561 * @ioc: Pointer to MPT_ADAPTER structure
2562 * @sleepFlag: Specifies whether the process can sleep
2563 *
2564 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2565 *
2566 * Returns 0 for success, non-zero for failure.
2567 */
2568static int
2569SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2570{
2571 IOCInit_t ioc_init;
2572 MPIDefaultReply_t init_reply;
2573 u32 state;
2574 int r;
2575 int count;
2576 int cntdn;
2577
2578 memset(&ioc_init, 0, sizeof(ioc_init));
2579 memset(&init_reply, 0, sizeof(init_reply));
2580
2581 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2582 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2583
2584 /* If we are in a recovery mode and we uploaded the FW image,
2585 * then this pointer is not NULL. Skip the upload a second time.
2586 * Set this flag if cached_fw set for either IOC.
2587 */
2588 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2589 ioc->upload_fw = 1;
2590 else
2591 ioc->upload_fw = 0;
2592 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2593 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2594
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002595 if(ioc->bus_type == SAS)
2596 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2597 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2599 else
2600 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002602 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2603 ioc->name, ioc->facts.MsgVersion));
2604 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2605 // set MsgVersion and HeaderVersion host driver was built with
2606 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2607 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002609 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2610 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2611 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2612 return -99;
2613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2615
2616 if (sizeof(dma_addr_t) == sizeof(u64)) {
2617 /* Save the upper 32-bits of the request
2618 * (reply) and sense buffers.
2619 */
2620 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2621 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2622 } else {
2623 /* Force 32-bit addressing */
2624 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2625 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2626 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002627
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2629 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002630 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2631 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
2633 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2634 ioc->name, &ioc_init));
2635
2636 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2637 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002638 if (r != 0) {
2639 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642
2643 /* No need to byte swap the multibyte fields in the reply
2644 * since we don't even look at it's contents.
2645 */
2646
2647 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2648 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002649
2650 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2651 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
2655 /* YIKES! SUPER IMPORTANT!!!
2656 * Poll IocState until _OPERATIONAL while IOC is doing
2657 * LoopInit and TargetDiscovery!
2658 */
2659 count = 0;
2660 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2661 state = mpt_GetIocState(ioc, 1);
2662 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2663 if (sleepFlag == CAN_SLEEP) {
2664 msleep_interruptible(1);
2665 } else {
2666 mdelay(1);
2667 }
2668
2669 if (!cntdn) {
2670 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2671 ioc->name, (int)((count+5)/HZ));
2672 return -9;
2673 }
2674
2675 state = mpt_GetIocState(ioc, 1);
2676 count++;
2677 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002678 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 ioc->name, count));
2680
2681 return r;
2682}
2683
2684/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2685/*
2686 * SendPortEnable - Send PortEnable request to MPT adapter port.
2687 * @ioc: Pointer to MPT_ADAPTER structure
2688 * @portnum: Port number to enable
2689 * @sleepFlag: Specifies whether the process can sleep
2690 *
2691 * Send PortEnable to bring IOC to OPERATIONAL state.
2692 *
2693 * Returns 0 for success, non-zero for failure.
2694 */
2695static int
2696SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2697{
2698 PortEnable_t port_enable;
2699 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002700 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 int req_sz;
2702 int reply_sz;
2703
2704 /* Destination... */
2705 reply_sz = sizeof(MPIDefaultReply_t);
2706 memset(&reply_buf, 0, reply_sz);
2707
2708 req_sz = sizeof(PortEnable_t);
2709 memset(&port_enable, 0, req_sz);
2710
2711 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2712 port_enable.PortNumber = portnum;
2713/* port_enable.ChainOffset = 0; */
2714/* port_enable.MsgFlags = 0; */
2715/* port_enable.MsgContext = 0; */
2716
2717 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2718 ioc->name, portnum, &port_enable));
2719
2720 /* RAID FW may take a long time to enable
2721 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002722 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2723 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2724 (ioc->bus_type == SAS)) {
2725 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2726 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2727 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002728 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002729 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2730 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2731 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002733 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734}
2735
2736/*
2737 * ioc: Pointer to MPT_ADAPTER structure
2738 * size - total FW bytes
2739 */
2740void
2741mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2742{
2743 if (ioc->cached_fw)
2744 return; /* use already allocated memory */
2745 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2746 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2747 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2748 } else {
2749 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2750 ioc->alloc_total += size;
2751 }
2752}
2753/*
2754 * If alt_img is NULL, delete from ioc structure.
2755 * Else, delete a secondary image in same format.
2756 */
2757void
2758mpt_free_fw_memory(MPT_ADAPTER *ioc)
2759{
2760 int sz;
2761
2762 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002763 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2765 pci_free_consistent(ioc->pcidev, sz,
2766 ioc->cached_fw, ioc->cached_fw_dma);
2767 ioc->cached_fw = NULL;
2768
2769 return;
2770}
2771
2772
2773/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2774/*
2775 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2776 * @ioc: Pointer to MPT_ADAPTER structure
2777 * @sleepFlag: Specifies whether the process can sleep
2778 *
2779 * Returns 0 for success, >0 for handshake failure
2780 * <0 for fw upload failure.
2781 *
2782 * Remark: If bound IOC and a successful FWUpload was performed
2783 * on the bound IOC, the second image is discarded
2784 * and memory is free'd. Both channels must upload to prevent
2785 * IOC from running in degraded mode.
2786 */
2787static int
2788mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2789{
2790 u8 request[ioc->req_sz];
2791 u8 reply[sizeof(FWUploadReply_t)];
2792 FWUpload_t *prequest;
2793 FWUploadReply_t *preply;
2794 FWUploadTCSGE_t *ptcsge;
2795 int sgeoffset;
2796 u32 flagsLength;
2797 int ii, sz, reply_sz;
2798 int cmdStatus;
2799
2800 /* If the image size is 0, we are done.
2801 */
2802 if ((sz = ioc->facts.FWImageSize) == 0)
2803 return 0;
2804
2805 mpt_alloc_fw_memory(ioc, sz);
2806
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002807 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002809
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 if (ioc->cached_fw == NULL) {
2811 /* Major Failure.
2812 */
2813 return -ENOMEM;
2814 }
2815
2816 prequest = (FWUpload_t *)&request;
2817 preply = (FWUploadReply_t *)&reply;
2818
2819 /* Destination... */
2820 memset(prequest, 0, ioc->req_sz);
2821
2822 reply_sz = sizeof(reply);
2823 memset(preply, 0, reply_sz);
2824
2825 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2826 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2827
2828 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2829 ptcsge->DetailsLength = 12;
2830 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2831 ptcsge->ImageSize = cpu_to_le32(sz);
2832
2833 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2834
2835 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2836 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2837
2838 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002839 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 prequest, sgeoffset));
2841 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2842
2843 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2844 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2845
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002846 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847
2848 cmdStatus = -EFAULT;
2849 if (ii == 0) {
2850 /* Handshake transfer was complete and successful.
2851 * Check the Reply Frame.
2852 */
2853 int status, transfer_sz;
2854 status = le16_to_cpu(preply->IOCStatus);
2855 if (status == MPI_IOCSTATUS_SUCCESS) {
2856 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2857 if (transfer_sz == sz)
2858 cmdStatus = 0;
2859 }
2860 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002861 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 ioc->name, cmdStatus));
2863
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002864
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 if (cmdStatus) {
2866
2867 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2868 ioc->name));
2869 mpt_free_fw_memory(ioc);
2870 }
2871
2872 return cmdStatus;
2873}
2874
2875/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2876/*
2877 * mpt_downloadboot - DownloadBoot code
2878 * @ioc: Pointer to MPT_ADAPTER structure
2879 * @flag: Specify which part of IOC memory is to be uploaded.
2880 * @sleepFlag: Specifies whether the process can sleep
2881 *
2882 * FwDownloadBoot requires Programmed IO access.
2883 *
2884 * Returns 0 for success
2885 * -1 FW Image size is 0
2886 * -2 No valid cached_fw Pointer
2887 * <0 for fw upload failure.
2888 */
2889static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002890mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 MpiExtImageHeader_t *pExtImage;
2893 u32 fwSize;
2894 u32 diag0val;
2895 int count;
2896 u32 *ptrFw;
2897 u32 diagRwData;
2898 u32 nextImage;
2899 u32 load_addr;
2900 u32 ioc_state=0;
2901
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002902 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2903 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002904
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2906 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2907 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2908 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2909 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2910 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2911
2912 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2913
2914 /* wait 1 msec */
2915 if (sleepFlag == CAN_SLEEP) {
2916 msleep_interruptible(1);
2917 } else {
2918 mdelay (1);
2919 }
2920
2921 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2922 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2923
2924 for (count = 0; count < 30; count ++) {
2925 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2926 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2927 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2928 ioc->name, count));
2929 break;
2930 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002931 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002933 msleep_interruptible (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002935 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 }
2937 }
2938
2939 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002940 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2941 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 ioc->name, diag0val));
2943 return -3;
2944 }
2945
2946 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2947 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2948 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2949 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2950 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2951 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2952
2953 /* Set the DiagRwEn and Disable ARM bits */
2954 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2955
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 fwSize = (pFwHeader->ImageSize + 3)/4;
2957 ptrFw = (u32 *) pFwHeader;
2958
2959 /* Write the LoadStartAddress to the DiagRw Address Register
2960 * using Programmed IO
2961 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002962 if (ioc->errata_flag_1064)
2963 pci_enable_io_access(ioc->pcidev);
2964
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2966 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2967 ioc->name, pFwHeader->LoadStartAddress));
2968
2969 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2970 ioc->name, fwSize*4, ptrFw));
2971 while (fwSize--) {
2972 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2973 }
2974
2975 nextImage = pFwHeader->NextImageHeaderOffset;
2976 while (nextImage) {
2977 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
2978
2979 load_addr = pExtImage->LoadStartAddress;
2980
2981 fwSize = (pExtImage->ImageSize + 3) >> 2;
2982 ptrFw = (u32 *)pExtImage;
2983
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002984 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
2985 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
2987
2988 while (fwSize--) {
2989 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2990 }
2991 nextImage = pExtImage->NextImageHeaderOffset;
2992 }
2993
2994 /* Write the IopResetVectorRegAddr */
2995 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
2996 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
2997
2998 /* Write the IopResetVectorValue */
2999 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3000 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3001
3002 /* Clear the internal flash bad bit - autoincrementing register,
3003 * so must do two writes.
3004 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003005 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003006 /*
3007 * 1030 and 1035 H/W errata, workaround to access
3008 * the ClearFlashBadSignatureBit
3009 */
3010 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3011 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3012 diagRwData |= 0x40000000;
3013 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3014 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3015
3016 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3017 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3018 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3019 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3020
3021 /* wait 1 msec */
3022 if (sleepFlag == CAN_SLEEP) {
3023 msleep_interruptible (1);
3024 } else {
3025 mdelay (1);
3026 }
3027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003029 if (ioc->errata_flag_1064)
3030 pci_disable_io_access(ioc->pcidev);
3031
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003033 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3034 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003036 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3038 ioc->name, diag0val));
3039 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3040
3041 /* Write 0xFF to reset the sequencer */
3042 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3043
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003044 if (ioc->bus_type == SAS) {
3045 ioc_state = mpt_GetIocState(ioc, 0);
3046 if ( (GetIocFacts(ioc, sleepFlag,
3047 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3048 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3049 ioc->name, ioc_state));
3050 return -EFAULT;
3051 }
3052 }
3053
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 for (count=0; count<HZ*20; count++) {
3055 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3056 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3057 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003058 if (ioc->bus_type == SAS) {
3059 return 0;
3060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3062 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3063 ioc->name));
3064 return -EFAULT;
3065 }
3066 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3067 ioc->name));
3068 return 0;
3069 }
3070 if (sleepFlag == CAN_SLEEP) {
3071 msleep_interruptible (10);
3072 } else {
3073 mdelay (10);
3074 }
3075 }
3076 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3077 ioc->name, ioc_state));
3078 return -EFAULT;
3079}
3080
3081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3082/*
3083 * KickStart - Perform hard reset of MPT adapter.
3084 * @ioc: Pointer to MPT_ADAPTER structure
3085 * @force: Force hard reset
3086 * @sleepFlag: Specifies whether the process can sleep
3087 *
3088 * This routine places MPT adapter in diagnostic mode via the
3089 * WriteSequence register, and then performs a hard reset of adapter
3090 * via the Diagnostic register.
3091 *
3092 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3093 * or NO_SLEEP (interrupt thread, use mdelay)
3094 * force - 1 if doorbell active, board fault state
3095 * board operational, IOC_RECOVERY or
3096 * IOC_BRINGUP and there is an alt_ioc.
3097 * 0 else
3098 *
3099 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003100 * 1 - hard reset, READY
3101 * 0 - no reset due to History bit, READY
3102 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 * OR reset but failed to come READY
3104 * -2 - no reset, could not enter DIAG mode
3105 * -3 - reset but bad FW bit
3106 */
3107static int
3108KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3109{
3110 int hard_reset_done = 0;
3111 u32 ioc_state=0;
3112 int cnt,cntdn;
3113
3114 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003115 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 /* Always issue a Msg Unit Reset first. This will clear some
3117 * SCSI bus hang conditions.
3118 */
3119 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3120
3121 if (sleepFlag == CAN_SLEEP) {
3122 msleep_interruptible (1000);
3123 } else {
3124 mdelay (1000);
3125 }
3126 }
3127
3128 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3129 if (hard_reset_done < 0)
3130 return hard_reset_done;
3131
3132 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3133 ioc->name));
3134
3135 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3136 for (cnt=0; cnt<cntdn; cnt++) {
3137 ioc_state = mpt_GetIocState(ioc, 1);
3138 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3139 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3140 ioc->name, cnt));
3141 return hard_reset_done;
3142 }
3143 if (sleepFlag == CAN_SLEEP) {
3144 msleep_interruptible (10);
3145 } else {
3146 mdelay (10);
3147 }
3148 }
3149
3150 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3151 ioc->name, ioc_state);
3152 return -1;
3153}
3154
3155/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3156/*
3157 * mpt_diag_reset - Perform hard reset of the adapter.
3158 * @ioc: Pointer to MPT_ADAPTER structure
3159 * @ignore: Set if to honor and clear to ignore
3160 * the reset history bit
3161 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3162 * else set to NO_SLEEP (use mdelay instead)
3163 *
3164 * This routine places the adapter in diagnostic mode via the
3165 * WriteSequence register and then performs a hard reset of adapter
3166 * via the Diagnostic register. Adapter should be in ready state
3167 * upon successful completion.
3168 *
3169 * Returns: 1 hard reset successful
3170 * 0 no reset performed because reset history bit set
3171 * -2 enabling diagnostic mode failed
3172 * -3 diagnostic reset failed
3173 */
3174static int
3175mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3176{
3177 u32 diag0val;
3178 u32 doorbell;
3179 int hard_reset_done = 0;
3180 int count = 0;
3181#ifdef MPT_DEBUG
3182 u32 diag1val = 0;
3183#endif
3184
3185 /* Clear any existing interrupts */
3186 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3187
3188 /* Use "Diagnostic reset" method! (only thing available!) */
3189 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3190
3191#ifdef MPT_DEBUG
3192 if (ioc->alt_ioc)
3193 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3194 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3195 ioc->name, diag0val, diag1val));
3196#endif
3197
3198 /* Do the reset if we are told to ignore the reset history
3199 * or if the reset history is 0
3200 */
3201 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3202 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3203 /* Write magic sequence to WriteSequence register
3204 * Loop until in diagnostic mode
3205 */
3206 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3207 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3208 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3209 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3210 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3211 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3212
3213 /* wait 100 msec */
3214 if (sleepFlag == CAN_SLEEP) {
3215 msleep_interruptible (100);
3216 } else {
3217 mdelay (100);
3218 }
3219
3220 count++;
3221 if (count > 20) {
3222 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3223 ioc->name, diag0val);
3224 return -2;
3225
3226 }
3227
3228 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3229
3230 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3231 ioc->name, diag0val));
3232 }
3233
3234#ifdef MPT_DEBUG
3235 if (ioc->alt_ioc)
3236 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3237 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3238 ioc->name, diag0val, diag1val));
3239#endif
3240 /*
3241 * Disable the ARM (Bug fix)
3242 *
3243 */
3244 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003245 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246
3247 /*
3248 * Now hit the reset bit in the Diagnostic register
3249 * (THE BIG HAMMER!) (Clears DRWE bit).
3250 */
3251 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3252 hard_reset_done = 1;
3253 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3254 ioc->name));
3255
3256 /*
3257 * Call each currently registered protocol IOC reset handler
3258 * with pre-reset indication.
3259 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3260 * MptResetHandlers[] registered yet.
3261 */
3262 {
3263 int ii;
3264 int r = 0;
3265
3266 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3267 if (MptResetHandlers[ii]) {
3268 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3269 ioc->name, ii));
3270 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
3271 if (ioc->alt_ioc) {
3272 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3273 ioc->name, ioc->alt_ioc->name, ii));
3274 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
3275 }
3276 }
3277 }
3278 /* FIXME? Examine results here? */
3279 }
3280
3281 if (ioc->cached_fw) {
3282 /* If the DownloadBoot operation fails, the
3283 * IOC will be left unusable. This is a fatal error
3284 * case. _diag_reset will return < 0
3285 */
3286 for (count = 0; count < 30; count ++) {
3287 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3288 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3289 break;
3290 }
3291
3292 /* wait 1 sec */
3293 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003294 msleep_interruptible (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 } else {
3296 mdelay (1000);
3297 }
3298 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003299 if ((count = mpt_downloadboot(ioc,
3300 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 printk(KERN_WARNING MYNAM
3302 ": firmware downloadboot failure (%d)!\n", count);
3303 }
3304
3305 } else {
3306 /* Wait for FW to reload and for board
3307 * to go to the READY state.
3308 * Maximum wait is 60 seconds.
3309 * If fail, no error will check again
3310 * with calling program.
3311 */
3312 for (count = 0; count < 60; count ++) {
3313 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3314 doorbell &= MPI_IOC_STATE_MASK;
3315
3316 if (doorbell == MPI_IOC_STATE_READY) {
3317 break;
3318 }
3319
3320 /* wait 1 sec */
3321 if (sleepFlag == CAN_SLEEP) {
3322 msleep_interruptible (1000);
3323 } else {
3324 mdelay (1000);
3325 }
3326 }
3327 }
3328 }
3329
3330 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3331#ifdef MPT_DEBUG
3332 if (ioc->alt_ioc)
3333 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3334 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3335 ioc->name, diag0val, diag1val));
3336#endif
3337
3338 /* Clear RESET_HISTORY bit! Place board in the
3339 * diagnostic mode to update the diag register.
3340 */
3341 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3342 count = 0;
3343 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3344 /* Write magic sequence to WriteSequence register
3345 * Loop until in diagnostic mode
3346 */
3347 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3348 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3349 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3350 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3351 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3352 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3353
3354 /* wait 100 msec */
3355 if (sleepFlag == CAN_SLEEP) {
3356 msleep_interruptible (100);
3357 } else {
3358 mdelay (100);
3359 }
3360
3361 count++;
3362 if (count > 20) {
3363 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3364 ioc->name, diag0val);
3365 break;
3366 }
3367 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3368 }
3369 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3370 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3371 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3372 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3373 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3374 ioc->name);
3375 }
3376
3377 /* Disable Diagnostic Mode
3378 */
3379 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3380
3381 /* Check FW reload status flags.
3382 */
3383 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3384 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3385 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3386 ioc->name, diag0val);
3387 return -3;
3388 }
3389
3390#ifdef MPT_DEBUG
3391 if (ioc->alt_ioc)
3392 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3393 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3394 ioc->name, diag0val, diag1val));
3395#endif
3396
3397 /*
3398 * Reset flag that says we've enabled event notification
3399 */
3400 ioc->facts.EventState = 0;
3401
3402 if (ioc->alt_ioc)
3403 ioc->alt_ioc->facts.EventState = 0;
3404
3405 return hard_reset_done;
3406}
3407
3408/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3409/*
3410 * SendIocReset - Send IOCReset request to MPT adapter.
3411 * @ioc: Pointer to MPT_ADAPTER structure
3412 * @reset_type: reset type, expected values are
3413 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3414 *
3415 * Send IOCReset request to the MPT adapter.
3416 *
3417 * Returns 0 for success, non-zero for failure.
3418 */
3419static int
3420SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3421{
3422 int r;
3423 u32 state;
3424 int cntdn, count;
3425
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003426 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 ioc->name, reset_type));
3428 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3429 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3430 return r;
3431
3432 /* FW ACK'd request, wait for READY state
3433 */
3434 count = 0;
3435 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3436
3437 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3438 cntdn--;
3439 count++;
3440 if (!cntdn) {
3441 if (sleepFlag != CAN_SLEEP)
3442 count *= 10;
3443
3444 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3445 ioc->name, (int)((count+5)/HZ));
3446 return -ETIME;
3447 }
3448
3449 if (sleepFlag == CAN_SLEEP) {
3450 msleep_interruptible(1);
3451 } else {
3452 mdelay (1); /* 1 msec delay */
3453 }
3454 }
3455
3456 /* TODO!
3457 * Cleanup all event stuff for this IOC; re-issue EventNotification
3458 * request if needed.
3459 */
3460 if (ioc->facts.Function)
3461 ioc->facts.EventState = 0;
3462
3463 return 0;
3464}
3465
3466/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3467/*
3468 * initChainBuffers - Allocate memory for and initialize
3469 * chain buffers, chain buffer control arrays and spinlock.
3470 * @hd: Pointer to MPT_SCSI_HOST structure
3471 * @init: If set, initialize the spin lock.
3472 */
3473static int
3474initChainBuffers(MPT_ADAPTER *ioc)
3475{
3476 u8 *mem;
3477 int sz, ii, num_chain;
3478 int scale, num_sge, numSGE;
3479
3480 /* ReqToChain size must equal the req_depth
3481 * index = req_idx
3482 */
3483 if (ioc->ReqToChain == NULL) {
3484 sz = ioc->req_depth * sizeof(int);
3485 mem = kmalloc(sz, GFP_ATOMIC);
3486 if (mem == NULL)
3487 return -1;
3488
3489 ioc->ReqToChain = (int *) mem;
3490 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3491 ioc->name, mem, sz));
3492 mem = kmalloc(sz, GFP_ATOMIC);
3493 if (mem == NULL)
3494 return -1;
3495
3496 ioc->RequestNB = (int *) mem;
3497 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3498 ioc->name, mem, sz));
3499 }
3500 for (ii = 0; ii < ioc->req_depth; ii++) {
3501 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3502 }
3503
3504 /* ChainToChain size must equal the total number
3505 * of chain buffers to be allocated.
3506 * index = chain_idx
3507 *
3508 * Calculate the number of chain buffers needed(plus 1) per I/O
3509 * then multiply the the maximum number of simultaneous cmds
3510 *
3511 * num_sge = num sge in request frame + last chain buffer
3512 * scale = num sge per chain buffer if no chain element
3513 */
3514 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3515 if (sizeof(dma_addr_t) == sizeof(u64))
3516 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3517 else
3518 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3519
3520 if (sizeof(dma_addr_t) == sizeof(u64)) {
3521 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3522 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3523 } else {
3524 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3525 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3526 }
3527 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3528 ioc->name, num_sge, numSGE));
3529
3530 if ( numSGE > MPT_SCSI_SG_DEPTH )
3531 numSGE = MPT_SCSI_SG_DEPTH;
3532
3533 num_chain = 1;
3534 while (numSGE - num_sge > 0) {
3535 num_chain++;
3536 num_sge += (scale - 1);
3537 }
3538 num_chain++;
3539
3540 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3541 ioc->name, numSGE, num_sge, num_chain));
3542
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003543 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 num_chain *= MPT_SCSI_CAN_QUEUE;
3545 else
3546 num_chain *= MPT_FC_CAN_QUEUE;
3547
3548 ioc->num_chain = num_chain;
3549
3550 sz = num_chain * sizeof(int);
3551 if (ioc->ChainToChain == NULL) {
3552 mem = kmalloc(sz, GFP_ATOMIC);
3553 if (mem == NULL)
3554 return -1;
3555
3556 ioc->ChainToChain = (int *) mem;
3557 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3558 ioc->name, mem, sz));
3559 } else {
3560 mem = (u8 *) ioc->ChainToChain;
3561 }
3562 memset(mem, 0xFF, sz);
3563 return num_chain;
3564}
3565
3566/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3567/*
3568 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3569 * @ioc: Pointer to MPT_ADAPTER structure
3570 *
3571 * This routine allocates memory for the MPT reply and request frame
3572 * pools (if necessary), and primes the IOC reply FIFO with
3573 * reply frames.
3574 *
3575 * Returns 0 for success, non-zero for failure.
3576 */
3577static int
3578PrimeIocFifos(MPT_ADAPTER *ioc)
3579{
3580 MPT_FRAME_HDR *mf;
3581 unsigned long flags;
3582 dma_addr_t alloc_dma;
3583 u8 *mem;
3584 int i, reply_sz, sz, total_size, num_chain;
3585
3586 /* Prime reply FIFO... */
3587
3588 if (ioc->reply_frames == NULL) {
3589 if ( (num_chain = initChainBuffers(ioc)) < 0)
3590 return -1;
3591
3592 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3593 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3594 ioc->name, ioc->reply_sz, ioc->reply_depth));
3595 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3596 ioc->name, reply_sz, reply_sz));
3597
3598 sz = (ioc->req_sz * ioc->req_depth);
3599 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3600 ioc->name, ioc->req_sz, ioc->req_depth));
3601 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3602 ioc->name, sz, sz));
3603 total_size += sz;
3604
3605 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3606 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3607 ioc->name, ioc->req_sz, num_chain));
3608 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3609 ioc->name, sz, sz, num_chain));
3610
3611 total_size += sz;
3612 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3613 if (mem == NULL) {
3614 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3615 ioc->name);
3616 goto out_fail;
3617 }
3618
3619 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3620 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3621
3622 memset(mem, 0, total_size);
3623 ioc->alloc_total += total_size;
3624 ioc->alloc = mem;
3625 ioc->alloc_dma = alloc_dma;
3626 ioc->alloc_sz = total_size;
3627 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3628 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3629
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003630 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3631 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3632
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 alloc_dma += reply_sz;
3634 mem += reply_sz;
3635
3636 /* Request FIFO - WE manage this! */
3637
3638 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3639 ioc->req_frames_dma = alloc_dma;
3640
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003641 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 ioc->name, mem, (void *)(ulong)alloc_dma));
3643
3644 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3645
3646#if defined(CONFIG_MTRR) && 0
3647 /*
3648 * Enable Write Combining MTRR for IOC's memory region.
3649 * (at least as much as we can; "size and base must be
3650 * multiples of 4 kiB"
3651 */
3652 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3653 sz,
3654 MTRR_TYPE_WRCOMB, 1);
3655 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3656 ioc->name, ioc->req_frames_dma, sz));
3657#endif
3658
3659 for (i = 0; i < ioc->req_depth; i++) {
3660 alloc_dma += ioc->req_sz;
3661 mem += ioc->req_sz;
3662 }
3663
3664 ioc->ChainBuffer = mem;
3665 ioc->ChainBufferDMA = alloc_dma;
3666
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003667 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3669
3670 /* Initialize the free chain Q.
3671 */
3672
3673 INIT_LIST_HEAD(&ioc->FreeChainQ);
3674
3675 /* Post the chain buffers to the FreeChainQ.
3676 */
3677 mem = (u8 *)ioc->ChainBuffer;
3678 for (i=0; i < num_chain; i++) {
3679 mf = (MPT_FRAME_HDR *) mem;
3680 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3681 mem += ioc->req_sz;
3682 }
3683
3684 /* Initialize Request frames linked list
3685 */
3686 alloc_dma = ioc->req_frames_dma;
3687 mem = (u8 *) ioc->req_frames;
3688
3689 spin_lock_irqsave(&ioc->FreeQlock, flags);
3690 INIT_LIST_HEAD(&ioc->FreeQ);
3691 for (i = 0; i < ioc->req_depth; i++) {
3692 mf = (MPT_FRAME_HDR *) mem;
3693
3694 /* Queue REQUESTs *internally*! */
3695 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3696
3697 mem += ioc->req_sz;
3698 }
3699 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3700
3701 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3702 ioc->sense_buf_pool =
3703 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3704 if (ioc->sense_buf_pool == NULL) {
3705 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3706 ioc->name);
3707 goto out_fail;
3708 }
3709
3710 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3711 ioc->alloc_total += sz;
3712 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3713 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3714
3715 }
3716
3717 /* Post Reply frames to FIFO
3718 */
3719 alloc_dma = ioc->alloc_dma;
3720 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3721 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3722
3723 for (i = 0; i < ioc->reply_depth; i++) {
3724 /* Write each address to the IOC! */
3725 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3726 alloc_dma += ioc->reply_sz;
3727 }
3728
3729 return 0;
3730
3731out_fail:
3732 if (ioc->alloc != NULL) {
3733 sz = ioc->alloc_sz;
3734 pci_free_consistent(ioc->pcidev,
3735 sz,
3736 ioc->alloc, ioc->alloc_dma);
3737 ioc->reply_frames = NULL;
3738 ioc->req_frames = NULL;
3739 ioc->alloc_total -= sz;
3740 }
3741 if (ioc->sense_buf_pool != NULL) {
3742 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3743 pci_free_consistent(ioc->pcidev,
3744 sz,
3745 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3746 ioc->sense_buf_pool = NULL;
3747 }
3748 return -1;
3749}
3750
3751/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3752/**
3753 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3754 * from IOC via doorbell handshake method.
3755 * @ioc: Pointer to MPT_ADAPTER structure
3756 * @reqBytes: Size of the request in bytes
3757 * @req: Pointer to MPT request frame
3758 * @replyBytes: Expected size of the reply in bytes
3759 * @u16reply: Pointer to area where reply should be written
3760 * @maxwait: Max wait time for a reply (in seconds)
3761 * @sleepFlag: Specifies whether the process can sleep
3762 *
3763 * NOTES: It is the callers responsibility to byte-swap fields in the
3764 * request which are greater than 1 byte in size. It is also the
3765 * callers responsibility to byte-swap response fields which are
3766 * greater than 1 byte in size.
3767 *
3768 * Returns 0 for success, non-zero for failure.
3769 */
3770static int
3771mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003772 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773{
3774 MPIDefaultReply_t *mptReply;
3775 int failcnt = 0;
3776 int t;
3777
3778 /*
3779 * Get ready to cache a handshake reply
3780 */
3781 ioc->hs_reply_idx = 0;
3782 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3783 mptReply->MsgLength = 0;
3784
3785 /*
3786 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3787 * then tell IOC that we want to handshake a request of N words.
3788 * (WRITE u32val to Doorbell reg).
3789 */
3790 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3791 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3792 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3793 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3794
3795 /*
3796 * Wait for IOC's doorbell handshake int
3797 */
3798 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3799 failcnt++;
3800
3801 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3802 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3803
3804 /* Read doorbell and check for active bit */
3805 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3806 return -1;
3807
3808 /*
3809 * Clear doorbell int (WRITE 0 to IntStatus reg),
3810 * then wait for IOC to ACKnowledge that it's ready for
3811 * our handshake request.
3812 */
3813 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3814 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3815 failcnt++;
3816
3817 if (!failcnt) {
3818 int ii;
3819 u8 *req_as_bytes = (u8 *) req;
3820
3821 /*
3822 * Stuff request words via doorbell handshake,
3823 * with ACK from IOC for each.
3824 */
3825 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3826 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3827 (req_as_bytes[(ii*4) + 1] << 8) |
3828 (req_as_bytes[(ii*4) + 2] << 16) |
3829 (req_as_bytes[(ii*4) + 3] << 24));
3830
3831 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3832 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3833 failcnt++;
3834 }
3835
3836 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3837 DBG_DUMP_REQUEST_FRAME_HDR(req)
3838
3839 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3840 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3841
3842 /*
3843 * Wait for completion of doorbell handshake reply from the IOC
3844 */
3845 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3846 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003847
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3849 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3850
3851 /*
3852 * Copy out the cached reply...
3853 */
3854 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3855 u16reply[ii] = ioc->hs_reply[ii];
3856 } else {
3857 return -99;
3858 }
3859
3860 return -failcnt;
3861}
3862
3863/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3864/*
3865 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3866 * in it's IntStatus register.
3867 * @ioc: Pointer to MPT_ADAPTER structure
3868 * @howlong: How long to wait (in seconds)
3869 * @sleepFlag: Specifies whether the process can sleep
3870 *
3871 * This routine waits (up to ~2 seconds max) for IOC doorbell
3872 * handshake ACKnowledge.
3873 *
3874 * Returns a negative value on failure, else wait loop count.
3875 */
3876static int
3877WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3878{
3879 int cntdn;
3880 int count = 0;
3881 u32 intstat=0;
3882
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003883 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884
3885 if (sleepFlag == CAN_SLEEP) {
3886 while (--cntdn) {
3887 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3888 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3889 break;
3890 msleep_interruptible (1);
3891 count++;
3892 }
3893 } else {
3894 while (--cntdn) {
3895 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3896 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3897 break;
3898 mdelay (1);
3899 count++;
3900 }
3901 }
3902
3903 if (cntdn) {
3904 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3905 ioc->name, count));
3906 return count;
3907 }
3908
3909 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3910 ioc->name, count, intstat);
3911 return -1;
3912}
3913
3914/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3915/*
3916 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3917 * in it's IntStatus register.
3918 * @ioc: Pointer to MPT_ADAPTER structure
3919 * @howlong: How long to wait (in seconds)
3920 * @sleepFlag: Specifies whether the process can sleep
3921 *
3922 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3923 *
3924 * Returns a negative value on failure, else wait loop count.
3925 */
3926static int
3927WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3928{
3929 int cntdn;
3930 int count = 0;
3931 u32 intstat=0;
3932
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003933 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 if (sleepFlag == CAN_SLEEP) {
3935 while (--cntdn) {
3936 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3937 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3938 break;
3939 msleep_interruptible(1);
3940 count++;
3941 }
3942 } else {
3943 while (--cntdn) {
3944 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3945 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3946 break;
3947 mdelay(1);
3948 count++;
3949 }
3950 }
3951
3952 if (cntdn) {
3953 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3954 ioc->name, count, howlong));
3955 return count;
3956 }
3957
3958 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3959 ioc->name, count, intstat);
3960 return -1;
3961}
3962
3963/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3964/*
3965 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3966 * @ioc: Pointer to MPT_ADAPTER structure
3967 * @howlong: How long to wait (in seconds)
3968 * @sleepFlag: Specifies whether the process can sleep
3969 *
3970 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3971 * Reply is cached to IOC private area large enough to hold a maximum
3972 * of 128 bytes of reply data.
3973 *
3974 * Returns a negative value on failure, else size of reply in WORDS.
3975 */
3976static int
3977WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3978{
3979 int u16cnt = 0;
3980 int failcnt = 0;
3981 int t;
3982 u16 *hs_reply = ioc->hs_reply;
3983 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3984 u16 hword;
3985
3986 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
3987
3988 /*
3989 * Get first two u16's so we can look at IOC's intended reply MsgLength
3990 */
3991 u16cnt=0;
3992 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
3993 failcnt++;
3994 } else {
3995 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
3996 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3997 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3998 failcnt++;
3999 else {
4000 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4001 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4002 }
4003 }
4004
4005 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004006 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4008
4009 /*
4010 * If no error (and IOC said MsgLength is > 0), piece together
4011 * reply 16 bits at a time.
4012 */
4013 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4014 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4015 failcnt++;
4016 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4017 /* don't overflow our IOC hs_reply[] buffer! */
4018 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4019 hs_reply[u16cnt] = hword;
4020 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4021 }
4022
4023 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4024 failcnt++;
4025 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4026
4027 if (failcnt) {
4028 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4029 ioc->name);
4030 return -failcnt;
4031 }
4032#if 0
4033 else if (u16cnt != (2 * mptReply->MsgLength)) {
4034 return -101;
4035 }
4036 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4037 return -102;
4038 }
4039#endif
4040
4041 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4042 DBG_DUMP_REPLY_FRAME(mptReply)
4043
4044 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4045 ioc->name, t, u16cnt/2));
4046 return u16cnt/2;
4047}
4048
4049/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4050/*
4051 * GetLanConfigPages - Fetch LANConfig pages.
4052 * @ioc: Pointer to MPT_ADAPTER structure
4053 *
4054 * Return: 0 for success
4055 * -ENOMEM if no memory available
4056 * -EPERM if not allowed due to ISR context
4057 * -EAGAIN if no msg frames currently available
4058 * -EFAULT for non-successful reply or no reply (timeout)
4059 */
4060static int
4061GetLanConfigPages(MPT_ADAPTER *ioc)
4062{
4063 ConfigPageHeader_t hdr;
4064 CONFIGPARMS cfg;
4065 LANPage0_t *ppage0_alloc;
4066 dma_addr_t page0_dma;
4067 LANPage1_t *ppage1_alloc;
4068 dma_addr_t page1_dma;
4069 int rc = 0;
4070 int data_sz;
4071 int copy_sz;
4072
4073 /* Get LAN Page 0 header */
4074 hdr.PageVersion = 0;
4075 hdr.PageLength = 0;
4076 hdr.PageNumber = 0;
4077 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004078 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 cfg.physAddr = -1;
4080 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4081 cfg.dir = 0;
4082 cfg.pageAddr = 0;
4083 cfg.timeout = 0;
4084
4085 if ((rc = mpt_config(ioc, &cfg)) != 0)
4086 return rc;
4087
4088 if (hdr.PageLength > 0) {
4089 data_sz = hdr.PageLength * 4;
4090 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4091 rc = -ENOMEM;
4092 if (ppage0_alloc) {
4093 memset((u8 *)ppage0_alloc, 0, data_sz);
4094 cfg.physAddr = page0_dma;
4095 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4096
4097 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4098 /* save the data */
4099 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4100 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4101
4102 }
4103
4104 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4105
4106 /* FIXME!
4107 * Normalize endianness of structure data,
4108 * by byte-swapping all > 1 byte fields!
4109 */
4110
4111 }
4112
4113 if (rc)
4114 return rc;
4115 }
4116
4117 /* Get LAN Page 1 header */
4118 hdr.PageVersion = 0;
4119 hdr.PageLength = 0;
4120 hdr.PageNumber = 1;
4121 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004122 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 cfg.physAddr = -1;
4124 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4125 cfg.dir = 0;
4126 cfg.pageAddr = 0;
4127
4128 if ((rc = mpt_config(ioc, &cfg)) != 0)
4129 return rc;
4130
4131 if (hdr.PageLength == 0)
4132 return 0;
4133
4134 data_sz = hdr.PageLength * 4;
4135 rc = -ENOMEM;
4136 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4137 if (ppage1_alloc) {
4138 memset((u8 *)ppage1_alloc, 0, data_sz);
4139 cfg.physAddr = page1_dma;
4140 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4141
4142 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4143 /* save the data */
4144 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4145 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4146 }
4147
4148 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4149
4150 /* FIXME!
4151 * Normalize endianness of structure data,
4152 * by byte-swapping all > 1 byte fields!
4153 */
4154
4155 }
4156
4157 return rc;
4158}
4159
4160/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4161/*
Michael Reed05e8ec12006-01-13 14:31:54 -06004162 * mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 * @ioc: Pointer to MPT_ADAPTER structure
4164 * @portnum: IOC Port number
4165 *
4166 * Return: 0 for success
4167 * -ENOMEM if no memory available
4168 * -EPERM if not allowed due to ISR context
4169 * -EAGAIN if no msg frames currently available
4170 * -EFAULT for non-successful reply or no reply (timeout)
4171 */
Michael Reed05e8ec12006-01-13 14:31:54 -06004172int
4173mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174{
4175 ConfigPageHeader_t hdr;
4176 CONFIGPARMS cfg;
4177 FCPortPage0_t *ppage0_alloc;
4178 FCPortPage0_t *pp0dest;
4179 dma_addr_t page0_dma;
4180 int data_sz;
4181 int copy_sz;
4182 int rc;
Michael Reed05e8ec12006-01-13 14:31:54 -06004183 int count = 400;
4184
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185
4186 /* Get FCPort Page 0 header */
4187 hdr.PageVersion = 0;
4188 hdr.PageLength = 0;
4189 hdr.PageNumber = 0;
4190 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004191 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 cfg.physAddr = -1;
4193 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4194 cfg.dir = 0;
4195 cfg.pageAddr = portnum;
4196 cfg.timeout = 0;
4197
4198 if ((rc = mpt_config(ioc, &cfg)) != 0)
4199 return rc;
4200
4201 if (hdr.PageLength == 0)
4202 return 0;
4203
4204 data_sz = hdr.PageLength * 4;
4205 rc = -ENOMEM;
4206 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4207 if (ppage0_alloc) {
Michael Reed05e8ec12006-01-13 14:31:54 -06004208
4209 try_again:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 memset((u8 *)ppage0_alloc, 0, data_sz);
4211 cfg.physAddr = page0_dma;
4212 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4213
4214 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4215 /* save the data */
4216 pp0dest = &ioc->fc_port_page0[portnum];
4217 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
4218 memcpy(pp0dest, ppage0_alloc, copy_sz);
4219
4220 /*
4221 * Normalize endianness of structure data,
4222 * by byte-swapping all > 1 byte fields!
4223 */
4224 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
4225 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
4226 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
4227 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
4228 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
4229 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
4230 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
4231 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
4232 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
4233 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
4234 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
4235 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
4236 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
4237 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
4238 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
4239 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
4240
Michael Reed05e8ec12006-01-13 14:31:54 -06004241 /*
4242 * if still doing discovery,
4243 * hang loose a while until finished
4244 */
4245 if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
4246 if (count-- > 0) {
4247 msleep_interruptible(100);
4248 goto try_again;
4249 }
4250 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
4251 " complete.\n",
4252 ioc->name);
4253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 }
4255
4256 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4257 }
4258
4259 return rc;
4260}
4261
4262/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4263/*
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004264 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4265 * @ioc: Pointer to MPT_ADAPTER structure
4266 * @sas_address: 64bit SAS Address for operation.
4267 * @target_id: specified target for operation
4268 * @bus: specified bus for operation
4269 * @persist_opcode: see below
4270 *
4271 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4272 * devices not currently present.
4273 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4274 *
4275 * NOTE: Don't use not this function during interrupt time.
4276 *
4277 * Returns: 0 for success, non-zero error
4278 */
4279
4280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4281int
4282mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4283{
4284 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4285 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4286 MPT_FRAME_HDR *mf = NULL;
4287 MPIHeader_t *mpi_hdr;
4288
4289
4290 /* insure garbage is not sent to fw */
4291 switch(persist_opcode) {
4292
4293 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4294 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4295 break;
4296
4297 default:
4298 return -1;
4299 break;
4300 }
4301
4302 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4303
4304 /* Get a MF for this command.
4305 */
4306 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4307 printk("%s: no msg frames!\n",__FUNCTION__);
4308 return -1;
4309 }
4310
4311 mpi_hdr = (MPIHeader_t *) mf;
4312 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4313 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4314 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4315 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4316 sasIoUnitCntrReq->Operation = persist_opcode;
4317
4318 init_timer(&ioc->persist_timer);
4319 ioc->persist_timer.data = (unsigned long) ioc;
4320 ioc->persist_timer.function = mpt_timer_expired;
4321 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4322 ioc->persist_wait_done=0;
4323 add_timer(&ioc->persist_timer);
4324 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4325 wait_event(mpt_waitq, ioc->persist_wait_done);
4326
4327 sasIoUnitCntrReply =
4328 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4329 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4330 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4331 __FUNCTION__,
4332 sasIoUnitCntrReply->IOCStatus,
4333 sasIoUnitCntrReply->IOCLogInfo);
4334 return -1;
4335 }
4336
4337 printk("%s: success\n",__FUNCTION__);
4338 return 0;
4339}
4340
4341/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004342
4343static void
4344mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4345 MpiEventDataRaid_t * pRaidEventData)
4346{
4347 int volume;
4348 int reason;
4349 int disk;
4350 int status;
4351 int flags;
4352 int state;
4353
4354 volume = pRaidEventData->VolumeID;
4355 reason = pRaidEventData->ReasonCode;
4356 disk = pRaidEventData->PhysDiskNum;
4357 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4358 flags = (status >> 0) & 0xff;
4359 state = (status >> 8) & 0xff;
4360
4361 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4362 return;
4363 }
4364
4365 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4366 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4367 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4368 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4369 ioc->name, disk);
4370 } else {
4371 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4372 ioc->name, volume);
4373 }
4374
4375 switch(reason) {
4376 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4377 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4378 ioc->name);
4379 break;
4380
4381 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4382
4383 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4384 ioc->name);
4385 break;
4386
4387 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4388 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4389 ioc->name);
4390 break;
4391
4392 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4393 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4394 ioc->name,
4395 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4396 ? "optimal"
4397 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4398 ? "degraded"
4399 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4400 ? "failed"
4401 : "state unknown",
4402 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4403 ? ", enabled" : "",
4404 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4405 ? ", quiesced" : "",
4406 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4407 ? ", resync in progress" : "" );
4408 break;
4409
4410 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4411 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4412 ioc->name, disk);
4413 break;
4414
4415 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4416 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4417 ioc->name);
4418 break;
4419
4420 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4421 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4422 ioc->name);
4423 break;
4424
4425 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4426 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4427 ioc->name);
4428 break;
4429
4430 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4431 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4432 ioc->name,
4433 state == MPI_PHYSDISK0_STATUS_ONLINE
4434 ? "online"
4435 : state == MPI_PHYSDISK0_STATUS_MISSING
4436 ? "missing"
4437 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4438 ? "not compatible"
4439 : state == MPI_PHYSDISK0_STATUS_FAILED
4440 ? "failed"
4441 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4442 ? "initializing"
4443 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4444 ? "offline requested"
4445 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4446 ? "failed requested"
4447 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4448 ? "offline"
4449 : "state unknown",
4450 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4451 ? ", out of sync" : "",
4452 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4453 ? ", quiesced" : "" );
4454 break;
4455
4456 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4457 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4458 ioc->name, disk);
4459 break;
4460
4461 case MPI_EVENT_RAID_RC_SMART_DATA:
4462 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4463 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4464 break;
4465
4466 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4467 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4468 ioc->name, disk);
4469 break;
4470 }
4471}
4472
4473/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004474/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4476 * @ioc: Pointer to MPT_ADAPTER structure
4477 *
4478 * Returns: 0 for success
4479 * -ENOMEM if no memory available
4480 * -EPERM if not allowed due to ISR context
4481 * -EAGAIN if no msg frames currently available
4482 * -EFAULT for non-successful reply or no reply (timeout)
4483 */
4484static int
4485GetIoUnitPage2(MPT_ADAPTER *ioc)
4486{
4487 ConfigPageHeader_t hdr;
4488 CONFIGPARMS cfg;
4489 IOUnitPage2_t *ppage_alloc;
4490 dma_addr_t page_dma;
4491 int data_sz;
4492 int rc;
4493
4494 /* Get the page header */
4495 hdr.PageVersion = 0;
4496 hdr.PageLength = 0;
4497 hdr.PageNumber = 2;
4498 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004499 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 cfg.physAddr = -1;
4501 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4502 cfg.dir = 0;
4503 cfg.pageAddr = 0;
4504 cfg.timeout = 0;
4505
4506 if ((rc = mpt_config(ioc, &cfg)) != 0)
4507 return rc;
4508
4509 if (hdr.PageLength == 0)
4510 return 0;
4511
4512 /* Read the config page */
4513 data_sz = hdr.PageLength * 4;
4514 rc = -ENOMEM;
4515 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4516 if (ppage_alloc) {
4517 memset((u8 *)ppage_alloc, 0, data_sz);
4518 cfg.physAddr = page_dma;
4519 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4520
4521 /* If Good, save data */
4522 if ((rc = mpt_config(ioc, &cfg)) == 0)
4523 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4524
4525 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4526 }
4527
4528 return rc;
4529}
4530
4531/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4532/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4533 * @ioc: Pointer to a Adapter Strucutre
4534 * @portnum: IOC port number
4535 *
4536 * Return: -EFAULT if read of config page header fails
4537 * or if no nvram
4538 * If read of SCSI Port Page 0 fails,
4539 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4540 * Adapter settings: async, narrow
4541 * Return 1
4542 * If read of SCSI Port Page 2 fails,
4543 * Adapter settings valid
4544 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4545 * Return 1
4546 * Else
4547 * Both valid
4548 * Return 0
4549 * CHECK - what type of locking mechanisms should be used????
4550 */
4551static int
4552mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4553{
4554 u8 *pbuf;
4555 dma_addr_t buf_dma;
4556 CONFIGPARMS cfg;
4557 ConfigPageHeader_t header;
4558 int ii;
4559 int data, rc = 0;
4560
4561 /* Allocate memory
4562 */
4563 if (!ioc->spi_data.nvram) {
4564 int sz;
4565 u8 *mem;
4566 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4567 mem = kmalloc(sz, GFP_ATOMIC);
4568 if (mem == NULL)
4569 return -EFAULT;
4570
4571 ioc->spi_data.nvram = (int *) mem;
4572
4573 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4574 ioc->name, ioc->spi_data.nvram, sz));
4575 }
4576
4577 /* Invalidate NVRAM information
4578 */
4579 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4580 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4581 }
4582
4583 /* Read SPP0 header, allocate memory, then read page.
4584 */
4585 header.PageVersion = 0;
4586 header.PageLength = 0;
4587 header.PageNumber = 0;
4588 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004589 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 cfg.physAddr = -1;
4591 cfg.pageAddr = portnum;
4592 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4593 cfg.dir = 0;
4594 cfg.timeout = 0; /* use default */
4595 if (mpt_config(ioc, &cfg) != 0)
4596 return -EFAULT;
4597
4598 if (header.PageLength > 0) {
4599 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4600 if (pbuf) {
4601 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4602 cfg.physAddr = buf_dma;
4603 if (mpt_config(ioc, &cfg) != 0) {
4604 ioc->spi_data.maxBusWidth = MPT_NARROW;
4605 ioc->spi_data.maxSyncOffset = 0;
4606 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4607 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4608 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004609 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4610 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 } else {
4612 /* Save the Port Page 0 data
4613 */
4614 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4615 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4616 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4617
4618 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4619 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004620 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 ioc->name, pPP0->Capabilities));
4622 }
4623 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4624 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4625 if (data) {
4626 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4627 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4628 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004629 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4630 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 } else {
4632 ioc->spi_data.maxSyncOffset = 0;
4633 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4634 }
4635
4636 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4637
4638 /* Update the minSyncFactor based on bus type.
4639 */
4640 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4641 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4642
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004643 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004645 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4646 ioc->name, ioc->spi_data.minSyncFactor));
4647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 }
4649 }
4650 if (pbuf) {
4651 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4652 }
4653 }
4654 }
4655
4656 /* SCSI Port Page 2 - Read the header then the page.
4657 */
4658 header.PageVersion = 0;
4659 header.PageLength = 0;
4660 header.PageNumber = 2;
4661 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004662 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 cfg.physAddr = -1;
4664 cfg.pageAddr = portnum;
4665 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4666 cfg.dir = 0;
4667 if (mpt_config(ioc, &cfg) != 0)
4668 return -EFAULT;
4669
4670 if (header.PageLength > 0) {
4671 /* Allocate memory and read SCSI Port Page 2
4672 */
4673 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4674 if (pbuf) {
4675 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4676 cfg.physAddr = buf_dma;
4677 if (mpt_config(ioc, &cfg) != 0) {
4678 /* Nvram data is left with INVALID mark
4679 */
4680 rc = 1;
4681 } else {
4682 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4683 MpiDeviceInfo_t *pdevice = NULL;
4684
Moore, Ericd8e925d2006-01-16 18:53:06 -07004685 /*
4686 * Save "Set to Avoid SCSI Bus Resets" flag
4687 */
4688 ioc->spi_data.bus_reset =
4689 (le32_to_cpu(pPP2->PortFlags) &
4690 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4691 0 : 1 ;
4692
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 /* Save the Port Page 2 data
4694 * (reformat into a 32bit quantity)
4695 */
4696 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4697 ioc->spi_data.PortFlags = data;
4698 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4699 pdevice = &pPP2->DeviceSettings[ii];
4700 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4701 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4702 ioc->spi_data.nvram[ii] = data;
4703 }
4704 }
4705
4706 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4707 }
4708 }
4709
4710 /* Update Adapter limits with those from NVRAM
4711 * Comment: Don't need to do this. Target performance
4712 * parameters will never exceed the adapters limits.
4713 */
4714
4715 return rc;
4716}
4717
4718/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4719/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4720 * @ioc: Pointer to a Adapter Strucutre
4721 * @portnum: IOC port number
4722 *
4723 * Return: -EFAULT if read of config page header fails
4724 * or 0 if success.
4725 */
4726static int
4727mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4728{
4729 CONFIGPARMS cfg;
4730 ConfigPageHeader_t header;
4731
4732 /* Read the SCSI Device Page 1 header
4733 */
4734 header.PageVersion = 0;
4735 header.PageLength = 0;
4736 header.PageNumber = 1;
4737 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004738 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 cfg.physAddr = -1;
4740 cfg.pageAddr = portnum;
4741 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4742 cfg.dir = 0;
4743 cfg.timeout = 0;
4744 if (mpt_config(ioc, &cfg) != 0)
4745 return -EFAULT;
4746
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004747 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4748 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749
4750 header.PageVersion = 0;
4751 header.PageLength = 0;
4752 header.PageNumber = 0;
4753 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4754 if (mpt_config(ioc, &cfg) != 0)
4755 return -EFAULT;
4756
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004757 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4758 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759
4760 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4761 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4762
4763 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4764 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4765 return 0;
4766}
4767
4768/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4769/**
4770 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4771 * @ioc: Pointer to a Adapter Strucutre
4772 * @portnum: IOC port number
4773 *
4774 * Return:
4775 * 0 on success
4776 * -EFAULT if read of config page header fails or data pointer not NULL
4777 * -ENOMEM if pci_alloc failed
4778 */
4779int
4780mpt_findImVolumes(MPT_ADAPTER *ioc)
4781{
4782 IOCPage2_t *pIoc2;
4783 u8 *mem;
4784 ConfigPageIoc2RaidVol_t *pIocRv;
4785 dma_addr_t ioc2_dma;
4786 CONFIGPARMS cfg;
4787 ConfigPageHeader_t header;
4788 int jj;
4789 int rc = 0;
4790 int iocpage2sz;
4791 u8 nVols, nPhys;
4792 u8 vid, vbus, vioc;
4793
4794 /* Read IOCP2 header then the page.
4795 */
4796 header.PageVersion = 0;
4797 header.PageLength = 0;
4798 header.PageNumber = 2;
4799 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004800 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 cfg.physAddr = -1;
4802 cfg.pageAddr = 0;
4803 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4804 cfg.dir = 0;
4805 cfg.timeout = 0;
4806 if (mpt_config(ioc, &cfg) != 0)
4807 return -EFAULT;
4808
4809 if (header.PageLength == 0)
4810 return -EFAULT;
4811
4812 iocpage2sz = header.PageLength * 4;
4813 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4814 if (!pIoc2)
4815 return -ENOMEM;
4816
4817 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4818 cfg.physAddr = ioc2_dma;
4819 if (mpt_config(ioc, &cfg) != 0)
4820 goto done_and_free;
4821
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004822 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4824 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004825 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 } else {
4827 goto done_and_free;
4828 }
4829 }
4830 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4831
4832 /* Identify RAID Volume Id's */
4833 nVols = pIoc2->NumActiveVolumes;
4834 if ( nVols == 0) {
4835 /* No RAID Volume.
4836 */
4837 goto done_and_free;
4838 } else {
4839 /* At least 1 RAID Volume
4840 */
4841 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004842 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4844 vid = pIocRv->VolumeID;
4845 vbus = pIocRv->VolumeBus;
4846 vioc = pIocRv->VolumeIOC;
4847
4848 /* find the match
4849 */
4850 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004851 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 } else {
4853 /* Error! Always bus 0
4854 */
4855 }
4856 }
4857 }
4858
4859 /* Identify Hidden Physical Disk Id's */
4860 nPhys = pIoc2->NumActivePhysDisks;
4861 if (nPhys == 0) {
4862 /* No physical disks.
4863 */
4864 } else {
4865 mpt_read_ioc_pg_3(ioc);
4866 }
4867
4868done_and_free:
4869 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4870
4871 return rc;
4872}
4873
Moore, Ericc972c702006-03-14 09:14:06 -07004874static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4876{
4877 IOCPage3_t *pIoc3;
4878 u8 *mem;
4879 CONFIGPARMS cfg;
4880 ConfigPageHeader_t header;
4881 dma_addr_t ioc3_dma;
4882 int iocpage3sz = 0;
4883
4884 /* Free the old page
4885 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004886 kfree(ioc->raid_data.pIocPg3);
4887 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888
4889 /* There is at least one physical disk.
4890 * Read and save IOC Page 3
4891 */
4892 header.PageVersion = 0;
4893 header.PageLength = 0;
4894 header.PageNumber = 3;
4895 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004896 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 cfg.physAddr = -1;
4898 cfg.pageAddr = 0;
4899 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4900 cfg.dir = 0;
4901 cfg.timeout = 0;
4902 if (mpt_config(ioc, &cfg) != 0)
4903 return 0;
4904
4905 if (header.PageLength == 0)
4906 return 0;
4907
4908 /* Read Header good, alloc memory
4909 */
4910 iocpage3sz = header.PageLength * 4;
4911 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4912 if (!pIoc3)
4913 return 0;
4914
4915 /* Read the Page and save the data
4916 * into malloc'd memory.
4917 */
4918 cfg.physAddr = ioc3_dma;
4919 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4920 if (mpt_config(ioc, &cfg) == 0) {
4921 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4922 if (mem) {
4923 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004924 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 }
4926 }
4927
4928 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4929
4930 return 0;
4931}
4932
4933static void
4934mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4935{
4936 IOCPage4_t *pIoc4;
4937 CONFIGPARMS cfg;
4938 ConfigPageHeader_t header;
4939 dma_addr_t ioc4_dma;
4940 int iocpage4sz;
4941
4942 /* Read and save IOC Page 4
4943 */
4944 header.PageVersion = 0;
4945 header.PageLength = 0;
4946 header.PageNumber = 4;
4947 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004948 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 cfg.physAddr = -1;
4950 cfg.pageAddr = 0;
4951 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4952 cfg.dir = 0;
4953 cfg.timeout = 0;
4954 if (mpt_config(ioc, &cfg) != 0)
4955 return;
4956
4957 if (header.PageLength == 0)
4958 return;
4959
4960 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4961 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4962 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4963 if (!pIoc4)
4964 return;
4965 } else {
4966 ioc4_dma = ioc->spi_data.IocPg4_dma;
4967 iocpage4sz = ioc->spi_data.IocPg4Sz;
4968 }
4969
4970 /* Read the Page into dma memory.
4971 */
4972 cfg.physAddr = ioc4_dma;
4973 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4974 if (mpt_config(ioc, &cfg) == 0) {
4975 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4976 ioc->spi_data.IocPg4_dma = ioc4_dma;
4977 ioc->spi_data.IocPg4Sz = iocpage4sz;
4978 } else {
4979 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4980 ioc->spi_data.pIocPg4 = NULL;
4981 }
4982}
4983
4984static void
4985mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4986{
4987 IOCPage1_t *pIoc1;
4988 CONFIGPARMS cfg;
4989 ConfigPageHeader_t header;
4990 dma_addr_t ioc1_dma;
4991 int iocpage1sz = 0;
4992 u32 tmp;
4993
4994 /* Check the Coalescing Timeout in IOC Page 1
4995 */
4996 header.PageVersion = 0;
4997 header.PageLength = 0;
4998 header.PageNumber = 1;
4999 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005000 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 cfg.physAddr = -1;
5002 cfg.pageAddr = 0;
5003 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5004 cfg.dir = 0;
5005 cfg.timeout = 0;
5006 if (mpt_config(ioc, &cfg) != 0)
5007 return;
5008
5009 if (header.PageLength == 0)
5010 return;
5011
5012 /* Read Header good, alloc memory
5013 */
5014 iocpage1sz = header.PageLength * 4;
5015 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5016 if (!pIoc1)
5017 return;
5018
5019 /* Read the Page and check coalescing timeout
5020 */
5021 cfg.physAddr = ioc1_dma;
5022 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5023 if (mpt_config(ioc, &cfg) == 0) {
5024
5025 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5026 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5027 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5028
5029 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5030 ioc->name, tmp));
5031
5032 if (tmp > MPT_COALESCING_TIMEOUT) {
5033 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5034
5035 /* Write NVRAM and current
5036 */
5037 cfg.dir = 1;
5038 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5039 if (mpt_config(ioc, &cfg) == 0) {
5040 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5041 ioc->name, MPT_COALESCING_TIMEOUT));
5042
5043 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5044 if (mpt_config(ioc, &cfg) == 0) {
5045 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5046 ioc->name, MPT_COALESCING_TIMEOUT));
5047 } else {
5048 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5049 ioc->name));
5050 }
5051
5052 } else {
5053 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5054 ioc->name));
5055 }
5056 }
5057
5058 } else {
5059 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5060 }
5061 }
5062
5063 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5064
5065 return;
5066}
5067
5068/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5069/*
5070 * SendEventNotification - Send EventNotification (on or off) request
5071 * to MPT adapter.
5072 * @ioc: Pointer to MPT_ADAPTER structure
5073 * @EvSwitch: Event switch flags
5074 */
5075static int
5076SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5077{
5078 EventNotification_t *evnp;
5079
5080 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5081 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005082 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 ioc->name));
5084 return 0;
5085 }
5086 memset(evnp, 0, sizeof(*evnp));
5087
Moore, Eric3a892be2006-03-14 09:14:03 -07005088 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089
5090 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5091 evnp->ChainOffset = 0;
5092 evnp->MsgFlags = 0;
5093 evnp->Switch = EvSwitch;
5094
5095 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5096
5097 return 0;
5098}
5099
5100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5101/**
5102 * SendEventAck - Send EventAck request to MPT adapter.
5103 * @ioc: Pointer to MPT_ADAPTER structure
5104 * @evnp: Pointer to original EventNotification request
5105 */
5106static int
5107SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5108{
5109 EventAck_t *pAck;
5110
5111 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005112 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5113 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5114 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5115 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 return -1;
5117 }
5118 memset(pAck, 0, sizeof(*pAck));
5119
5120 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5121
5122 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5123 pAck->ChainOffset = 0;
5124 pAck->MsgFlags = 0;
5125 pAck->Event = evnp->Event;
5126 pAck->EventContext = evnp->EventContext;
5127
5128 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5129
5130 return 0;
5131}
5132
5133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5134/**
5135 * mpt_config - Generic function to issue config message
5136 * @ioc - Pointer to an adapter structure
5137 * @cfg - Pointer to a configuration structure. Struct contains
5138 * action, page address, direction, physical address
5139 * and pointer to a configuration page header
5140 * Page header is updated.
5141 *
5142 * Returns 0 for success
5143 * -EPERM if not allowed due to ISR context
5144 * -EAGAIN if no msg frames currently available
5145 * -EFAULT for non-successful reply or no reply (timeout)
5146 */
5147int
5148mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5149{
5150 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005151 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 MPT_FRAME_HDR *mf;
5153 unsigned long flags;
5154 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005155 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 int in_isr;
5157
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005158 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 * to be in ISR context, because that is fatal!
5160 */
5161 in_isr = in_interrupt();
5162 if (in_isr) {
5163 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5164 ioc->name));
5165 return -EPERM;
5166 }
5167
5168 /* Get and Populate a free Frame
5169 */
5170 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5171 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5172 ioc->name));
5173 return -EAGAIN;
5174 }
5175 pReq = (Config_t *)mf;
5176 pReq->Action = pCfg->action;
5177 pReq->Reserved = 0;
5178 pReq->ChainOffset = 0;
5179 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005180
5181 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 pReq->ExtPageLength = 0;
5183 pReq->ExtPageType = 0;
5184 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005185
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 for (ii=0; ii < 8; ii++)
5187 pReq->Reserved2[ii] = 0;
5188
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005189 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5190 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5191 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5192 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5193
5194 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5195 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5196 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5197 pReq->ExtPageType = pExtHdr->ExtPageType;
5198 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5199
5200 /* Page Length must be treated as a reserved field for the extended header. */
5201 pReq->Header.PageLength = 0;
5202 }
5203
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5205
5206 /* Add a SGE to the config request.
5207 */
5208 if (pCfg->dir)
5209 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5210 else
5211 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5212
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005213 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5214 flagsLength |= pExtHdr->ExtPageLength * 4;
5215
5216 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5217 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5218 }
5219 else {
5220 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5221
5222 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5223 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225
5226 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5227
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 /* Append pCfg pointer to end of mf
5229 */
5230 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5231
5232 /* Initalize the timer
5233 */
5234 init_timer(&pCfg->timer);
5235 pCfg->timer.data = (unsigned long) ioc;
5236 pCfg->timer.function = mpt_timer_expired;
5237 pCfg->wait_done = 0;
5238
5239 /* Set the timer; ensure 10 second minimum */
5240 if (pCfg->timeout < 10)
5241 pCfg->timer.expires = jiffies + HZ*10;
5242 else
5243 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5244
5245 /* Add to end of Q, set timer and then issue this command */
5246 spin_lock_irqsave(&ioc->FreeQlock, flags);
5247 list_add_tail(&pCfg->linkage, &ioc->configQ);
5248 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5249
5250 add_timer(&pCfg->timer);
5251 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5252 wait_event(mpt_waitq, pCfg->wait_done);
5253
5254 /* mf has been freed - do not access */
5255
5256 rc = pCfg->status;
5257
5258 return rc;
5259}
5260
5261/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262/*
5263 * mpt_timer_expired - Call back for timer process.
5264 * Used only internal config functionality.
5265 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5266 */
5267static void
5268mpt_timer_expired(unsigned long data)
5269{
5270 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5271
5272 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5273
5274 /* Perform a FW reload */
5275 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5276 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5277
5278 /* No more processing.
5279 * Hard reset clean-up will wake up
5280 * process and free all resources.
5281 */
5282 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5283
5284 return;
5285}
5286
5287/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5288/*
5289 * mpt_ioc_reset - Base cleanup for hard reset
5290 * @ioc: Pointer to the adapter structure
5291 * @reset_phase: Indicates pre- or post-reset functionality
5292 *
5293 * Remark: Free's resources with internally generated commands.
5294 */
5295static int
5296mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5297{
5298 CONFIGPARMS *pCfg;
5299 unsigned long flags;
5300
5301 dprintk((KERN_WARNING MYNAM
5302 ": IOC %s_reset routed to MPT base driver!\n",
5303 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5304 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5305
5306 if (reset_phase == MPT_IOC_SETUP_RESET) {
5307 ;
5308 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5309 /* If the internal config Q is not empty -
5310 * delete timer. MF resources will be freed when
5311 * the FIFO's are primed.
5312 */
5313 spin_lock_irqsave(&ioc->FreeQlock, flags);
5314 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5315 del_timer(&pCfg->timer);
5316 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5317
5318 } else {
5319 CONFIGPARMS *pNext;
5320
5321 /* Search the configQ for internal commands.
5322 * Flush the Q, and wake up all suspended threads.
5323 */
5324 spin_lock_irqsave(&ioc->FreeQlock, flags);
5325 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5326 list_del(&pCfg->linkage);
5327
5328 pCfg->status = MPT_CONFIG_ERROR;
5329 pCfg->wait_done = 1;
5330 wake_up(&mpt_waitq);
5331 }
5332 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5333 }
5334
5335 return 1; /* currently means nothing really */
5336}
5337
5338
5339#ifdef CONFIG_PROC_FS /* { */
5340/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5341/*
5342 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5343 */
5344/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5345/*
5346 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5347 *
5348 * Returns 0 for success, non-zero for failure.
5349 */
5350static int
5351procmpt_create(void)
5352{
5353 struct proc_dir_entry *ent;
5354
5355 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5356 if (mpt_proc_root_dir == NULL)
5357 return -ENOTDIR;
5358
5359 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5360 if (ent)
5361 ent->read_proc = procmpt_summary_read;
5362
5363 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5364 if (ent)
5365 ent->read_proc = procmpt_version_read;
5366
5367 return 0;
5368}
5369
5370/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5371/*
5372 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5373 *
5374 * Returns 0 for success, non-zero for failure.
5375 */
5376static void
5377procmpt_destroy(void)
5378{
5379 remove_proc_entry("version", mpt_proc_root_dir);
5380 remove_proc_entry("summary", mpt_proc_root_dir);
5381 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5382}
5383
5384/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5385/*
5386 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5387 * or from /proc/mpt/iocN/summary.
5388 * @buf: Pointer to area to write information
5389 * @start: Pointer to start pointer
5390 * @offset: Offset to start writing
5391 * @request:
5392 * @eof: Pointer to EOF integer
5393 * @data: Pointer
5394 *
5395 * Returns number of characters written to process performing the read.
5396 */
5397static int
5398procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5399{
5400 MPT_ADAPTER *ioc;
5401 char *out = buf;
5402 int len;
5403
5404 if (data) {
5405 int more = 0;
5406
5407 ioc = data;
5408 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5409
5410 out += more;
5411 } else {
5412 list_for_each_entry(ioc, &ioc_list, list) {
5413 int more = 0;
5414
5415 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5416
5417 out += more;
5418 if ((out-buf) >= request)
5419 break;
5420 }
5421 }
5422
5423 len = out - buf;
5424
5425 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5426}
5427
5428/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5429/*
5430 * procmpt_version_read - Handle read request from /proc/mpt/version.
5431 * @buf: Pointer to area to write information
5432 * @start: Pointer to start pointer
5433 * @offset: Offset to start writing
5434 * @request:
5435 * @eof: Pointer to EOF integer
5436 * @data: Pointer
5437 *
5438 * Returns number of characters written to process performing the read.
5439 */
5440static int
5441procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5442{
5443 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005444 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 char *drvname;
5446 int len;
5447
5448 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5449 len += sprintf(buf+len, " Fusion MPT base driver\n");
5450
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005451 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5453 drvname = NULL;
5454 if (MptCallbacks[ii]) {
5455 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005456 case MPTSPI_DRIVER:
5457 if (!scsi++) drvname = "SPI host";
5458 break;
5459 case MPTFC_DRIVER:
5460 if (!fc++) drvname = "FC host";
5461 break;
5462 case MPTSAS_DRIVER:
5463 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 break;
5465 case MPTLAN_DRIVER:
5466 if (!lan++) drvname = "LAN";
5467 break;
5468 case MPTSTM_DRIVER:
5469 if (!targ++) drvname = "SCSI target";
5470 break;
5471 case MPTCTL_DRIVER:
5472 if (!ctl++) drvname = "ioctl";
5473 break;
5474 }
5475
5476 if (drvname)
5477 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5478 }
5479 }
5480
5481 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5482}
5483
5484/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5485/*
5486 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5487 * @buf: Pointer to area to write information
5488 * @start: Pointer to start pointer
5489 * @offset: Offset to start writing
5490 * @request:
5491 * @eof: Pointer to EOF integer
5492 * @data: Pointer
5493 *
5494 * Returns number of characters written to process performing the read.
5495 */
5496static int
5497procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5498{
5499 MPT_ADAPTER *ioc = data;
5500 int len;
5501 char expVer[32];
5502 int sz;
5503 int p;
5504
5505 mpt_get_fw_exp_ver(expVer, ioc);
5506
5507 len = sprintf(buf, "%s:", ioc->name);
5508 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5509 len += sprintf(buf+len, " (f/w download boot flag set)");
5510// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5511// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5512
5513 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5514 ioc->facts.ProductID,
5515 ioc->prod_name);
5516 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5517 if (ioc->facts.FWImageSize)
5518 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5519 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5520 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5521 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5522
5523 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5524 ioc->facts.CurrentHostMfaHighAddr);
5525 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5526 ioc->facts.CurrentSenseBufferHighAddr);
5527
5528 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5529 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5530
5531 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5532 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5533 /*
5534 * Rounding UP to nearest 4-kB boundary here...
5535 */
5536 sz = (ioc->req_sz * ioc->req_depth) + 128;
5537 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5538 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5539 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5540 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5541 4*ioc->facts.RequestFrameSize,
5542 ioc->facts.GlobalCredits);
5543
5544 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5545 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5546 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5547 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5548 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5549 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5550 ioc->facts.CurReplyFrameSize,
5551 ioc->facts.ReplyQueueDepth);
5552
5553 len += sprintf(buf+len, " MaxDevices = %d\n",
5554 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5555 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5556
5557 /* per-port info */
5558 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5559 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5560 p+1,
5561 ioc->facts.NumberOfPorts);
5562 if (ioc->bus_type == FC) {
5563 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5564 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5565 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5566 a[5], a[4], a[3], a[2], a[1], a[0]);
5567 }
5568 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5569 ioc->fc_port_page0[p].WWNN.High,
5570 ioc->fc_port_page0[p].WWNN.Low,
5571 ioc->fc_port_page0[p].WWPN.High,
5572 ioc->fc_port_page0[p].WWPN.Low);
5573 }
5574 }
5575
5576 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5577}
5578
5579#endif /* CONFIG_PROC_FS } */
5580
5581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5582static void
5583mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5584{
5585 buf[0] ='\0';
5586 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5587 sprintf(buf, " (Exp %02d%02d)",
5588 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5589 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5590
5591 /* insider hack! */
5592 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5593 strcat(buf, " [MDBG]");
5594 }
5595}
5596
5597/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5598/**
5599 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5600 * @ioc: Pointer to MPT_ADAPTER structure
5601 * @buffer: Pointer to buffer where IOC summary info should be written
5602 * @size: Pointer to number of bytes we wrote (set by this routine)
5603 * @len: Offset at which to start writing in buffer
5604 * @showlan: Display LAN stuff?
5605 *
5606 * This routine writes (english readable) ASCII text, which represents
5607 * a summary of IOC information, to a buffer.
5608 */
5609void
5610mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5611{
5612 char expVer[32];
5613 int y;
5614
5615 mpt_get_fw_exp_ver(expVer, ioc);
5616
5617 /*
5618 * Shorter summary of attached ioc's...
5619 */
5620 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5621 ioc->name,
5622 ioc->prod_name,
5623 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5624 ioc->facts.FWVersion.Word,
5625 expVer,
5626 ioc->facts.NumberOfPorts,
5627 ioc->req_depth);
5628
5629 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5630 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5631 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5632 a[5], a[4], a[3], a[2], a[1], a[0]);
5633 }
5634
5635#ifndef __sparc__
5636 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
5637#else
5638 y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
5639#endif
5640
5641 if (!ioc->active)
5642 y += sprintf(buffer+len+y, " (disabled)");
5643
5644 y += sprintf(buffer+len+y, "\n");
5645
5646 *size = y;
5647}
5648
5649/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5650/*
5651 * Reset Handling
5652 */
5653/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5654/**
5655 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5656 * Management call based on input arg values. If TaskMgmt fails,
5657 * return associated SCSI request.
5658 * @ioc: Pointer to MPT_ADAPTER structure
5659 * @sleepFlag: Indicates if sleep or schedule must be called.
5660 *
5661 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5662 * or a non-interrupt thread. In the former, must not call schedule().
5663 *
5664 * Remark: A return of -1 is a FATAL error case, as it means a
5665 * FW reload/initialization failed.
5666 *
5667 * Returns 0 for SUCCESS or -1 if FAILED.
5668 */
5669int
5670mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5671{
5672 int rc;
5673 unsigned long flags;
5674
5675 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5676#ifdef MFCNT
5677 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5678 printk("MF count 0x%x !\n", ioc->mfcnt);
5679#endif
5680
5681 /* Reset the adapter. Prevent more than 1 call to
5682 * mpt_do_ioc_recovery at any instant in time.
5683 */
5684 spin_lock_irqsave(&ioc->diagLock, flags);
5685 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5686 spin_unlock_irqrestore(&ioc->diagLock, flags);
5687 return 0;
5688 } else {
5689 ioc->diagPending = 1;
5690 }
5691 spin_unlock_irqrestore(&ioc->diagLock, flags);
5692
5693 /* FIXME: If do_ioc_recovery fails, repeat....
5694 */
5695
5696 /* The SCSI driver needs to adjust timeouts on all current
5697 * commands prior to the diagnostic reset being issued.
5698 * Prevents timeouts occuring during a diagnostic reset...very bad.
5699 * For all other protocol drivers, this is a no-op.
5700 */
5701 {
5702 int ii;
5703 int r = 0;
5704
5705 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5706 if (MptResetHandlers[ii]) {
5707 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5708 ioc->name, ii));
5709 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
5710 if (ioc->alt_ioc) {
5711 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5712 ioc->name, ioc->alt_ioc->name, ii));
5713 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
5714 }
5715 }
5716 }
5717 }
5718
5719 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5720 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5721 rc, ioc->name);
5722 }
5723 ioc->reload_fw = 0;
5724 if (ioc->alt_ioc)
5725 ioc->alt_ioc->reload_fw = 0;
5726
5727 spin_lock_irqsave(&ioc->diagLock, flags);
5728 ioc->diagPending = 0;
5729 if (ioc->alt_ioc)
5730 ioc->alt_ioc->diagPending = 0;
5731 spin_unlock_irqrestore(&ioc->diagLock, flags);
5732
5733 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5734
5735 return rc;
5736}
5737
Eric Moore509e5e52006-04-26 13:22:37 -06005738# define EVENT_DESCR_STR_SZ 100
5739
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005741static void
5742EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743{
Eric Moore509e5e52006-04-26 13:22:37 -06005744 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745
5746 switch(event) {
5747 case MPI_EVENT_NONE:
5748 ds = "None";
5749 break;
5750 case MPI_EVENT_LOG_DATA:
5751 ds = "Log Data";
5752 break;
5753 case MPI_EVENT_STATE_CHANGE:
5754 ds = "State Change";
5755 break;
5756 case MPI_EVENT_UNIT_ATTENTION:
5757 ds = "Unit Attention";
5758 break;
5759 case MPI_EVENT_IOC_BUS_RESET:
5760 ds = "IOC Bus Reset";
5761 break;
5762 case MPI_EVENT_EXT_BUS_RESET:
5763 ds = "External Bus Reset";
5764 break;
5765 case MPI_EVENT_RESCAN:
5766 ds = "Bus Rescan Event";
5767 /* Ok, do we need to do anything here? As far as
5768 I can tell, this is when a new device gets added
5769 to the loop. */
5770 break;
5771 case MPI_EVENT_LINK_STATUS_CHANGE:
5772 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5773 ds = "Link Status(FAILURE) Change";
5774 else
5775 ds = "Link Status(ACTIVE) Change";
5776 break;
5777 case MPI_EVENT_LOOP_STATE_CHANGE:
5778 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5779 ds = "Loop State(LIP) Change";
5780 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005781 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 else
Eric Moore509e5e52006-04-26 13:22:37 -06005783 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 break;
5785 case MPI_EVENT_LOGOUT:
5786 ds = "Logout";
5787 break;
5788 case MPI_EVENT_EVENT_CHANGE:
5789 if (evData0)
5790 ds = "Events(ON) Change";
5791 else
5792 ds = "Events(OFF) Change";
5793 break;
5794 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005795 {
5796 u8 ReasonCode = (u8)(evData0 >> 16);
5797 switch (ReasonCode) {
5798 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5799 ds = "Integrated Raid: Volume Created";
5800 break;
5801 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5802 ds = "Integrated Raid: Volume Deleted";
5803 break;
5804 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5805 ds = "Integrated Raid: Volume Settings Changed";
5806 break;
5807 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5808 ds = "Integrated Raid: Volume Status Changed";
5809 break;
5810 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5811 ds = "Integrated Raid: Volume Physdisk Changed";
5812 break;
5813 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5814 ds = "Integrated Raid: Physdisk Created";
5815 break;
5816 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5817 ds = "Integrated Raid: Physdisk Deleted";
5818 break;
5819 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5820 ds = "Integrated Raid: Physdisk Settings Changed";
5821 break;
5822 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5823 ds = "Integrated Raid: Physdisk Status Changed";
5824 break;
5825 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5826 ds = "Integrated Raid: Domain Validation Needed";
5827 break;
5828 case MPI_EVENT_RAID_RC_SMART_DATA :
5829 ds = "Integrated Raid; Smart Data";
5830 break;
5831 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5832 ds = "Integrated Raid: Replace Action Started";
5833 break;
5834 default:
5835 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005837 }
5838 break;
5839 }
5840 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5841 ds = "SCSI Device Status Change";
5842 break;
5843 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5844 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005845 u8 id = (u8)(evData0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005846 u8 ReasonCode = (u8)(evData0 >> 16);
5847 switch (ReasonCode) {
5848 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005849 snprintf(evStr, EVENT_DESCR_STR_SZ,
5850 "SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005851 break;
5852 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005853 snprintf(evStr, EVENT_DESCR_STR_SZ,
5854 "SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005855 break;
5856 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005857 snprintf(evStr, EVENT_DESCR_STR_SZ,
5858 "SAS Device Status Change: SMART Data: id=%d",
5859 id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005860 break;
5861 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005862 snprintf(evStr, EVENT_DESCR_STR_SZ,
5863 "SAS Device Status Change: No Persistancy "
5864 "Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005865 break;
5866 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005867 snprintf(evStr, EVENT_DESCR_STR_SZ,
5868 "SAS Device Status Change: Unknown: id=%d", id);
5869 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005870 }
5871 break;
5872 }
5873 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5874 ds = "Bus Timer Expired";
5875 break;
5876 case MPI_EVENT_QUEUE_FULL:
5877 ds = "Queue Full";
5878 break;
5879 case MPI_EVENT_SAS_SES:
5880 ds = "SAS SES Event";
5881 break;
5882 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5883 ds = "Persistent Table Full";
5884 break;
5885 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005886 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005887 u8 LinkRates = (u8)(evData0 >> 8);
5888 u8 PhyNumber = (u8)(evData0);
5889 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5890 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5891 switch (LinkRates) {
5892 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06005893 snprintf(evStr, EVENT_DESCR_STR_SZ,
5894 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005895 " Rate Unknown",PhyNumber);
5896 break;
5897 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06005898 snprintf(evStr, EVENT_DESCR_STR_SZ,
5899 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005900 " Phy Disabled",PhyNumber);
5901 break;
5902 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06005903 snprintf(evStr, EVENT_DESCR_STR_SZ,
5904 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005905 " Failed Speed Nego",PhyNumber);
5906 break;
5907 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06005908 snprintf(evStr, EVENT_DESCR_STR_SZ,
5909 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005910 " Sata OOB Completed",PhyNumber);
5911 break;
5912 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06005913 snprintf(evStr, EVENT_DESCR_STR_SZ,
5914 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005915 " Rate 1.5 Gbps",PhyNumber);
5916 break;
5917 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06005918 snprintf(evStr, EVENT_DESCR_STR_SZ,
5919 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005920 " Rate 3.0 Gpbs",PhyNumber);
5921 break;
5922 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005923 snprintf(evStr, EVENT_DESCR_STR_SZ,
5924 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07005925 break;
5926 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005927 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005928 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005929 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5930 ds = "SAS Discovery Error";
5931 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005932 case MPI_EVENT_IR_RESYNC_UPDATE:
5933 {
5934 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06005935 snprintf(evStr, EVENT_DESCR_STR_SZ,
5936 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07005937 break;
5938 }
5939 case MPI_EVENT_IR2:
5940 {
5941 u8 ReasonCode = (u8)(evData0 >> 16);
5942 switch (ReasonCode) {
5943 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5944 ds = "IR2: LD State Changed";
5945 break;
5946 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5947 ds = "IR2: PD State Changed";
5948 break;
5949 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5950 ds = "IR2: Bad Block Table Full";
5951 break;
5952 case MPI_EVENT_IR2_RC_PD_INSERTED:
5953 ds = "IR2: PD Inserted";
5954 break;
5955 case MPI_EVENT_IR2_RC_PD_REMOVED:
5956 ds = "IR2: PD Removed";
5957 break;
5958 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5959 ds = "IR2: Foreign CFG Detected";
5960 break;
5961 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5962 ds = "IR2: Rebuild Medium Error";
5963 break;
5964 default:
5965 ds = "IR2";
5966 break;
5967 }
5968 break;
5969 }
5970 case MPI_EVENT_SAS_DISCOVERY:
5971 {
5972 if (evData0)
5973 ds = "SAS Discovery: Start";
5974 else
5975 ds = "SAS Discovery: Stop";
5976 break;
5977 }
5978 case MPI_EVENT_LOG_ENTRY_ADDED:
5979 ds = "SAS Log Entry Added";
5980 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005981
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 /*
5983 * MPT base "custom" events may be added here...
5984 */
5985 default:
5986 ds = "Unknown";
5987 break;
5988 }
Eric Moore509e5e52006-04-26 13:22:37 -06005989 if (ds)
5990 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991}
5992
5993/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5994/*
5995 * ProcessEventNotification - Route a received EventNotificationReply to
5996 * all currently regeistered event handlers.
5997 * @ioc: Pointer to MPT_ADAPTER structure
5998 * @pEventReply: Pointer to EventNotification reply frame
5999 * @evHandlers: Pointer to integer, number of event handlers
6000 *
6001 * Returns sum of event handlers return values.
6002 */
6003static int
6004ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6005{
6006 u16 evDataLen;
6007 u32 evData0 = 0;
6008// u32 evCtx;
6009 int ii;
6010 int r = 0;
6011 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006012 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013 u8 event;
6014
6015 /*
6016 * Do platform normalization of values
6017 */
6018 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6019// evCtx = le32_to_cpu(pEventReply->EventContext);
6020 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6021 if (evDataLen) {
6022 evData0 = le32_to_cpu(pEventReply->Data[0]);
6023 }
6024
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006025 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07006026 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006028 event,
6029 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030
Moore, Eric3a892be2006-03-14 09:14:03 -07006031#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6033 for (ii = 0; ii < evDataLen; ii++)
6034 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6035 printk("\n");
6036#endif
6037
6038 /*
6039 * Do general / base driver event processing
6040 */
6041 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6043 if (evDataLen) {
6044 u8 evState = evData0 & 0xFF;
6045
6046 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6047
6048 /* Update EventState field in cached IocFacts */
6049 if (ioc->facts.Function) {
6050 ioc->facts.EventState = evState;
6051 }
6052 }
6053 break;
Moore, Ericece50912006-01-16 18:53:19 -07006054 case MPI_EVENT_INTEGRATED_RAID:
6055 mptbase_raid_process_event_data(ioc,
6056 (MpiEventDataRaid_t *)pEventReply->Data);
6057 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006058 default:
6059 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 }
6061
6062 /*
6063 * Should this event be logged? Events are written sequentially.
6064 * When buffer is full, start again at the top.
6065 */
6066 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6067 int idx;
6068
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006069 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070
6071 ioc->events[idx].event = event;
6072 ioc->events[idx].eventContext = ioc->eventContext;
6073
6074 for (ii = 0; ii < 2; ii++) {
6075 if (ii < evDataLen)
6076 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6077 else
6078 ioc->events[idx].data[ii] = 0;
6079 }
6080
6081 ioc->eventContext++;
6082 }
6083
6084
6085 /*
6086 * Call each currently registered protocol event handler.
6087 */
6088 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6089 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006090 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091 ioc->name, ii));
6092 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6093 handlers++;
6094 }
6095 }
6096 /* FIXME? Examine results here? */
6097
6098 /*
6099 * If needed, send (a single) EventAck.
6100 */
6101 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006102 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006103 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006104 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006105 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 ioc->name, ii));
6107 }
6108 }
6109
6110 *evHandlers = handlers;
6111 return r;
6112}
6113
6114/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6115/*
6116 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6117 * @ioc: Pointer to MPT_ADAPTER structure
6118 * @log_info: U32 LogInfo reply word from the IOC
6119 *
6120 * Refer to lsi/fc_log.h.
6121 */
6122static void
6123mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6124{
6125 static char *subcl_str[8] = {
6126 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6127 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6128 };
6129 u8 subcl = (log_info >> 24) & 0x7;
6130
6131 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6132 ioc->name, log_info, subcl_str[subcl]);
6133}
6134
6135/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6136/*
Moore, Eric335a9412006-01-17 17:06:23 -07006137 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006138 * @ioc: Pointer to MPT_ADAPTER structure
6139 * @mr: Pointer to MPT reply frame
6140 * @log_info: U32 LogInfo word from the IOC
6141 *
6142 * Refer to lsi/sp_log.h.
6143 */
6144static void
Moore, Eric335a9412006-01-17 17:06:23 -07006145mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146{
6147 u32 info = log_info & 0x00FF0000;
6148 char *desc = "unknown";
6149
6150 switch (info) {
6151 case 0x00010000:
6152 desc = "bug! MID not found";
6153 if (ioc->reload_fw == 0)
6154 ioc->reload_fw++;
6155 break;
6156
6157 case 0x00020000:
6158 desc = "Parity Error";
6159 break;
6160
6161 case 0x00030000:
6162 desc = "ASYNC Outbound Overrun";
6163 break;
6164
6165 case 0x00040000:
6166 desc = "SYNC Offset Error";
6167 break;
6168
6169 case 0x00050000:
6170 desc = "BM Change";
6171 break;
6172
6173 case 0x00060000:
6174 desc = "Msg In Overflow";
6175 break;
6176
6177 case 0x00070000:
6178 desc = "DMA Error";
6179 break;
6180
6181 case 0x00080000:
6182 desc = "Outbound DMA Overrun";
6183 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006184
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 case 0x00090000:
6186 desc = "Task Management";
6187 break;
6188
6189 case 0x000A0000:
6190 desc = "Device Problem";
6191 break;
6192
6193 case 0x000B0000:
6194 desc = "Invalid Phase Change";
6195 break;
6196
6197 case 0x000C0000:
6198 desc = "Untagged Table Size";
6199 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006200
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201 }
6202
6203 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6204}
6205
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006206/* strings for sas loginfo */
6207 static char *originator_str[] = {
6208 "IOP", /* 00h */
6209 "PL", /* 01h */
6210 "IR" /* 02h */
6211 };
6212 static char *iop_code_str[] = {
6213 NULL, /* 00h */
6214 "Invalid SAS Address", /* 01h */
6215 NULL, /* 02h */
6216 "Invalid Page", /* 03h */
6217 NULL, /* 04h */
6218 "Task Terminated" /* 05h */
6219 };
6220 static char *pl_code_str[] = {
6221 NULL, /* 00h */
6222 "Open Failure", /* 01h */
6223 "Invalid Scatter Gather List", /* 02h */
6224 "Wrong Relative Offset or Frame Length", /* 03h */
6225 "Frame Transfer Error", /* 04h */
6226 "Transmit Frame Connected Low", /* 05h */
6227 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6228 "SATA Read Log Receive Data Error", /* 07h */
6229 "SATA NCQ Fail All Commands After Error", /* 08h */
6230 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6231 "Receive Frame Invalid Message", /* 0Ah */
6232 "Receive Context Message Valid Error", /* 0Bh */
6233 "Receive Frame Current Frame Error", /* 0Ch */
6234 "SATA Link Down", /* 0Dh */
6235 "Discovery SATA Init W IOS", /* 0Eh */
6236 "Config Invalid Page", /* 0Fh */
6237 "Discovery SATA Init Timeout", /* 10h */
6238 "Reset", /* 11h */
6239 "Abort", /* 12h */
6240 "IO Not Yet Executed", /* 13h */
6241 "IO Executed", /* 14h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006242 "Persistant Reservation Out Not Affiliation Owner", /* 15h */
6243 "Open Transmit DMA Abort", /* 16h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006244 NULL, /* 17h */
6245 NULL, /* 18h */
6246 NULL, /* 19h */
6247 NULL, /* 1Ah */
6248 NULL, /* 1Bh */
6249 NULL, /* 1Ch */
6250 NULL, /* 1Dh */
6251 NULL, /* 1Eh */
6252 NULL, /* 1Fh */
6253 "Enclosure Management" /* 20h */
6254 };
6255
6256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6257/*
6258 * mpt_sas_log_info - Log information returned from SAS IOC.
6259 * @ioc: Pointer to MPT_ADAPTER structure
6260 * @log_info: U32 LogInfo reply word from the IOC
6261 *
6262 * Refer to lsi/mpi_log_sas.h.
6263 */
6264static void
6265mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6266{
6267union loginfo_type {
6268 u32 loginfo;
6269 struct {
6270 u32 subcode:16;
6271 u32 code:8;
6272 u32 originator:4;
6273 u32 bus_type:4;
6274 }dw;
6275};
6276 union loginfo_type sas_loginfo;
6277 char *code_desc = NULL;
6278
6279 sas_loginfo.loginfo = log_info;
6280 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6281 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6282 return;
6283 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6284 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6285 code_desc = iop_code_str[sas_loginfo.dw.code];
6286 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6287 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6288 code_desc = pl_code_str[sas_loginfo.dw.code];
6289 }
6290
6291 if (code_desc != NULL)
6292 printk(MYIOC_s_INFO_FMT
6293 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6294 " SubCode(0x%04x)\n",
6295 ioc->name,
6296 log_info,
6297 originator_str[sas_loginfo.dw.originator],
6298 code_desc,
6299 sas_loginfo.dw.subcode);
6300 else
6301 printk(MYIOC_s_INFO_FMT
6302 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6303 " SubCode(0x%04x)\n",
6304 ioc->name,
6305 log_info,
6306 originator_str[sas_loginfo.dw.originator],
6307 sas_loginfo.dw.code,
6308 sas_loginfo.dw.subcode);
6309}
6310
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6312/*
6313 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6314 * @ioc: Pointer to MPT_ADAPTER structure
6315 * @ioc_status: U32 IOCStatus word from IOC
6316 * @mf: Pointer to MPT request frame
6317 *
6318 * Refer to lsi/mpi.h.
6319 */
6320static void
6321mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6322{
6323 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
6324 char *desc = "";
6325
6326 switch (status) {
6327 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6328 desc = "Invalid Function";
6329 break;
6330
6331 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6332 desc = "Busy";
6333 break;
6334
6335 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6336 desc = "Invalid SGL";
6337 break;
6338
6339 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6340 desc = "Internal Error";
6341 break;
6342
6343 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6344 desc = "Reserved";
6345 break;
6346
6347 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6348 desc = "Insufficient Resources";
6349 break;
6350
6351 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6352 desc = "Invalid Field";
6353 break;
6354
6355 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6356 desc = "Invalid State";
6357 break;
6358
6359 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6360 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6361 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6362 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6363 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6364 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6365 /* No message for Config IOCStatus values */
6366 break;
6367
6368 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6369 /* No message for recovered error
6370 desc = "SCSI Recovered Error";
6371 */
6372 break;
6373
6374 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6375 desc = "SCSI Invalid Bus";
6376 break;
6377
6378 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6379 desc = "SCSI Invalid TargetID";
6380 break;
6381
6382 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6383 {
6384 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6385 U8 cdb = pScsiReq->CDB[0];
6386 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6387 desc = "SCSI Device Not There";
6388 }
6389 break;
6390 }
6391
6392 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6393 desc = "SCSI Data Overrun";
6394 break;
6395
6396 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006397 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398 desc = "SCSI Data Underrun";
6399 */
6400 break;
6401
6402 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6403 desc = "SCSI I/O Data Error";
6404 break;
6405
6406 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6407 desc = "SCSI Protocol Error";
6408 break;
6409
6410 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6411 desc = "SCSI Task Terminated";
6412 break;
6413
6414 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6415 desc = "SCSI Residual Mismatch";
6416 break;
6417
6418 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6419 desc = "SCSI Task Management Failed";
6420 break;
6421
6422 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6423 desc = "SCSI IOC Terminated";
6424 break;
6425
6426 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6427 desc = "SCSI Ext Terminated";
6428 break;
6429
6430 default:
6431 desc = "Others";
6432 break;
6433 }
6434 if (desc != "")
6435 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6436}
6437
6438/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006439EXPORT_SYMBOL(mpt_attach);
6440EXPORT_SYMBOL(mpt_detach);
6441#ifdef CONFIG_PM
6442EXPORT_SYMBOL(mpt_resume);
6443EXPORT_SYMBOL(mpt_suspend);
6444#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006446EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447EXPORT_SYMBOL(mpt_register);
6448EXPORT_SYMBOL(mpt_deregister);
6449EXPORT_SYMBOL(mpt_event_register);
6450EXPORT_SYMBOL(mpt_event_deregister);
6451EXPORT_SYMBOL(mpt_reset_register);
6452EXPORT_SYMBOL(mpt_reset_deregister);
6453EXPORT_SYMBOL(mpt_device_driver_register);
6454EXPORT_SYMBOL(mpt_device_driver_deregister);
6455EXPORT_SYMBOL(mpt_get_msg_frame);
6456EXPORT_SYMBOL(mpt_put_msg_frame);
6457EXPORT_SYMBOL(mpt_free_msg_frame);
6458EXPORT_SYMBOL(mpt_add_sge);
6459EXPORT_SYMBOL(mpt_send_handshake_request);
6460EXPORT_SYMBOL(mpt_verify_adapter);
6461EXPORT_SYMBOL(mpt_GetIocState);
6462EXPORT_SYMBOL(mpt_print_ioc_summary);
6463EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006464EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006465EXPORT_SYMBOL(mpt_HardResetHandler);
6466EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006467EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468EXPORT_SYMBOL(mpt_alloc_fw_memory);
6469EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006470EXPORT_SYMBOL(mptbase_sas_persist_operation);
Michael Reed05e8ec12006-01-13 14:31:54 -06006471EXPORT_SYMBOL(mptbase_GetFcPortPage0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006472
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473
6474/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6475/*
6476 * fusion_init - Fusion MPT base driver initialization routine.
6477 *
6478 * Returns 0 for success, non-zero for failure.
6479 */
6480static int __init
6481fusion_init(void)
6482{
6483 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006484
6485 show_mptmod_ver(my_NAME, my_VERSION);
6486 printk(KERN_INFO COPYRIGHT "\n");
6487
6488 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6489 MptCallbacks[i] = NULL;
6490 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6491 MptEvHandlers[i] = NULL;
6492 MptResetHandlers[i] = NULL;
6493 }
6494
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006495 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496 * EventNotification handling.
6497 */
6498 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6499
6500 /* Register for hard reset handling callbacks.
6501 */
6502 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6503 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6504 } else {
6505 /* FIXME! */
6506 }
6507
6508#ifdef CONFIG_PROC_FS
6509 (void) procmpt_create();
6510#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006511 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006512}
6513
6514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6515/*
6516 * fusion_exit - Perform driver unload cleanup.
6517 *
6518 * This routine frees all resources associated with each MPT adapter
6519 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6520 */
6521static void __exit
6522fusion_exit(void)
6523{
6524
6525 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6526
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527 mpt_reset_deregister(mpt_base_index);
6528
6529#ifdef CONFIG_PROC_FS
6530 procmpt_destroy();
6531#endif
6532}
6533
Linus Torvalds1da177e2005-04-16 15:20:36 -07006534module_init(fusion_init);
6535module_exit(fusion_exit);