blob: 266414ca2814e935b1d589f4c68aa7eed49c028e [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);
1192 spin_lock_init(&ioc->fc_rport_lock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001193 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
1195 /* Initialize the event logging.
1196 */
1197 ioc->eventTypes = 0; /* None */
1198 ioc->eventContext = 0;
1199 ioc->eventLogSize = 0;
1200 ioc->events = NULL;
1201
1202#ifdef MFCNT
1203 ioc->mfcnt = 0;
1204#endif
1205
1206 ioc->cached_fw = NULL;
1207
1208 /* Initilize SCSI Config Data structure
1209 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001210 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
1212 /* Initialize the running configQ head.
1213 */
1214 INIT_LIST_HEAD(&ioc->configQ);
1215
Michael Reed05e8ec12006-01-13 14:31:54 -06001216 /* Initialize the fc rport list head.
1217 */
1218 INIT_LIST_HEAD(&ioc->fc_rports);
1219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 /* Find lookup slot. */
1221 INIT_LIST_HEAD(&ioc->list);
1222 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 mem_phys = msize = 0;
1225 port = psize = 0;
1226 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1227 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1228 /* Get I/O space! */
1229 port = pci_resource_start(pdev, ii);
1230 psize = pci_resource_len(pdev,ii);
1231 } else {
1232 /* Get memmap */
1233 mem_phys = pci_resource_start(pdev, ii);
1234 msize = pci_resource_len(pdev,ii);
1235 break;
1236 }
1237 }
1238 ioc->mem_size = msize;
1239
1240 if (ii == DEVICE_COUNT_RESOURCE) {
1241 printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
1242 kfree(ioc);
1243 return -EINVAL;
1244 }
1245
1246 dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
1247 dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
1248
1249 mem = NULL;
1250 /* Get logical ptr for PciMem0 space */
1251 /*mem = ioremap(mem_phys, msize);*/
1252 mem = ioremap(mem_phys, 0x100);
1253 if (mem == NULL) {
1254 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1255 kfree(ioc);
1256 return -EINVAL;
1257 }
1258 ioc->memmap = mem;
1259 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1260
1261 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1262 &ioc->facts, &ioc->pfacts[0]));
1263
1264 ioc->mem_phys = mem_phys;
1265 ioc->chip = (SYSIF_REGS __iomem *)mem;
1266
1267 /* Save Port IO values in case we need to do downloadboot */
1268 {
1269 u8 *pmem = (u8*)port;
1270 ioc->pio_mem_phys = port;
1271 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1272 }
1273
1274 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1275 ioc->prod_name = "LSIFC909";
1276 ioc->bus_type = FC;
1277 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001278 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 ioc->prod_name = "LSIFC929";
1280 ioc->bus_type = FC;
1281 }
1282 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1283 ioc->prod_name = "LSIFC919";
1284 ioc->bus_type = FC;
1285 }
1286 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1287 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1288 ioc->bus_type = FC;
1289 if (revision < XL_929) {
1290 ioc->prod_name = "LSIFC929X";
1291 /* 929X Chip Fix. Set Split transactions level
1292 * for PCIX. Set MOST bits to zero.
1293 */
1294 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1295 pcixcmd &= 0x8F;
1296 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1297 } else {
1298 ioc->prod_name = "LSIFC929XL";
1299 /* 929XL Chip Fix. Set MMRBC to 0x08.
1300 */
1301 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1302 pcixcmd |= 0x08;
1303 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1304 }
1305 }
1306 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1307 ioc->prod_name = "LSIFC919X";
1308 ioc->bus_type = FC;
1309 /* 919X Chip Fix. Set Split transactions level
1310 * for PCIX. Set MOST bits to zero.
1311 */
1312 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1313 pcixcmd &= 0x8F;
1314 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1315 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001316 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1317 ioc->prod_name = "LSIFC939X";
1318 ioc->bus_type = FC;
1319 ioc->errata_flag_1064 = 1;
1320 }
1321 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1322 ioc->prod_name = "LSIFC949X";
1323 ioc->bus_type = FC;
1324 ioc->errata_flag_1064 = 1;
1325 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001326 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1327 ioc->prod_name = "LSIFC949E";
1328 ioc->bus_type = FC;
1329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1331 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001332 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 /* 1030 Chip Fix. Disable Split transactions
1334 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1335 */
1336 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1337 if (revision < C0_1030) {
1338 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1339 pcixcmd &= 0x8F;
1340 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1341 }
1342 }
1343 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1344 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001345 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001347 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1348 ioc->prod_name = "LSISAS1064";
1349 ioc->bus_type = SAS;
1350 ioc->errata_flag_1064 = 1;
1351 }
1352 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) {
1353 ioc->prod_name = "LSISAS1066";
1354 ioc->bus_type = SAS;
1355 ioc->errata_flag_1064 = 1;
1356 }
1357 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1358 ioc->prod_name = "LSISAS1068";
1359 ioc->bus_type = SAS;
1360 ioc->errata_flag_1064 = 1;
1361 }
1362 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1363 ioc->prod_name = "LSISAS1064E";
1364 ioc->bus_type = SAS;
1365 }
1366 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) {
1367 ioc->prod_name = "LSISAS1066E";
1368 ioc->bus_type = SAS;
1369 }
1370 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1371 ioc->prod_name = "LSISAS1068E";
1372 ioc->bus_type = SAS;
1373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001375 if (ioc->errata_flag_1064)
1376 pci_disable_io_access(pdev);
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 sprintf(ioc->name, "ioc%d", ioc->id);
1379
1380 spin_lock_init(&ioc->FreeQlock);
1381
1382 /* Disable all! */
1383 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1384 ioc->active = 0;
1385 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1386
1387 /* Set lookup ptr. */
1388 list_add_tail(&ioc->list, &ioc_list);
1389
1390 ioc->pci_irq = -1;
1391 if (pdev->irq) {
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001392 if (mpt_msi_enable && !pci_enable_msi(pdev))
1393 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", ioc->name);
1394
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
1396
1397 if (r < 0) {
1398#ifndef __sparc__
1399 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
1400 ioc->name, pdev->irq);
1401#else
1402 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
1403 ioc->name, __irq_itoa(pdev->irq));
1404#endif
1405 list_del(&ioc->list);
1406 iounmap(mem);
1407 kfree(ioc);
1408 return -EBUSY;
1409 }
1410
1411 ioc->pci_irq = pdev->irq;
1412
1413 pci_set_master(pdev); /* ?? */
1414 pci_set_drvdata(pdev, ioc);
1415
1416#ifndef __sparc__
1417 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
1418#else
1419 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
1420#endif
1421 }
1422
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001423 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 */
1425 mpt_detect_bound_ports(ioc, pdev);
1426
James Bottomleyc92f2222006-03-01 09:02:49 -06001427 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1428 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 printk(KERN_WARNING MYNAM
1430 ": WARNING - %s did not initialize properly! (%d)\n",
1431 ioc->name, r);
1432
1433 list_del(&ioc->list);
1434 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001435 if (mpt_msi_enable)
1436 pci_disable_msi(pdev);
Moore, Eric335a9412006-01-17 17:06:23 -07001437 if (ioc->alt_ioc)
1438 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 iounmap(mem);
1440 kfree(ioc);
1441 pci_set_drvdata(pdev, NULL);
1442 return r;
1443 }
1444
1445 /* call per device driver probe entry point */
1446 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1447 if(MptDeviceDriverHandlers[ii] &&
1448 MptDeviceDriverHandlers[ii]->probe) {
1449 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1450 }
1451 }
1452
1453#ifdef CONFIG_PROC_FS
1454 /*
1455 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1456 */
1457 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1458 if (dent) {
1459 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1460 if (ent) {
1461 ent->read_proc = procmpt_iocinfo_read;
1462 ent->data = ioc;
1463 }
1464 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1465 if (ent) {
1466 ent->read_proc = procmpt_summary_read;
1467 ent->data = ioc;
1468 }
1469 }
1470#endif
1471
1472 return 0;
1473}
1474
1475/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1476/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001477 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 * @pdev: Pointer to pci_dev structure
1479 *
1480 */
1481
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001482void
1483mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484{
1485 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1486 char pname[32];
1487 int ii;
1488
1489 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1490 remove_proc_entry(pname, NULL);
1491 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1492 remove_proc_entry(pname, NULL);
1493 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1494 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001495
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 /* call per device driver remove entry point */
1497 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1498 if(MptDeviceDriverHandlers[ii] &&
1499 MptDeviceDriverHandlers[ii]->remove) {
1500 MptDeviceDriverHandlers[ii]->remove(pdev);
1501 }
1502 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 /* Disable interrupts! */
1505 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1506
1507 ioc->active = 0;
1508 synchronize_irq(pdev->irq);
1509
1510 /* Clear any lingering interrupt */
1511 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1512
1513 CHIPREG_READ32(&ioc->chip->IntStatus);
1514
1515 mpt_adapter_dispose(ioc);
1516
1517 pci_set_drvdata(pdev, NULL);
1518}
1519
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520/**************************************************************************
1521 * Power Management
1522 */
1523#ifdef CONFIG_PM
1524/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1525/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001526 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 *
1528 *
1529 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001530int
1531mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
1533 u32 device_state;
1534 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
Pavel Machek2a569572005-07-07 17:56:40 -07001536 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
1538 printk(MYIOC_s_INFO_FMT
1539 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1540 ioc->name, pdev, pci_name(pdev), device_state);
1541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 pci_save_state(pdev);
1543
1544 /* put ioc into READY_STATE */
1545 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1546 printk(MYIOC_s_ERR_FMT
1547 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1548 }
1549
1550 /* disable interrupts */
1551 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1552 ioc->active = 0;
1553
1554 /* Clear any lingering interrupt */
1555 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1556
1557 pci_disable_device(pdev);
1558 pci_set_power_state(pdev, device_state);
1559
1560 return 0;
1561}
1562
1563/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1564/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001565 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 *
1567 *
1568 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001569int
1570mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571{
1572 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1573 u32 device_state = pdev->current_state;
1574 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001575
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 printk(MYIOC_s_INFO_FMT
1577 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1578 ioc->name, pdev, pci_name(pdev), device_state);
1579
1580 pci_set_power_state(pdev, 0);
1581 pci_restore_state(pdev);
1582 pci_enable_device(pdev);
1583
1584 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001585 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 ioc->active = 1;
1587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 printk(MYIOC_s_INFO_FMT
1589 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1590 ioc->name,
1591 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1592 CHIPREG_READ32(&ioc->chip->Doorbell));
1593
1594 /* bring ioc to operational state */
1595 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1596 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1597 printk(MYIOC_s_INFO_FMT
1598 "pci-resume: Cannot recover, error:[%x]\n",
1599 ioc->name, recovery_state);
1600 } else {
1601 printk(MYIOC_s_INFO_FMT
1602 "pci-resume: success\n", ioc->name);
1603 }
1604
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 return 0;
1606}
1607#endif
1608
1609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1610/*
1611 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1612 * @ioc: Pointer to MPT adapter structure
1613 * @reason: Event word / reason
1614 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1615 *
1616 * This routine performs all the steps necessary to bring the IOC
1617 * to a OPERATIONAL state.
1618 *
1619 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1620 * MPT adapter.
1621 *
1622 * Returns:
1623 * 0 for success
1624 * -1 if failed to get board READY
1625 * -2 if READY but IOCFacts Failed
1626 * -3 if READY but PrimeIOCFifos Failed
1627 * -4 if READY but IOCInit Failed
1628 */
1629static int
1630mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1631{
1632 int hard_reset_done = 0;
1633 int alt_ioc_ready = 0;
1634 int hard;
1635 int rc=0;
1636 int ii;
1637 int handlers;
1638 int ret = 0;
1639 int reset_alt_ioc_active = 0;
1640
1641 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1642 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1643
1644 /* Disable reply interrupts (also blocks FreeQ) */
1645 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1646 ioc->active = 0;
1647
1648 if (ioc->alt_ioc) {
1649 if (ioc->alt_ioc->active)
1650 reset_alt_ioc_active = 1;
1651
1652 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1653 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1654 ioc->alt_ioc->active = 0;
1655 }
1656
1657 hard = 1;
1658 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1659 hard = 0;
1660
1661 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1662 if (hard_reset_done == -4) {
1663 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1664 ioc->name);
1665
1666 if (reset_alt_ioc_active && ioc->alt_ioc) {
1667 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1668 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1669 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001670 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 ioc->alt_ioc->active = 1;
1672 }
1673
1674 } else {
1675 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1676 ioc->name);
1677 }
1678 return -1;
1679 }
1680
1681 /* hard_reset_done = 0 if a soft reset was performed
1682 * and 1 if a hard reset was performed.
1683 */
1684 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1685 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1686 alt_ioc_ready = 1;
1687 else
1688 printk(KERN_WARNING MYNAM
1689 ": alt-%s: Not ready WARNING!\n",
1690 ioc->alt_ioc->name);
1691 }
1692
1693 for (ii=0; ii<5; ii++) {
1694 /* Get IOC facts! Allow 5 retries */
1695 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1696 break;
1697 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 if (ii == 5) {
1701 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1702 ret = -2;
1703 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1704 MptDisplayIocCapabilities(ioc);
1705 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 if (alt_ioc_ready) {
1708 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1709 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1710 /* Retry - alt IOC was initialized once
1711 */
1712 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1713 }
1714 if (rc) {
1715 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1716 alt_ioc_ready = 0;
1717 reset_alt_ioc_active = 0;
1718 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1719 MptDisplayIocCapabilities(ioc->alt_ioc);
1720 }
1721 }
1722
1723 /* Prime reply & request queues!
1724 * (mucho alloc's) Must be done prior to
1725 * init as upper addresses are needed for init.
1726 * If fails, continue with alt-ioc processing
1727 */
1728 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1729 ret = -3;
1730
1731 /* May need to check/upload firmware & data here!
1732 * If fails, continue with alt-ioc processing
1733 */
1734 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1735 ret = -4;
1736// NEW!
1737 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1738 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1739 ioc->alt_ioc->name, rc);
1740 alt_ioc_ready = 0;
1741 reset_alt_ioc_active = 0;
1742 }
1743
1744 if (alt_ioc_ready) {
1745 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1746 alt_ioc_ready = 0;
1747 reset_alt_ioc_active = 0;
1748 printk(KERN_WARNING MYNAM
1749 ": alt-%s: (%d) init failure WARNING!\n",
1750 ioc->alt_ioc->name, rc);
1751 }
1752 }
1753
1754 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1755 if (ioc->upload_fw) {
1756 ddlprintk((MYIOC_s_INFO_FMT
1757 "firmware upload required!\n", ioc->name));
1758
1759 /* Controller is not operational, cannot do upload
1760 */
1761 if (ret == 0) {
1762 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001763 if (rc == 0) {
1764 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1765 /*
1766 * Maintain only one pointer to FW memory
1767 * so there will not be two attempt to
1768 * downloadboot onboard dual function
1769 * chips (mpt_adapter_disable,
1770 * mpt_diag_reset)
1771 */
1772 ioc->cached_fw = NULL;
1773 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1774 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1775 }
1776 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001778 ret = -5;
1779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 }
1781 }
1782 }
1783
1784 if (ret == 0) {
1785 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001786 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 ioc->active = 1;
1788 }
1789
1790 if (reset_alt_ioc_active && ioc->alt_ioc) {
1791 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001792 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001794 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 ioc->alt_ioc->active = 1;
1796 }
1797
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001798 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 * and EventAck handling.
1800 */
1801 if ((ret == 0) && (!ioc->facts.EventState))
1802 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1803
1804 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1805 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1806
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001807 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1809 * recursive scenario; GetLanConfigPages times out, timer expired
1810 * routine calls HardResetHandler, which calls into here again,
1811 * and we try GetLanConfigPages again...
1812 */
1813 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001814 if (ioc->bus_type == SAS) {
1815
1816 /* clear persistency table */
1817 if(ioc->facts.IOCExceptions &
1818 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1819 ret = mptbase_sas_persist_operation(ioc,
1820 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1821 if(ret != 0)
1822 return -1;
1823 }
1824
1825 /* Find IM volumes
1826 */
1827 mpt_findImVolumes(ioc);
1828
1829 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 /*
1831 * Pre-fetch FC port WWN and stuff...
1832 * (FCPortPage0_t stuff)
1833 */
1834 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
Michael Reed05e8ec12006-01-13 14:31:54 -06001835 (void) mptbase_GetFcPortPage0(ioc, ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 }
1837
1838 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1839 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1840 /*
1841 * Pre-fetch the ports LAN MAC address!
1842 * (LANPage1_t stuff)
1843 */
1844 (void) GetLanConfigPages(ioc);
1845#ifdef MPT_DEBUG
1846 {
1847 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1848 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1849 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1850 }
1851#endif
1852 }
1853 } else {
1854 /* Get NVRAM and adapter maximums from SPP 0 and 2
1855 */
1856 mpt_GetScsiPortSettings(ioc, 0);
1857
1858 /* Get version and length of SDP 1
1859 */
1860 mpt_readScsiDevicePageHeaders(ioc, 0);
1861
1862 /* Find IM volumes
1863 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001864 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 mpt_findImVolumes(ioc);
1866
1867 /* Check, and possibly reset, the coalescing value
1868 */
1869 mpt_read_ioc_pg_1(ioc);
1870
1871 mpt_read_ioc_pg_4(ioc);
1872 }
1873
1874 GetIoUnitPage2(ioc);
1875 }
1876
1877 /*
1878 * Call each currently registered protocol IOC reset handler
1879 * with post-reset indication.
1880 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1881 * MptResetHandlers[] registered yet.
1882 */
1883 if (hard_reset_done) {
1884 rc = handlers = 0;
1885 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1886 if ((ret == 0) && MptResetHandlers[ii]) {
1887 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1888 ioc->name, ii));
1889 rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
1890 handlers++;
1891 }
1892
1893 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001894 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 ioc->name, ioc->alt_ioc->name, ii));
1896 rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
1897 handlers++;
1898 }
1899 }
1900 /* FIXME? Examine results here? */
1901 }
1902
1903 return ret;
1904}
1905
1906/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1907/*
1908 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1909 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1910 * 929X, 1030 or 1035.
1911 * @ioc: Pointer to MPT adapter structure
1912 * @pdev: Pointer to (struct pci_dev) structure
1913 *
1914 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1915 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1916 */
1917static void
1918mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1919{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001920 struct pci_dev *peer=NULL;
1921 unsigned int slot = PCI_SLOT(pdev->devfn);
1922 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 MPT_ADAPTER *ioc_srch;
1924
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001925 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1926 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001927 ioc->name, pci_name(pdev), pdev->bus->number,
1928 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001929
1930 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1931 if (!peer) {
1932 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1933 if (!peer)
1934 return;
1935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936
1937 list_for_each_entry(ioc_srch, &ioc_list, list) {
1938 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001939 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 /* Paranoia checks */
1941 if (ioc->alt_ioc != NULL) {
1942 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001943 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 break;
1945 } else if (ioc_srch->alt_ioc != NULL) {
1946 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001947 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 break;
1949 }
1950 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001951 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 ioc_srch->alt_ioc = ioc;
1953 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 }
1955 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001956 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957}
1958
1959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1960/*
1961 * mpt_adapter_disable - Disable misbehaving MPT adapter.
1962 * @this: Pointer to MPT adapter structure
1963 */
1964static void
1965mpt_adapter_disable(MPT_ADAPTER *ioc)
1966{
1967 int sz;
1968 int ret;
1969
1970 if (ioc->cached_fw != NULL) {
1971 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001972 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 printk(KERN_WARNING MYNAM
1974 ": firmware downloadboot failure (%d)!\n", ret);
1975 }
1976 }
1977
1978 /* Disable adapter interrupts! */
1979 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1980 ioc->active = 0;
1981 /* Clear any lingering interrupt */
1982 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1983
1984 if (ioc->alloc != NULL) {
1985 sz = ioc->alloc_sz;
1986 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1987 ioc->name, ioc->alloc, ioc->alloc_sz));
1988 pci_free_consistent(ioc->pcidev, sz,
1989 ioc->alloc, ioc->alloc_dma);
1990 ioc->reply_frames = NULL;
1991 ioc->req_frames = NULL;
1992 ioc->alloc = NULL;
1993 ioc->alloc_total -= sz;
1994 }
1995
1996 if (ioc->sense_buf_pool != NULL) {
1997 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
1998 pci_free_consistent(ioc->pcidev, sz,
1999 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2000 ioc->sense_buf_pool = NULL;
2001 ioc->alloc_total -= sz;
2002 }
2003
2004 if (ioc->events != NULL){
2005 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2006 kfree(ioc->events);
2007 ioc->events = NULL;
2008 ioc->alloc_total -= sz;
2009 }
2010
2011 if (ioc->cached_fw != NULL) {
2012 sz = ioc->facts.FWImageSize;
2013 pci_free_consistent(ioc->pcidev, sz,
2014 ioc->cached_fw, ioc->cached_fw_dma);
2015 ioc->cached_fw = NULL;
2016 ioc->alloc_total -= sz;
2017 }
2018
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002019 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002020 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002021 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002022 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
2024 if (ioc->spi_data.pIocPg4 != NULL) {
2025 sz = ioc->spi_data.IocPg4Sz;
2026 pci_free_consistent(ioc->pcidev, sz,
2027 ioc->spi_data.pIocPg4,
2028 ioc->spi_data.IocPg4_dma);
2029 ioc->spi_data.pIocPg4 = NULL;
2030 ioc->alloc_total -= sz;
2031 }
2032
2033 if (ioc->ReqToChain != NULL) {
2034 kfree(ioc->ReqToChain);
2035 kfree(ioc->RequestNB);
2036 ioc->ReqToChain = NULL;
2037 }
2038
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002039 kfree(ioc->ChainToChain);
2040 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002041
2042 if (ioc->HostPageBuffer != NULL) {
2043 if((ret = mpt_host_page_access_control(ioc,
2044 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2045 printk(KERN_ERR MYNAM
2046 ": %s: host page buffers free failed (%d)!\n",
2047 __FUNCTION__, ret);
2048 }
2049 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2050 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2051 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2052 ioc->HostPageBuffer,
2053 ioc->HostPageBuffer_dma);
2054 ioc->HostPageBuffer = NULL;
2055 ioc->HostPageBuffer_sz = 0;
2056 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058}
2059
2060/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2061/*
2062 * mpt_adapter_dispose - Free all resources associated with a MPT
2063 * adapter.
2064 * @ioc: Pointer to MPT adapter structure
2065 *
2066 * This routine unregisters h/w resources and frees all alloc'd memory
2067 * associated with a MPT adapter structure.
2068 */
2069static void
2070mpt_adapter_dispose(MPT_ADAPTER *ioc)
2071{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002072 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002074 if (ioc == NULL)
2075 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002077 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002079 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002081 if (ioc->pci_irq != -1) {
2082 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002083 if (mpt_msi_enable)
2084 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002085 ioc->pci_irq = -1;
2086 }
2087
2088 if (ioc->memmap != NULL) {
2089 iounmap(ioc->memmap);
2090 ioc->memmap = NULL;
2091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
2093#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002094 if (ioc->mtrr_reg > 0) {
2095 mtrr_del(ioc->mtrr_reg, 0, 0);
2096 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098#endif
2099
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002100 /* Zap the adapter lookup ptr! */
2101 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002103 sz_last = ioc->alloc_total;
2104 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2105 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002106
2107 if (ioc->alt_ioc)
2108 ioc->alt_ioc->alt_ioc = NULL;
2109
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002110 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111}
2112
2113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2114/*
2115 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2116 * @ioc: Pointer to MPT adapter structure
2117 */
2118static void
2119MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2120{
2121 int i = 0;
2122
2123 printk(KERN_INFO "%s: ", ioc->name);
2124 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2125 printk("%s: ", ioc->prod_name+3);
2126 printk("Capabilities={");
2127
2128 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2129 printk("Initiator");
2130 i++;
2131 }
2132
2133 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2134 printk("%sTarget", i ? "," : "");
2135 i++;
2136 }
2137
2138 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2139 printk("%sLAN", i ? "," : "");
2140 i++;
2141 }
2142
2143#if 0
2144 /*
2145 * This would probably evoke more questions than it's worth
2146 */
2147 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2148 printk("%sLogBusAddr", i ? "," : "");
2149 i++;
2150 }
2151#endif
2152
2153 printk("}\n");
2154}
2155
2156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2157/*
2158 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2159 * @ioc: Pointer to MPT_ADAPTER structure
2160 * @force: Force hard KickStart of IOC
2161 * @sleepFlag: Specifies whether the process can sleep
2162 *
2163 * Returns:
2164 * 1 - DIAG reset and READY
2165 * 0 - READY initially OR soft reset and READY
2166 * -1 - Any failure on KickStart
2167 * -2 - Msg Unit Reset Failed
2168 * -3 - IO Unit Reset Failed
2169 * -4 - IOC owned by a PEER
2170 */
2171static int
2172MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2173{
2174 u32 ioc_state;
2175 int statefault = 0;
2176 int cntdn;
2177 int hard_reset_done = 0;
2178 int r;
2179 int ii;
2180 int whoinit;
2181
2182 /* Get current [raw] IOC state */
2183 ioc_state = mpt_GetIocState(ioc, 0);
2184 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2185
2186 /*
2187 * Check to see if IOC got left/stuck in doorbell handshake
2188 * grip of death. If so, hard reset the IOC.
2189 */
2190 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2191 statefault = 1;
2192 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2193 ioc->name);
2194 }
2195
2196 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002197 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 return 0;
2199
2200 /*
2201 * Check to see if IOC is in FAULT state.
2202 */
2203 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2204 statefault = 2;
2205 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2206 ioc->name);
2207 printk(KERN_WARNING " FAULT code = %04xh\n",
2208 ioc_state & MPI_DOORBELL_DATA_MASK);
2209 }
2210
2211 /*
2212 * Hmmm... Did it get left operational?
2213 */
2214 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002215 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 ioc->name));
2217
2218 /* Check WhoInit.
2219 * If PCI Peer, exit.
2220 * Else, if no fault conditions are present, issue a MessageUnitReset
2221 * Else, fall through to KickStart case
2222 */
2223 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002224 dinitprintk((KERN_INFO MYNAM
2225 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 whoinit, statefault, force));
2227 if (whoinit == MPI_WHOINIT_PCI_PEER)
2228 return -4;
2229 else {
2230 if ((statefault == 0 ) && (force == 0)) {
2231 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2232 return 0;
2233 }
2234 statefault = 3;
2235 }
2236 }
2237
2238 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2239 if (hard_reset_done < 0)
2240 return -1;
2241
2242 /*
2243 * Loop here waiting for IOC to come READY.
2244 */
2245 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002246 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
2248 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2249 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2250 /*
2251 * BIOS or previous driver load left IOC in OP state.
2252 * Reset messaging FIFOs.
2253 */
2254 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2255 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2256 return -2;
2257 }
2258 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2259 /*
2260 * Something is wrong. Try to get IOC back
2261 * to a known state.
2262 */
2263 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2264 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2265 return -3;
2266 }
2267 }
2268
2269 ii++; cntdn--;
2270 if (!cntdn) {
2271 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2272 ioc->name, (int)((ii+5)/HZ));
2273 return -ETIME;
2274 }
2275
2276 if (sleepFlag == CAN_SLEEP) {
2277 msleep_interruptible(1);
2278 } else {
2279 mdelay (1); /* 1 msec delay */
2280 }
2281
2282 }
2283
2284 if (statefault < 3) {
2285 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2286 ioc->name,
2287 statefault==1 ? "stuck handshake" : "IOC FAULT");
2288 }
2289
2290 return hard_reset_done;
2291}
2292
2293/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2294/*
2295 * mpt_GetIocState - Get the current state of a MPT adapter.
2296 * @ioc: Pointer to MPT_ADAPTER structure
2297 * @cooked: Request raw or cooked IOC state
2298 *
2299 * Returns all IOC Doorbell register bits if cooked==0, else just the
2300 * Doorbell bits in MPI_IOC_STATE_MASK.
2301 */
2302u32
2303mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2304{
2305 u32 s, sc;
2306
2307 /* Get! */
2308 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2309// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2310 sc = s & MPI_IOC_STATE_MASK;
2311
2312 /* Save! */
2313 ioc->last_state = sc;
2314
2315 return cooked ? sc : s;
2316}
2317
2318/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2319/*
2320 * GetIocFacts - Send IOCFacts request to MPT adapter.
2321 * @ioc: Pointer to MPT_ADAPTER structure
2322 * @sleepFlag: Specifies whether the process can sleep
2323 * @reason: If recovery, only update facts.
2324 *
2325 * Returns 0 for success, non-zero for failure.
2326 */
2327static int
2328GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2329{
2330 IOCFacts_t get_facts;
2331 IOCFactsReply_t *facts;
2332 int r;
2333 int req_sz;
2334 int reply_sz;
2335 int sz;
2336 u32 status, vv;
2337 u8 shiftFactor=1;
2338
2339 /* IOC *must* NOT be in RESET state! */
2340 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2341 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2342 ioc->name,
2343 ioc->last_state );
2344 return -44;
2345 }
2346
2347 facts = &ioc->facts;
2348
2349 /* Destination (reply area)... */
2350 reply_sz = sizeof(*facts);
2351 memset(facts, 0, reply_sz);
2352
2353 /* Request area (get_facts on the stack right now!) */
2354 req_sz = sizeof(get_facts);
2355 memset(&get_facts, 0, req_sz);
2356
2357 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2358 /* Assert: All other get_facts fields are zero! */
2359
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002360 dinitprintk((MYIOC_s_INFO_FMT
2361 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 ioc->name, req_sz, reply_sz));
2363
2364 /* No non-zero fields in the get_facts request are greater than
2365 * 1 byte in size, so we can just fire it off as is.
2366 */
2367 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2368 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2369 if (r != 0)
2370 return r;
2371
2372 /*
2373 * Now byte swap (GRRR) the necessary fields before any further
2374 * inspection of reply contents.
2375 *
2376 * But need to do some sanity checks on MsgLength (byte) field
2377 * to make sure we don't zero IOC's req_sz!
2378 */
2379 /* Did we get a valid reply? */
2380 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2381 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2382 /*
2383 * If not been here, done that, save off first WhoInit value
2384 */
2385 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2386 ioc->FirstWhoInit = facts->WhoInit;
2387 }
2388
2389 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2390 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2391 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2392 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2393 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002394 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 /* CHECKME! IOCStatus, IOCLogInfo */
2396
2397 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2398 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2399
2400 /*
2401 * FC f/w version changed between 1.1 and 1.2
2402 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2403 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2404 */
2405 if (facts->MsgVersion < 0x0102) {
2406 /*
2407 * Handle old FC f/w style, convert to new...
2408 */
2409 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2410 facts->FWVersion.Word =
2411 ((oldv<<12) & 0xFF000000) |
2412 ((oldv<<8) & 0x000FFF00);
2413 } else
2414 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2415
2416 facts->ProductID = le16_to_cpu(facts->ProductID);
2417 facts->CurrentHostMfaHighAddr =
2418 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2419 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2420 facts->CurrentSenseBufferHighAddr =
2421 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2422 facts->CurReplyFrameSize =
2423 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002424 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
2426 /*
2427 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2428 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2429 * to 14 in MPI-1.01.0x.
2430 */
2431 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2432 facts->MsgVersion > 0x0100) {
2433 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2434 }
2435
2436 sz = facts->FWImageSize;
2437 if ( sz & 0x01 )
2438 sz += 1;
2439 if ( sz & 0x02 )
2440 sz += 2;
2441 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002442
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 if (!facts->RequestFrameSize) {
2444 /* Something is wrong! */
2445 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2446 ioc->name);
2447 return -55;
2448 }
2449
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002450 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 vv = ((63 / (sz * 4)) + 1) & 0x03;
2452 ioc->NB_for_64_byte_frame = vv;
2453 while ( sz )
2454 {
2455 shiftFactor++;
2456 sz = sz >> 1;
2457 }
2458 ioc->NBShiftFactor = shiftFactor;
2459 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2460 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002461
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2463 /*
2464 * Set values for this IOC's request & reply frame sizes,
2465 * and request & reply queue depths...
2466 */
2467 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2468 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2469 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2470 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2471
2472 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2473 ioc->name, ioc->reply_sz, ioc->reply_depth));
2474 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2475 ioc->name, ioc->req_sz, ioc->req_depth));
2476
2477 /* Get port facts! */
2478 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2479 return r;
2480 }
2481 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002482 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2484 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2485 RequestFrameSize)/sizeof(u32)));
2486 return -66;
2487 }
2488
2489 return 0;
2490}
2491
2492/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2493/*
2494 * GetPortFacts - Send PortFacts request to MPT adapter.
2495 * @ioc: Pointer to MPT_ADAPTER structure
2496 * @portnum: Port number
2497 * @sleepFlag: Specifies whether the process can sleep
2498 *
2499 * Returns 0 for success, non-zero for failure.
2500 */
2501static int
2502GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2503{
2504 PortFacts_t get_pfacts;
2505 PortFactsReply_t *pfacts;
2506 int ii;
2507 int req_sz;
2508 int reply_sz;
2509
2510 /* IOC *must* NOT be in RESET state! */
2511 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2512 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2513 ioc->name,
2514 ioc->last_state );
2515 return -4;
2516 }
2517
2518 pfacts = &ioc->pfacts[portnum];
2519
2520 /* Destination (reply area)... */
2521 reply_sz = sizeof(*pfacts);
2522 memset(pfacts, 0, reply_sz);
2523
2524 /* Request area (get_pfacts on the stack right now!) */
2525 req_sz = sizeof(get_pfacts);
2526 memset(&get_pfacts, 0, req_sz);
2527
2528 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2529 get_pfacts.PortNumber = portnum;
2530 /* Assert: All other get_pfacts fields are zero! */
2531
2532 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2533 ioc->name, portnum));
2534
2535 /* No non-zero fields in the get_pfacts request are greater than
2536 * 1 byte in size, so we can just fire it off as is.
2537 */
2538 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2539 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2540 if (ii != 0)
2541 return ii;
2542
2543 /* Did we get a valid reply? */
2544
2545 /* Now byte swap the necessary fields in the response. */
2546 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2547 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2548 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2549 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2550 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2551 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2552 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2553 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2554 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2555
2556 return 0;
2557}
2558
2559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2560/*
2561 * SendIocInit - Send IOCInit request to MPT adapter.
2562 * @ioc: Pointer to MPT_ADAPTER structure
2563 * @sleepFlag: Specifies whether the process can sleep
2564 *
2565 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2566 *
2567 * Returns 0 for success, non-zero for failure.
2568 */
2569static int
2570SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2571{
2572 IOCInit_t ioc_init;
2573 MPIDefaultReply_t init_reply;
2574 u32 state;
2575 int r;
2576 int count;
2577 int cntdn;
2578
2579 memset(&ioc_init, 0, sizeof(ioc_init));
2580 memset(&init_reply, 0, sizeof(init_reply));
2581
2582 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2583 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2584
2585 /* If we are in a recovery mode and we uploaded the FW image,
2586 * then this pointer is not NULL. Skip the upload a second time.
2587 * Set this flag if cached_fw set for either IOC.
2588 */
2589 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2590 ioc->upload_fw = 1;
2591 else
2592 ioc->upload_fw = 0;
2593 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2594 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2595
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002596 if(ioc->bus_type == SAS)
2597 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2598 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2600 else
2601 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002603 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2604 ioc->name, ioc->facts.MsgVersion));
2605 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2606 // set MsgVersion and HeaderVersion host driver was built with
2607 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2608 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002610 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2611 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2612 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2613 return -99;
2614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2616
2617 if (sizeof(dma_addr_t) == sizeof(u64)) {
2618 /* Save the upper 32-bits of the request
2619 * (reply) and sense buffers.
2620 */
2621 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2622 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2623 } else {
2624 /* Force 32-bit addressing */
2625 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2626 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2627 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002628
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2630 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002631 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2632 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633
2634 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2635 ioc->name, &ioc_init));
2636
2637 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2638 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002639 if (r != 0) {
2640 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643
2644 /* No need to byte swap the multibyte fields in the reply
2645 * since we don't even look at it's contents.
2646 */
2647
2648 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2649 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002650
2651 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2652 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
2656 /* YIKES! SUPER IMPORTANT!!!
2657 * Poll IocState until _OPERATIONAL while IOC is doing
2658 * LoopInit and TargetDiscovery!
2659 */
2660 count = 0;
2661 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2662 state = mpt_GetIocState(ioc, 1);
2663 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2664 if (sleepFlag == CAN_SLEEP) {
2665 msleep_interruptible(1);
2666 } else {
2667 mdelay(1);
2668 }
2669
2670 if (!cntdn) {
2671 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2672 ioc->name, (int)((count+5)/HZ));
2673 return -9;
2674 }
2675
2676 state = mpt_GetIocState(ioc, 1);
2677 count++;
2678 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002679 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 ioc->name, count));
2681
2682 return r;
2683}
2684
2685/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2686/*
2687 * SendPortEnable - Send PortEnable request to MPT adapter port.
2688 * @ioc: Pointer to MPT_ADAPTER structure
2689 * @portnum: Port number to enable
2690 * @sleepFlag: Specifies whether the process can sleep
2691 *
2692 * Send PortEnable to bring IOC to OPERATIONAL state.
2693 *
2694 * Returns 0 for success, non-zero for failure.
2695 */
2696static int
2697SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2698{
2699 PortEnable_t port_enable;
2700 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002701 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 int req_sz;
2703 int reply_sz;
2704
2705 /* Destination... */
2706 reply_sz = sizeof(MPIDefaultReply_t);
2707 memset(&reply_buf, 0, reply_sz);
2708
2709 req_sz = sizeof(PortEnable_t);
2710 memset(&port_enable, 0, req_sz);
2711
2712 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2713 port_enable.PortNumber = portnum;
2714/* port_enable.ChainOffset = 0; */
2715/* port_enable.MsgFlags = 0; */
2716/* port_enable.MsgContext = 0; */
2717
2718 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2719 ioc->name, portnum, &port_enable));
2720
2721 /* RAID FW may take a long time to enable
2722 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002723 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2724 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2725 (ioc->bus_type == SAS)) {
2726 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2727 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2728 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002729 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002730 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2731 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2732 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002734 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735}
2736
2737/*
2738 * ioc: Pointer to MPT_ADAPTER structure
2739 * size - total FW bytes
2740 */
2741void
2742mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2743{
2744 if (ioc->cached_fw)
2745 return; /* use already allocated memory */
2746 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2747 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2748 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2749 } else {
2750 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2751 ioc->alloc_total += size;
2752 }
2753}
2754/*
2755 * If alt_img is NULL, delete from ioc structure.
2756 * Else, delete a secondary image in same format.
2757 */
2758void
2759mpt_free_fw_memory(MPT_ADAPTER *ioc)
2760{
2761 int sz;
2762
2763 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002764 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2766 pci_free_consistent(ioc->pcidev, sz,
2767 ioc->cached_fw, ioc->cached_fw_dma);
2768 ioc->cached_fw = NULL;
2769
2770 return;
2771}
2772
2773
2774/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2775/*
2776 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2777 * @ioc: Pointer to MPT_ADAPTER structure
2778 * @sleepFlag: Specifies whether the process can sleep
2779 *
2780 * Returns 0 for success, >0 for handshake failure
2781 * <0 for fw upload failure.
2782 *
2783 * Remark: If bound IOC and a successful FWUpload was performed
2784 * on the bound IOC, the second image is discarded
2785 * and memory is free'd. Both channels must upload to prevent
2786 * IOC from running in degraded mode.
2787 */
2788static int
2789mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2790{
2791 u8 request[ioc->req_sz];
2792 u8 reply[sizeof(FWUploadReply_t)];
2793 FWUpload_t *prequest;
2794 FWUploadReply_t *preply;
2795 FWUploadTCSGE_t *ptcsge;
2796 int sgeoffset;
2797 u32 flagsLength;
2798 int ii, sz, reply_sz;
2799 int cmdStatus;
2800
2801 /* If the image size is 0, we are done.
2802 */
2803 if ((sz = ioc->facts.FWImageSize) == 0)
2804 return 0;
2805
2806 mpt_alloc_fw_memory(ioc, sz);
2807
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002808 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002810
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 if (ioc->cached_fw == NULL) {
2812 /* Major Failure.
2813 */
2814 return -ENOMEM;
2815 }
2816
2817 prequest = (FWUpload_t *)&request;
2818 preply = (FWUploadReply_t *)&reply;
2819
2820 /* Destination... */
2821 memset(prequest, 0, ioc->req_sz);
2822
2823 reply_sz = sizeof(reply);
2824 memset(preply, 0, reply_sz);
2825
2826 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2827 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2828
2829 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2830 ptcsge->DetailsLength = 12;
2831 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2832 ptcsge->ImageSize = cpu_to_le32(sz);
2833
2834 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2835
2836 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2837 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2838
2839 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002840 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 prequest, sgeoffset));
2842 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2843
2844 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2845 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2846
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002847 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848
2849 cmdStatus = -EFAULT;
2850 if (ii == 0) {
2851 /* Handshake transfer was complete and successful.
2852 * Check the Reply Frame.
2853 */
2854 int status, transfer_sz;
2855 status = le16_to_cpu(preply->IOCStatus);
2856 if (status == MPI_IOCSTATUS_SUCCESS) {
2857 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2858 if (transfer_sz == sz)
2859 cmdStatus = 0;
2860 }
2861 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002862 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 ioc->name, cmdStatus));
2864
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002865
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 if (cmdStatus) {
2867
2868 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2869 ioc->name));
2870 mpt_free_fw_memory(ioc);
2871 }
2872
2873 return cmdStatus;
2874}
2875
2876/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2877/*
2878 * mpt_downloadboot - DownloadBoot code
2879 * @ioc: Pointer to MPT_ADAPTER structure
2880 * @flag: Specify which part of IOC memory is to be uploaded.
2881 * @sleepFlag: Specifies whether the process can sleep
2882 *
2883 * FwDownloadBoot requires Programmed IO access.
2884 *
2885 * Returns 0 for success
2886 * -1 FW Image size is 0
2887 * -2 No valid cached_fw Pointer
2888 * <0 for fw upload failure.
2889 */
2890static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002891mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 MpiExtImageHeader_t *pExtImage;
2894 u32 fwSize;
2895 u32 diag0val;
2896 int count;
2897 u32 *ptrFw;
2898 u32 diagRwData;
2899 u32 nextImage;
2900 u32 load_addr;
2901 u32 ioc_state=0;
2902
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002903 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2904 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002905
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2907 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2908 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2909 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2910 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2911 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2912
2913 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2914
2915 /* wait 1 msec */
2916 if (sleepFlag == CAN_SLEEP) {
2917 msleep_interruptible(1);
2918 } else {
2919 mdelay (1);
2920 }
2921
2922 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2923 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2924
2925 for (count = 0; count < 30; count ++) {
2926 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2927 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2928 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2929 ioc->name, count));
2930 break;
2931 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002932 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002934 msleep_interruptible (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002936 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 }
2938 }
2939
2940 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002941 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2942 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 ioc->name, diag0val));
2944 return -3;
2945 }
2946
2947 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2948 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2949 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2950 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2951 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2952 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2953
2954 /* Set the DiagRwEn and Disable ARM bits */
2955 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2956
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 fwSize = (pFwHeader->ImageSize + 3)/4;
2958 ptrFw = (u32 *) pFwHeader;
2959
2960 /* Write the LoadStartAddress to the DiagRw Address Register
2961 * using Programmed IO
2962 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002963 if (ioc->errata_flag_1064)
2964 pci_enable_io_access(ioc->pcidev);
2965
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2967 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2968 ioc->name, pFwHeader->LoadStartAddress));
2969
2970 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2971 ioc->name, fwSize*4, ptrFw));
2972 while (fwSize--) {
2973 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2974 }
2975
2976 nextImage = pFwHeader->NextImageHeaderOffset;
2977 while (nextImage) {
2978 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
2979
2980 load_addr = pExtImage->LoadStartAddress;
2981
2982 fwSize = (pExtImage->ImageSize + 3) >> 2;
2983 ptrFw = (u32 *)pExtImage;
2984
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002985 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
2986 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
2988
2989 while (fwSize--) {
2990 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2991 }
2992 nextImage = pExtImage->NextImageHeaderOffset;
2993 }
2994
2995 /* Write the IopResetVectorRegAddr */
2996 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
2997 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
2998
2999 /* Write the IopResetVectorValue */
3000 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3001 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3002
3003 /* Clear the internal flash bad bit - autoincrementing register,
3004 * so must do two writes.
3005 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003006 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003007 /*
3008 * 1030 and 1035 H/W errata, workaround to access
3009 * the ClearFlashBadSignatureBit
3010 */
3011 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3012 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3013 diagRwData |= 0x40000000;
3014 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3015 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3016
3017 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3018 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3019 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3020 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3021
3022 /* wait 1 msec */
3023 if (sleepFlag == CAN_SLEEP) {
3024 msleep_interruptible (1);
3025 } else {
3026 mdelay (1);
3027 }
3028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003030 if (ioc->errata_flag_1064)
3031 pci_disable_io_access(ioc->pcidev);
3032
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003034 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3035 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003037 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3039 ioc->name, diag0val));
3040 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3041
3042 /* Write 0xFF to reset the sequencer */
3043 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3044
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003045 if (ioc->bus_type == SAS) {
3046 ioc_state = mpt_GetIocState(ioc, 0);
3047 if ( (GetIocFacts(ioc, sleepFlag,
3048 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3049 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3050 ioc->name, ioc_state));
3051 return -EFAULT;
3052 }
3053 }
3054
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 for (count=0; count<HZ*20; count++) {
3056 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3057 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3058 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003059 if (ioc->bus_type == SAS) {
3060 return 0;
3061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3063 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3064 ioc->name));
3065 return -EFAULT;
3066 }
3067 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3068 ioc->name));
3069 return 0;
3070 }
3071 if (sleepFlag == CAN_SLEEP) {
3072 msleep_interruptible (10);
3073 } else {
3074 mdelay (10);
3075 }
3076 }
3077 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3078 ioc->name, ioc_state));
3079 return -EFAULT;
3080}
3081
3082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3083/*
3084 * KickStart - Perform hard reset of MPT adapter.
3085 * @ioc: Pointer to MPT_ADAPTER structure
3086 * @force: Force hard reset
3087 * @sleepFlag: Specifies whether the process can sleep
3088 *
3089 * This routine places MPT adapter in diagnostic mode via the
3090 * WriteSequence register, and then performs a hard reset of adapter
3091 * via the Diagnostic register.
3092 *
3093 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3094 * or NO_SLEEP (interrupt thread, use mdelay)
3095 * force - 1 if doorbell active, board fault state
3096 * board operational, IOC_RECOVERY or
3097 * IOC_BRINGUP and there is an alt_ioc.
3098 * 0 else
3099 *
3100 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003101 * 1 - hard reset, READY
3102 * 0 - no reset due to History bit, READY
3103 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 * OR reset but failed to come READY
3105 * -2 - no reset, could not enter DIAG mode
3106 * -3 - reset but bad FW bit
3107 */
3108static int
3109KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3110{
3111 int hard_reset_done = 0;
3112 u32 ioc_state=0;
3113 int cnt,cntdn;
3114
3115 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003116 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 /* Always issue a Msg Unit Reset first. This will clear some
3118 * SCSI bus hang conditions.
3119 */
3120 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3121
3122 if (sleepFlag == CAN_SLEEP) {
3123 msleep_interruptible (1000);
3124 } else {
3125 mdelay (1000);
3126 }
3127 }
3128
3129 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3130 if (hard_reset_done < 0)
3131 return hard_reset_done;
3132
3133 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3134 ioc->name));
3135
3136 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3137 for (cnt=0; cnt<cntdn; cnt++) {
3138 ioc_state = mpt_GetIocState(ioc, 1);
3139 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3140 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3141 ioc->name, cnt));
3142 return hard_reset_done;
3143 }
3144 if (sleepFlag == CAN_SLEEP) {
3145 msleep_interruptible (10);
3146 } else {
3147 mdelay (10);
3148 }
3149 }
3150
3151 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3152 ioc->name, ioc_state);
3153 return -1;
3154}
3155
3156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3157/*
3158 * mpt_diag_reset - Perform hard reset of the adapter.
3159 * @ioc: Pointer to MPT_ADAPTER structure
3160 * @ignore: Set if to honor and clear to ignore
3161 * the reset history bit
3162 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3163 * else set to NO_SLEEP (use mdelay instead)
3164 *
3165 * This routine places the adapter in diagnostic mode via the
3166 * WriteSequence register and then performs a hard reset of adapter
3167 * via the Diagnostic register. Adapter should be in ready state
3168 * upon successful completion.
3169 *
3170 * Returns: 1 hard reset successful
3171 * 0 no reset performed because reset history bit set
3172 * -2 enabling diagnostic mode failed
3173 * -3 diagnostic reset failed
3174 */
3175static int
3176mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3177{
3178 u32 diag0val;
3179 u32 doorbell;
3180 int hard_reset_done = 0;
3181 int count = 0;
3182#ifdef MPT_DEBUG
3183 u32 diag1val = 0;
3184#endif
3185
3186 /* Clear any existing interrupts */
3187 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3188
3189 /* Use "Diagnostic reset" method! (only thing available!) */
3190 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3191
3192#ifdef MPT_DEBUG
3193 if (ioc->alt_ioc)
3194 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3195 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3196 ioc->name, diag0val, diag1val));
3197#endif
3198
3199 /* Do the reset if we are told to ignore the reset history
3200 * or if the reset history is 0
3201 */
3202 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3203 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3204 /* Write magic sequence to WriteSequence register
3205 * Loop until in diagnostic mode
3206 */
3207 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3208 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3209 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3210 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3211 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3212 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3213
3214 /* wait 100 msec */
3215 if (sleepFlag == CAN_SLEEP) {
3216 msleep_interruptible (100);
3217 } else {
3218 mdelay (100);
3219 }
3220
3221 count++;
3222 if (count > 20) {
3223 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3224 ioc->name, diag0val);
3225 return -2;
3226
3227 }
3228
3229 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3230
3231 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3232 ioc->name, diag0val));
3233 }
3234
3235#ifdef MPT_DEBUG
3236 if (ioc->alt_ioc)
3237 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3238 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3239 ioc->name, diag0val, diag1val));
3240#endif
3241 /*
3242 * Disable the ARM (Bug fix)
3243 *
3244 */
3245 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003246 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
3248 /*
3249 * Now hit the reset bit in the Diagnostic register
3250 * (THE BIG HAMMER!) (Clears DRWE bit).
3251 */
3252 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3253 hard_reset_done = 1;
3254 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3255 ioc->name));
3256
3257 /*
3258 * Call each currently registered protocol IOC reset handler
3259 * with pre-reset indication.
3260 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3261 * MptResetHandlers[] registered yet.
3262 */
3263 {
3264 int ii;
3265 int r = 0;
3266
3267 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3268 if (MptResetHandlers[ii]) {
3269 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3270 ioc->name, ii));
3271 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
3272 if (ioc->alt_ioc) {
3273 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3274 ioc->name, ioc->alt_ioc->name, ii));
3275 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
3276 }
3277 }
3278 }
3279 /* FIXME? Examine results here? */
3280 }
3281
3282 if (ioc->cached_fw) {
3283 /* If the DownloadBoot operation fails, the
3284 * IOC will be left unusable. This is a fatal error
3285 * case. _diag_reset will return < 0
3286 */
3287 for (count = 0; count < 30; count ++) {
3288 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3289 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3290 break;
3291 }
3292
3293 /* wait 1 sec */
3294 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003295 msleep_interruptible (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 } else {
3297 mdelay (1000);
3298 }
3299 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003300 if ((count = mpt_downloadboot(ioc,
3301 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 printk(KERN_WARNING MYNAM
3303 ": firmware downloadboot failure (%d)!\n", count);
3304 }
3305
3306 } else {
3307 /* Wait for FW to reload and for board
3308 * to go to the READY state.
3309 * Maximum wait is 60 seconds.
3310 * If fail, no error will check again
3311 * with calling program.
3312 */
3313 for (count = 0; count < 60; count ++) {
3314 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3315 doorbell &= MPI_IOC_STATE_MASK;
3316
3317 if (doorbell == MPI_IOC_STATE_READY) {
3318 break;
3319 }
3320
3321 /* wait 1 sec */
3322 if (sleepFlag == CAN_SLEEP) {
3323 msleep_interruptible (1000);
3324 } else {
3325 mdelay (1000);
3326 }
3327 }
3328 }
3329 }
3330
3331 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3332#ifdef MPT_DEBUG
3333 if (ioc->alt_ioc)
3334 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3335 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3336 ioc->name, diag0val, diag1val));
3337#endif
3338
3339 /* Clear RESET_HISTORY bit! Place board in the
3340 * diagnostic mode to update the diag register.
3341 */
3342 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3343 count = 0;
3344 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3345 /* Write magic sequence to WriteSequence register
3346 * Loop until in diagnostic mode
3347 */
3348 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3349 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3350 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3351 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3352 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3353 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3354
3355 /* wait 100 msec */
3356 if (sleepFlag == CAN_SLEEP) {
3357 msleep_interruptible (100);
3358 } else {
3359 mdelay (100);
3360 }
3361
3362 count++;
3363 if (count > 20) {
3364 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3365 ioc->name, diag0val);
3366 break;
3367 }
3368 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3369 }
3370 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3371 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3372 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3373 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3374 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3375 ioc->name);
3376 }
3377
3378 /* Disable Diagnostic Mode
3379 */
3380 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3381
3382 /* Check FW reload status flags.
3383 */
3384 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3385 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3386 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3387 ioc->name, diag0val);
3388 return -3;
3389 }
3390
3391#ifdef MPT_DEBUG
3392 if (ioc->alt_ioc)
3393 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3394 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3395 ioc->name, diag0val, diag1val));
3396#endif
3397
3398 /*
3399 * Reset flag that says we've enabled event notification
3400 */
3401 ioc->facts.EventState = 0;
3402
3403 if (ioc->alt_ioc)
3404 ioc->alt_ioc->facts.EventState = 0;
3405
3406 return hard_reset_done;
3407}
3408
3409/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3410/*
3411 * SendIocReset - Send IOCReset request to MPT adapter.
3412 * @ioc: Pointer to MPT_ADAPTER structure
3413 * @reset_type: reset type, expected values are
3414 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3415 *
3416 * Send IOCReset request to the MPT adapter.
3417 *
3418 * Returns 0 for success, non-zero for failure.
3419 */
3420static int
3421SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3422{
3423 int r;
3424 u32 state;
3425 int cntdn, count;
3426
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003427 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 ioc->name, reset_type));
3429 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3430 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3431 return r;
3432
3433 /* FW ACK'd request, wait for READY state
3434 */
3435 count = 0;
3436 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3437
3438 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3439 cntdn--;
3440 count++;
3441 if (!cntdn) {
3442 if (sleepFlag != CAN_SLEEP)
3443 count *= 10;
3444
3445 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3446 ioc->name, (int)((count+5)/HZ));
3447 return -ETIME;
3448 }
3449
3450 if (sleepFlag == CAN_SLEEP) {
3451 msleep_interruptible(1);
3452 } else {
3453 mdelay (1); /* 1 msec delay */
3454 }
3455 }
3456
3457 /* TODO!
3458 * Cleanup all event stuff for this IOC; re-issue EventNotification
3459 * request if needed.
3460 */
3461 if (ioc->facts.Function)
3462 ioc->facts.EventState = 0;
3463
3464 return 0;
3465}
3466
3467/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3468/*
3469 * initChainBuffers - Allocate memory for and initialize
3470 * chain buffers, chain buffer control arrays and spinlock.
3471 * @hd: Pointer to MPT_SCSI_HOST structure
3472 * @init: If set, initialize the spin lock.
3473 */
3474static int
3475initChainBuffers(MPT_ADAPTER *ioc)
3476{
3477 u8 *mem;
3478 int sz, ii, num_chain;
3479 int scale, num_sge, numSGE;
3480
3481 /* ReqToChain size must equal the req_depth
3482 * index = req_idx
3483 */
3484 if (ioc->ReqToChain == NULL) {
3485 sz = ioc->req_depth * sizeof(int);
3486 mem = kmalloc(sz, GFP_ATOMIC);
3487 if (mem == NULL)
3488 return -1;
3489
3490 ioc->ReqToChain = (int *) mem;
3491 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3492 ioc->name, mem, sz));
3493 mem = kmalloc(sz, GFP_ATOMIC);
3494 if (mem == NULL)
3495 return -1;
3496
3497 ioc->RequestNB = (int *) mem;
3498 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3499 ioc->name, mem, sz));
3500 }
3501 for (ii = 0; ii < ioc->req_depth; ii++) {
3502 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3503 }
3504
3505 /* ChainToChain size must equal the total number
3506 * of chain buffers to be allocated.
3507 * index = chain_idx
3508 *
3509 * Calculate the number of chain buffers needed(plus 1) per I/O
3510 * then multiply the the maximum number of simultaneous cmds
3511 *
3512 * num_sge = num sge in request frame + last chain buffer
3513 * scale = num sge per chain buffer if no chain element
3514 */
3515 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3516 if (sizeof(dma_addr_t) == sizeof(u64))
3517 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3518 else
3519 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3520
3521 if (sizeof(dma_addr_t) == sizeof(u64)) {
3522 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3523 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3524 } else {
3525 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3526 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3527 }
3528 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3529 ioc->name, num_sge, numSGE));
3530
3531 if ( numSGE > MPT_SCSI_SG_DEPTH )
3532 numSGE = MPT_SCSI_SG_DEPTH;
3533
3534 num_chain = 1;
3535 while (numSGE - num_sge > 0) {
3536 num_chain++;
3537 num_sge += (scale - 1);
3538 }
3539 num_chain++;
3540
3541 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3542 ioc->name, numSGE, num_sge, num_chain));
3543
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003544 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 num_chain *= MPT_SCSI_CAN_QUEUE;
3546 else
3547 num_chain *= MPT_FC_CAN_QUEUE;
3548
3549 ioc->num_chain = num_chain;
3550
3551 sz = num_chain * sizeof(int);
3552 if (ioc->ChainToChain == NULL) {
3553 mem = kmalloc(sz, GFP_ATOMIC);
3554 if (mem == NULL)
3555 return -1;
3556
3557 ioc->ChainToChain = (int *) mem;
3558 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3559 ioc->name, mem, sz));
3560 } else {
3561 mem = (u8 *) ioc->ChainToChain;
3562 }
3563 memset(mem, 0xFF, sz);
3564 return num_chain;
3565}
3566
3567/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3568/*
3569 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3570 * @ioc: Pointer to MPT_ADAPTER structure
3571 *
3572 * This routine allocates memory for the MPT reply and request frame
3573 * pools (if necessary), and primes the IOC reply FIFO with
3574 * reply frames.
3575 *
3576 * Returns 0 for success, non-zero for failure.
3577 */
3578static int
3579PrimeIocFifos(MPT_ADAPTER *ioc)
3580{
3581 MPT_FRAME_HDR *mf;
3582 unsigned long flags;
3583 dma_addr_t alloc_dma;
3584 u8 *mem;
3585 int i, reply_sz, sz, total_size, num_chain;
3586
3587 /* Prime reply FIFO... */
3588
3589 if (ioc->reply_frames == NULL) {
3590 if ( (num_chain = initChainBuffers(ioc)) < 0)
3591 return -1;
3592
3593 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3594 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3595 ioc->name, ioc->reply_sz, ioc->reply_depth));
3596 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3597 ioc->name, reply_sz, reply_sz));
3598
3599 sz = (ioc->req_sz * ioc->req_depth);
3600 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3601 ioc->name, ioc->req_sz, ioc->req_depth));
3602 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3603 ioc->name, sz, sz));
3604 total_size += sz;
3605
3606 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3607 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3608 ioc->name, ioc->req_sz, num_chain));
3609 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3610 ioc->name, sz, sz, num_chain));
3611
3612 total_size += sz;
3613 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3614 if (mem == NULL) {
3615 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3616 ioc->name);
3617 goto out_fail;
3618 }
3619
3620 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3621 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3622
3623 memset(mem, 0, total_size);
3624 ioc->alloc_total += total_size;
3625 ioc->alloc = mem;
3626 ioc->alloc_dma = alloc_dma;
3627 ioc->alloc_sz = total_size;
3628 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3629 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3630
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003631 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3632 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3633
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 alloc_dma += reply_sz;
3635 mem += reply_sz;
3636
3637 /* Request FIFO - WE manage this! */
3638
3639 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3640 ioc->req_frames_dma = alloc_dma;
3641
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003642 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 ioc->name, mem, (void *)(ulong)alloc_dma));
3644
3645 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3646
3647#if defined(CONFIG_MTRR) && 0
3648 /*
3649 * Enable Write Combining MTRR for IOC's memory region.
3650 * (at least as much as we can; "size and base must be
3651 * multiples of 4 kiB"
3652 */
3653 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3654 sz,
3655 MTRR_TYPE_WRCOMB, 1);
3656 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3657 ioc->name, ioc->req_frames_dma, sz));
3658#endif
3659
3660 for (i = 0; i < ioc->req_depth; i++) {
3661 alloc_dma += ioc->req_sz;
3662 mem += ioc->req_sz;
3663 }
3664
3665 ioc->ChainBuffer = mem;
3666 ioc->ChainBufferDMA = alloc_dma;
3667
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003668 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3670
3671 /* Initialize the free chain Q.
3672 */
3673
3674 INIT_LIST_HEAD(&ioc->FreeChainQ);
3675
3676 /* Post the chain buffers to the FreeChainQ.
3677 */
3678 mem = (u8 *)ioc->ChainBuffer;
3679 for (i=0; i < num_chain; i++) {
3680 mf = (MPT_FRAME_HDR *) mem;
3681 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3682 mem += ioc->req_sz;
3683 }
3684
3685 /* Initialize Request frames linked list
3686 */
3687 alloc_dma = ioc->req_frames_dma;
3688 mem = (u8 *) ioc->req_frames;
3689
3690 spin_lock_irqsave(&ioc->FreeQlock, flags);
3691 INIT_LIST_HEAD(&ioc->FreeQ);
3692 for (i = 0; i < ioc->req_depth; i++) {
3693 mf = (MPT_FRAME_HDR *) mem;
3694
3695 /* Queue REQUESTs *internally*! */
3696 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3697
3698 mem += ioc->req_sz;
3699 }
3700 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3701
3702 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3703 ioc->sense_buf_pool =
3704 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3705 if (ioc->sense_buf_pool == NULL) {
3706 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3707 ioc->name);
3708 goto out_fail;
3709 }
3710
3711 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3712 ioc->alloc_total += sz;
3713 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3714 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3715
3716 }
3717
3718 /* Post Reply frames to FIFO
3719 */
3720 alloc_dma = ioc->alloc_dma;
3721 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3722 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3723
3724 for (i = 0; i < ioc->reply_depth; i++) {
3725 /* Write each address to the IOC! */
3726 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3727 alloc_dma += ioc->reply_sz;
3728 }
3729
3730 return 0;
3731
3732out_fail:
3733 if (ioc->alloc != NULL) {
3734 sz = ioc->alloc_sz;
3735 pci_free_consistent(ioc->pcidev,
3736 sz,
3737 ioc->alloc, ioc->alloc_dma);
3738 ioc->reply_frames = NULL;
3739 ioc->req_frames = NULL;
3740 ioc->alloc_total -= sz;
3741 }
3742 if (ioc->sense_buf_pool != NULL) {
3743 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3744 pci_free_consistent(ioc->pcidev,
3745 sz,
3746 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3747 ioc->sense_buf_pool = NULL;
3748 }
3749 return -1;
3750}
3751
3752/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3753/**
3754 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3755 * from IOC via doorbell handshake method.
3756 * @ioc: Pointer to MPT_ADAPTER structure
3757 * @reqBytes: Size of the request in bytes
3758 * @req: Pointer to MPT request frame
3759 * @replyBytes: Expected size of the reply in bytes
3760 * @u16reply: Pointer to area where reply should be written
3761 * @maxwait: Max wait time for a reply (in seconds)
3762 * @sleepFlag: Specifies whether the process can sleep
3763 *
3764 * NOTES: It is the callers responsibility to byte-swap fields in the
3765 * request which are greater than 1 byte in size. It is also the
3766 * callers responsibility to byte-swap response fields which are
3767 * greater than 1 byte in size.
3768 *
3769 * Returns 0 for success, non-zero for failure.
3770 */
3771static int
3772mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003773 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774{
3775 MPIDefaultReply_t *mptReply;
3776 int failcnt = 0;
3777 int t;
3778
3779 /*
3780 * Get ready to cache a handshake reply
3781 */
3782 ioc->hs_reply_idx = 0;
3783 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3784 mptReply->MsgLength = 0;
3785
3786 /*
3787 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3788 * then tell IOC that we want to handshake a request of N words.
3789 * (WRITE u32val to Doorbell reg).
3790 */
3791 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3792 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3793 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3794 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3795
3796 /*
3797 * Wait for IOC's doorbell handshake int
3798 */
3799 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3800 failcnt++;
3801
3802 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3803 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3804
3805 /* Read doorbell and check for active bit */
3806 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3807 return -1;
3808
3809 /*
3810 * Clear doorbell int (WRITE 0 to IntStatus reg),
3811 * then wait for IOC to ACKnowledge that it's ready for
3812 * our handshake request.
3813 */
3814 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3815 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3816 failcnt++;
3817
3818 if (!failcnt) {
3819 int ii;
3820 u8 *req_as_bytes = (u8 *) req;
3821
3822 /*
3823 * Stuff request words via doorbell handshake,
3824 * with ACK from IOC for each.
3825 */
3826 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3827 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3828 (req_as_bytes[(ii*4) + 1] << 8) |
3829 (req_as_bytes[(ii*4) + 2] << 16) |
3830 (req_as_bytes[(ii*4) + 3] << 24));
3831
3832 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3833 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3834 failcnt++;
3835 }
3836
3837 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3838 DBG_DUMP_REQUEST_FRAME_HDR(req)
3839
3840 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3841 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3842
3843 /*
3844 * Wait for completion of doorbell handshake reply from the IOC
3845 */
3846 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3847 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003848
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3850 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3851
3852 /*
3853 * Copy out the cached reply...
3854 */
3855 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3856 u16reply[ii] = ioc->hs_reply[ii];
3857 } else {
3858 return -99;
3859 }
3860
3861 return -failcnt;
3862}
3863
3864/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3865/*
3866 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3867 * in it's IntStatus register.
3868 * @ioc: Pointer to MPT_ADAPTER structure
3869 * @howlong: How long to wait (in seconds)
3870 * @sleepFlag: Specifies whether the process can sleep
3871 *
3872 * This routine waits (up to ~2 seconds max) for IOC doorbell
3873 * handshake ACKnowledge.
3874 *
3875 * Returns a negative value on failure, else wait loop count.
3876 */
3877static int
3878WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3879{
3880 int cntdn;
3881 int count = 0;
3882 u32 intstat=0;
3883
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003884 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885
3886 if (sleepFlag == CAN_SLEEP) {
3887 while (--cntdn) {
3888 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3889 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3890 break;
3891 msleep_interruptible (1);
3892 count++;
3893 }
3894 } else {
3895 while (--cntdn) {
3896 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3897 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3898 break;
3899 mdelay (1);
3900 count++;
3901 }
3902 }
3903
3904 if (cntdn) {
3905 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3906 ioc->name, count));
3907 return count;
3908 }
3909
3910 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3911 ioc->name, count, intstat);
3912 return -1;
3913}
3914
3915/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3916/*
3917 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3918 * in it's IntStatus register.
3919 * @ioc: Pointer to MPT_ADAPTER structure
3920 * @howlong: How long to wait (in seconds)
3921 * @sleepFlag: Specifies whether the process can sleep
3922 *
3923 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3924 *
3925 * Returns a negative value on failure, else wait loop count.
3926 */
3927static int
3928WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3929{
3930 int cntdn;
3931 int count = 0;
3932 u32 intstat=0;
3933
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003934 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 if (sleepFlag == CAN_SLEEP) {
3936 while (--cntdn) {
3937 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3938 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3939 break;
3940 msleep_interruptible(1);
3941 count++;
3942 }
3943 } else {
3944 while (--cntdn) {
3945 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3946 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3947 break;
3948 mdelay(1);
3949 count++;
3950 }
3951 }
3952
3953 if (cntdn) {
3954 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3955 ioc->name, count, howlong));
3956 return count;
3957 }
3958
3959 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3960 ioc->name, count, intstat);
3961 return -1;
3962}
3963
3964/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3965/*
3966 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3967 * @ioc: Pointer to MPT_ADAPTER structure
3968 * @howlong: How long to wait (in seconds)
3969 * @sleepFlag: Specifies whether the process can sleep
3970 *
3971 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3972 * Reply is cached to IOC private area large enough to hold a maximum
3973 * of 128 bytes of reply data.
3974 *
3975 * Returns a negative value on failure, else size of reply in WORDS.
3976 */
3977static int
3978WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3979{
3980 int u16cnt = 0;
3981 int failcnt = 0;
3982 int t;
3983 u16 *hs_reply = ioc->hs_reply;
3984 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3985 u16 hword;
3986
3987 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
3988
3989 /*
3990 * Get first two u16's so we can look at IOC's intended reply MsgLength
3991 */
3992 u16cnt=0;
3993 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
3994 failcnt++;
3995 } else {
3996 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
3997 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3998 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3999 failcnt++;
4000 else {
4001 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4002 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4003 }
4004 }
4005
4006 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004007 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4009
4010 /*
4011 * If no error (and IOC said MsgLength is > 0), piece together
4012 * reply 16 bits at a time.
4013 */
4014 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4015 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4016 failcnt++;
4017 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4018 /* don't overflow our IOC hs_reply[] buffer! */
4019 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4020 hs_reply[u16cnt] = hword;
4021 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4022 }
4023
4024 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4025 failcnt++;
4026 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4027
4028 if (failcnt) {
4029 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4030 ioc->name);
4031 return -failcnt;
4032 }
4033#if 0
4034 else if (u16cnt != (2 * mptReply->MsgLength)) {
4035 return -101;
4036 }
4037 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4038 return -102;
4039 }
4040#endif
4041
4042 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4043 DBG_DUMP_REPLY_FRAME(mptReply)
4044
4045 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4046 ioc->name, t, u16cnt/2));
4047 return u16cnt/2;
4048}
4049
4050/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4051/*
4052 * GetLanConfigPages - Fetch LANConfig pages.
4053 * @ioc: Pointer to MPT_ADAPTER structure
4054 *
4055 * Return: 0 for success
4056 * -ENOMEM if no memory available
4057 * -EPERM if not allowed due to ISR context
4058 * -EAGAIN if no msg frames currently available
4059 * -EFAULT for non-successful reply or no reply (timeout)
4060 */
4061static int
4062GetLanConfigPages(MPT_ADAPTER *ioc)
4063{
4064 ConfigPageHeader_t hdr;
4065 CONFIGPARMS cfg;
4066 LANPage0_t *ppage0_alloc;
4067 dma_addr_t page0_dma;
4068 LANPage1_t *ppage1_alloc;
4069 dma_addr_t page1_dma;
4070 int rc = 0;
4071 int data_sz;
4072 int copy_sz;
4073
4074 /* Get LAN Page 0 header */
4075 hdr.PageVersion = 0;
4076 hdr.PageLength = 0;
4077 hdr.PageNumber = 0;
4078 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004079 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 cfg.physAddr = -1;
4081 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4082 cfg.dir = 0;
4083 cfg.pageAddr = 0;
4084 cfg.timeout = 0;
4085
4086 if ((rc = mpt_config(ioc, &cfg)) != 0)
4087 return rc;
4088
4089 if (hdr.PageLength > 0) {
4090 data_sz = hdr.PageLength * 4;
4091 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4092 rc = -ENOMEM;
4093 if (ppage0_alloc) {
4094 memset((u8 *)ppage0_alloc, 0, data_sz);
4095 cfg.physAddr = page0_dma;
4096 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4097
4098 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4099 /* save the data */
4100 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4101 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4102
4103 }
4104
4105 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4106
4107 /* FIXME!
4108 * Normalize endianness of structure data,
4109 * by byte-swapping all > 1 byte fields!
4110 */
4111
4112 }
4113
4114 if (rc)
4115 return rc;
4116 }
4117
4118 /* Get LAN Page 1 header */
4119 hdr.PageVersion = 0;
4120 hdr.PageLength = 0;
4121 hdr.PageNumber = 1;
4122 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004123 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 cfg.physAddr = -1;
4125 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4126 cfg.dir = 0;
4127 cfg.pageAddr = 0;
4128
4129 if ((rc = mpt_config(ioc, &cfg)) != 0)
4130 return rc;
4131
4132 if (hdr.PageLength == 0)
4133 return 0;
4134
4135 data_sz = hdr.PageLength * 4;
4136 rc = -ENOMEM;
4137 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4138 if (ppage1_alloc) {
4139 memset((u8 *)ppage1_alloc, 0, data_sz);
4140 cfg.physAddr = page1_dma;
4141 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4142
4143 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4144 /* save the data */
4145 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4146 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4147 }
4148
4149 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4150
4151 /* FIXME!
4152 * Normalize endianness of structure data,
4153 * by byte-swapping all > 1 byte fields!
4154 */
4155
4156 }
4157
4158 return rc;
4159}
4160
4161/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4162/*
Michael Reed05e8ec12006-01-13 14:31:54 -06004163 * mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 * @ioc: Pointer to MPT_ADAPTER structure
4165 * @portnum: IOC Port number
4166 *
4167 * Return: 0 for success
4168 * -ENOMEM if no memory available
4169 * -EPERM if not allowed due to ISR context
4170 * -EAGAIN if no msg frames currently available
4171 * -EFAULT for non-successful reply or no reply (timeout)
4172 */
Michael Reed05e8ec12006-01-13 14:31:54 -06004173int
4174mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175{
4176 ConfigPageHeader_t hdr;
4177 CONFIGPARMS cfg;
4178 FCPortPage0_t *ppage0_alloc;
4179 FCPortPage0_t *pp0dest;
4180 dma_addr_t page0_dma;
4181 int data_sz;
4182 int copy_sz;
4183 int rc;
Michael Reed05e8ec12006-01-13 14:31:54 -06004184 int count = 400;
4185
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
4187 /* Get FCPort Page 0 header */
4188 hdr.PageVersion = 0;
4189 hdr.PageLength = 0;
4190 hdr.PageNumber = 0;
4191 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004192 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 cfg.physAddr = -1;
4194 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4195 cfg.dir = 0;
4196 cfg.pageAddr = portnum;
4197 cfg.timeout = 0;
4198
4199 if ((rc = mpt_config(ioc, &cfg)) != 0)
4200 return rc;
4201
4202 if (hdr.PageLength == 0)
4203 return 0;
4204
4205 data_sz = hdr.PageLength * 4;
4206 rc = -ENOMEM;
4207 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4208 if (ppage0_alloc) {
Michael Reed05e8ec12006-01-13 14:31:54 -06004209
4210 try_again:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 memset((u8 *)ppage0_alloc, 0, data_sz);
4212 cfg.physAddr = page0_dma;
4213 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4214
4215 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4216 /* save the data */
4217 pp0dest = &ioc->fc_port_page0[portnum];
4218 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
4219 memcpy(pp0dest, ppage0_alloc, copy_sz);
4220
4221 /*
4222 * Normalize endianness of structure data,
4223 * by byte-swapping all > 1 byte fields!
4224 */
4225 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
4226 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
4227 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
4228 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
4229 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
4230 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
4231 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
4232 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
4233 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
4234 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
4235 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
4236 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
4237 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
4238 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
4239 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
4240 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
4241
Michael Reed05e8ec12006-01-13 14:31:54 -06004242 /*
4243 * if still doing discovery,
4244 * hang loose a while until finished
4245 */
4246 if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
4247 if (count-- > 0) {
4248 msleep_interruptible(100);
4249 goto try_again;
4250 }
4251 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
4252 " complete.\n",
4253 ioc->name);
4254 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 }
4256
4257 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4258 }
4259
4260 return rc;
4261}
4262
4263/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4264/*
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004265 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4266 * @ioc: Pointer to MPT_ADAPTER structure
4267 * @sas_address: 64bit SAS Address for operation.
4268 * @target_id: specified target for operation
4269 * @bus: specified bus for operation
4270 * @persist_opcode: see below
4271 *
4272 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4273 * devices not currently present.
4274 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4275 *
4276 * NOTE: Don't use not this function during interrupt time.
4277 *
4278 * Returns: 0 for success, non-zero error
4279 */
4280
4281/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4282int
4283mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4284{
4285 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4286 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4287 MPT_FRAME_HDR *mf = NULL;
4288 MPIHeader_t *mpi_hdr;
4289
4290
4291 /* insure garbage is not sent to fw */
4292 switch(persist_opcode) {
4293
4294 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4295 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4296 break;
4297
4298 default:
4299 return -1;
4300 break;
4301 }
4302
4303 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4304
4305 /* Get a MF for this command.
4306 */
4307 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4308 printk("%s: no msg frames!\n",__FUNCTION__);
4309 return -1;
4310 }
4311
4312 mpi_hdr = (MPIHeader_t *) mf;
4313 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4314 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4315 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4316 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4317 sasIoUnitCntrReq->Operation = persist_opcode;
4318
4319 init_timer(&ioc->persist_timer);
4320 ioc->persist_timer.data = (unsigned long) ioc;
4321 ioc->persist_timer.function = mpt_timer_expired;
4322 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4323 ioc->persist_wait_done=0;
4324 add_timer(&ioc->persist_timer);
4325 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4326 wait_event(mpt_waitq, ioc->persist_wait_done);
4327
4328 sasIoUnitCntrReply =
4329 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4330 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4331 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4332 __FUNCTION__,
4333 sasIoUnitCntrReply->IOCStatus,
4334 sasIoUnitCntrReply->IOCLogInfo);
4335 return -1;
4336 }
4337
4338 printk("%s: success\n",__FUNCTION__);
4339 return 0;
4340}
4341
4342/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004343
4344static void
4345mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4346 MpiEventDataRaid_t * pRaidEventData)
4347{
4348 int volume;
4349 int reason;
4350 int disk;
4351 int status;
4352 int flags;
4353 int state;
4354
4355 volume = pRaidEventData->VolumeID;
4356 reason = pRaidEventData->ReasonCode;
4357 disk = pRaidEventData->PhysDiskNum;
4358 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4359 flags = (status >> 0) & 0xff;
4360 state = (status >> 8) & 0xff;
4361
4362 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4363 return;
4364 }
4365
4366 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4367 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4368 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4369 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4370 ioc->name, disk);
4371 } else {
4372 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4373 ioc->name, volume);
4374 }
4375
4376 switch(reason) {
4377 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4378 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4379 ioc->name);
4380 break;
4381
4382 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4383
4384 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4385 ioc->name);
4386 break;
4387
4388 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4389 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4390 ioc->name);
4391 break;
4392
4393 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4394 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4395 ioc->name,
4396 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4397 ? "optimal"
4398 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4399 ? "degraded"
4400 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4401 ? "failed"
4402 : "state unknown",
4403 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4404 ? ", enabled" : "",
4405 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4406 ? ", quiesced" : "",
4407 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4408 ? ", resync in progress" : "" );
4409 break;
4410
4411 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4412 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4413 ioc->name, disk);
4414 break;
4415
4416 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4417 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4418 ioc->name);
4419 break;
4420
4421 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4422 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4423 ioc->name);
4424 break;
4425
4426 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4427 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4428 ioc->name);
4429 break;
4430
4431 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4432 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4433 ioc->name,
4434 state == MPI_PHYSDISK0_STATUS_ONLINE
4435 ? "online"
4436 : state == MPI_PHYSDISK0_STATUS_MISSING
4437 ? "missing"
4438 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4439 ? "not compatible"
4440 : state == MPI_PHYSDISK0_STATUS_FAILED
4441 ? "failed"
4442 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4443 ? "initializing"
4444 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4445 ? "offline requested"
4446 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4447 ? "failed requested"
4448 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4449 ? "offline"
4450 : "state unknown",
4451 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4452 ? ", out of sync" : "",
4453 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4454 ? ", quiesced" : "" );
4455 break;
4456
4457 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4458 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4459 ioc->name, disk);
4460 break;
4461
4462 case MPI_EVENT_RAID_RC_SMART_DATA:
4463 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4464 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4465 break;
4466
4467 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4468 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4469 ioc->name, disk);
4470 break;
4471 }
4472}
4473
4474/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004475/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4477 * @ioc: Pointer to MPT_ADAPTER structure
4478 *
4479 * Returns: 0 for success
4480 * -ENOMEM if no memory available
4481 * -EPERM if not allowed due to ISR context
4482 * -EAGAIN if no msg frames currently available
4483 * -EFAULT for non-successful reply or no reply (timeout)
4484 */
4485static int
4486GetIoUnitPage2(MPT_ADAPTER *ioc)
4487{
4488 ConfigPageHeader_t hdr;
4489 CONFIGPARMS cfg;
4490 IOUnitPage2_t *ppage_alloc;
4491 dma_addr_t page_dma;
4492 int data_sz;
4493 int rc;
4494
4495 /* Get the page header */
4496 hdr.PageVersion = 0;
4497 hdr.PageLength = 0;
4498 hdr.PageNumber = 2;
4499 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004500 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 cfg.physAddr = -1;
4502 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4503 cfg.dir = 0;
4504 cfg.pageAddr = 0;
4505 cfg.timeout = 0;
4506
4507 if ((rc = mpt_config(ioc, &cfg)) != 0)
4508 return rc;
4509
4510 if (hdr.PageLength == 0)
4511 return 0;
4512
4513 /* Read the config page */
4514 data_sz = hdr.PageLength * 4;
4515 rc = -ENOMEM;
4516 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4517 if (ppage_alloc) {
4518 memset((u8 *)ppage_alloc, 0, data_sz);
4519 cfg.physAddr = page_dma;
4520 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4521
4522 /* If Good, save data */
4523 if ((rc = mpt_config(ioc, &cfg)) == 0)
4524 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4525
4526 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4527 }
4528
4529 return rc;
4530}
4531
4532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4533/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4534 * @ioc: Pointer to a Adapter Strucutre
4535 * @portnum: IOC port number
4536 *
4537 * Return: -EFAULT if read of config page header fails
4538 * or if no nvram
4539 * If read of SCSI Port Page 0 fails,
4540 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4541 * Adapter settings: async, narrow
4542 * Return 1
4543 * If read of SCSI Port Page 2 fails,
4544 * Adapter settings valid
4545 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4546 * Return 1
4547 * Else
4548 * Both valid
4549 * Return 0
4550 * CHECK - what type of locking mechanisms should be used????
4551 */
4552static int
4553mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4554{
4555 u8 *pbuf;
4556 dma_addr_t buf_dma;
4557 CONFIGPARMS cfg;
4558 ConfigPageHeader_t header;
4559 int ii;
4560 int data, rc = 0;
4561
4562 /* Allocate memory
4563 */
4564 if (!ioc->spi_data.nvram) {
4565 int sz;
4566 u8 *mem;
4567 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4568 mem = kmalloc(sz, GFP_ATOMIC);
4569 if (mem == NULL)
4570 return -EFAULT;
4571
4572 ioc->spi_data.nvram = (int *) mem;
4573
4574 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4575 ioc->name, ioc->spi_data.nvram, sz));
4576 }
4577
4578 /* Invalidate NVRAM information
4579 */
4580 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4581 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4582 }
4583
4584 /* Read SPP0 header, allocate memory, then read page.
4585 */
4586 header.PageVersion = 0;
4587 header.PageLength = 0;
4588 header.PageNumber = 0;
4589 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004590 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 cfg.physAddr = -1;
4592 cfg.pageAddr = portnum;
4593 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4594 cfg.dir = 0;
4595 cfg.timeout = 0; /* use default */
4596 if (mpt_config(ioc, &cfg) != 0)
4597 return -EFAULT;
4598
4599 if (header.PageLength > 0) {
4600 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4601 if (pbuf) {
4602 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4603 cfg.physAddr = buf_dma;
4604 if (mpt_config(ioc, &cfg) != 0) {
4605 ioc->spi_data.maxBusWidth = MPT_NARROW;
4606 ioc->spi_data.maxSyncOffset = 0;
4607 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4608 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4609 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004610 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4611 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 } else {
4613 /* Save the Port Page 0 data
4614 */
4615 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4616 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4617 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4618
4619 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4620 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004621 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 ioc->name, pPP0->Capabilities));
4623 }
4624 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4625 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4626 if (data) {
4627 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4628 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4629 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004630 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4631 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 } else {
4633 ioc->spi_data.maxSyncOffset = 0;
4634 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4635 }
4636
4637 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4638
4639 /* Update the minSyncFactor based on bus type.
4640 */
4641 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4642 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4643
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004644 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004646 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4647 ioc->name, ioc->spi_data.minSyncFactor));
4648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 }
4650 }
4651 if (pbuf) {
4652 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4653 }
4654 }
4655 }
4656
4657 /* SCSI Port Page 2 - Read the header then the page.
4658 */
4659 header.PageVersion = 0;
4660 header.PageLength = 0;
4661 header.PageNumber = 2;
4662 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004663 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 cfg.physAddr = -1;
4665 cfg.pageAddr = portnum;
4666 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4667 cfg.dir = 0;
4668 if (mpt_config(ioc, &cfg) != 0)
4669 return -EFAULT;
4670
4671 if (header.PageLength > 0) {
4672 /* Allocate memory and read SCSI Port Page 2
4673 */
4674 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4675 if (pbuf) {
4676 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4677 cfg.physAddr = buf_dma;
4678 if (mpt_config(ioc, &cfg) != 0) {
4679 /* Nvram data is left with INVALID mark
4680 */
4681 rc = 1;
4682 } else {
4683 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4684 MpiDeviceInfo_t *pdevice = NULL;
4685
Moore, Ericd8e925d2006-01-16 18:53:06 -07004686 /*
4687 * Save "Set to Avoid SCSI Bus Resets" flag
4688 */
4689 ioc->spi_data.bus_reset =
4690 (le32_to_cpu(pPP2->PortFlags) &
4691 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4692 0 : 1 ;
4693
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 /* Save the Port Page 2 data
4695 * (reformat into a 32bit quantity)
4696 */
4697 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4698 ioc->spi_data.PortFlags = data;
4699 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4700 pdevice = &pPP2->DeviceSettings[ii];
4701 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4702 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4703 ioc->spi_data.nvram[ii] = data;
4704 }
4705 }
4706
4707 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4708 }
4709 }
4710
4711 /* Update Adapter limits with those from NVRAM
4712 * Comment: Don't need to do this. Target performance
4713 * parameters will never exceed the adapters limits.
4714 */
4715
4716 return rc;
4717}
4718
4719/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4720/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4721 * @ioc: Pointer to a Adapter Strucutre
4722 * @portnum: IOC port number
4723 *
4724 * Return: -EFAULT if read of config page header fails
4725 * or 0 if success.
4726 */
4727static int
4728mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4729{
4730 CONFIGPARMS cfg;
4731 ConfigPageHeader_t header;
4732
4733 /* Read the SCSI Device Page 1 header
4734 */
4735 header.PageVersion = 0;
4736 header.PageLength = 0;
4737 header.PageNumber = 1;
4738 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004739 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 cfg.physAddr = -1;
4741 cfg.pageAddr = portnum;
4742 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4743 cfg.dir = 0;
4744 cfg.timeout = 0;
4745 if (mpt_config(ioc, &cfg) != 0)
4746 return -EFAULT;
4747
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004748 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4749 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750
4751 header.PageVersion = 0;
4752 header.PageLength = 0;
4753 header.PageNumber = 0;
4754 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4755 if (mpt_config(ioc, &cfg) != 0)
4756 return -EFAULT;
4757
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004758 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4759 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760
4761 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4762 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4763
4764 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4765 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4766 return 0;
4767}
4768
4769/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4770/**
4771 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4772 * @ioc: Pointer to a Adapter Strucutre
4773 * @portnum: IOC port number
4774 *
4775 * Return:
4776 * 0 on success
4777 * -EFAULT if read of config page header fails or data pointer not NULL
4778 * -ENOMEM if pci_alloc failed
4779 */
4780int
4781mpt_findImVolumes(MPT_ADAPTER *ioc)
4782{
4783 IOCPage2_t *pIoc2;
4784 u8 *mem;
4785 ConfigPageIoc2RaidVol_t *pIocRv;
4786 dma_addr_t ioc2_dma;
4787 CONFIGPARMS cfg;
4788 ConfigPageHeader_t header;
4789 int jj;
4790 int rc = 0;
4791 int iocpage2sz;
4792 u8 nVols, nPhys;
4793 u8 vid, vbus, vioc;
4794
4795 /* Read IOCP2 header then the page.
4796 */
4797 header.PageVersion = 0;
4798 header.PageLength = 0;
4799 header.PageNumber = 2;
4800 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004801 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 cfg.physAddr = -1;
4803 cfg.pageAddr = 0;
4804 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4805 cfg.dir = 0;
4806 cfg.timeout = 0;
4807 if (mpt_config(ioc, &cfg) != 0)
4808 return -EFAULT;
4809
4810 if (header.PageLength == 0)
4811 return -EFAULT;
4812
4813 iocpage2sz = header.PageLength * 4;
4814 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4815 if (!pIoc2)
4816 return -ENOMEM;
4817
4818 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4819 cfg.physAddr = ioc2_dma;
4820 if (mpt_config(ioc, &cfg) != 0)
4821 goto done_and_free;
4822
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004823 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4825 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004826 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 } else {
4828 goto done_and_free;
4829 }
4830 }
4831 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4832
4833 /* Identify RAID Volume Id's */
4834 nVols = pIoc2->NumActiveVolumes;
4835 if ( nVols == 0) {
4836 /* No RAID Volume.
4837 */
4838 goto done_and_free;
4839 } else {
4840 /* At least 1 RAID Volume
4841 */
4842 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004843 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4845 vid = pIocRv->VolumeID;
4846 vbus = pIocRv->VolumeBus;
4847 vioc = pIocRv->VolumeIOC;
4848
4849 /* find the match
4850 */
4851 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004852 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 } else {
4854 /* Error! Always bus 0
4855 */
4856 }
4857 }
4858 }
4859
4860 /* Identify Hidden Physical Disk Id's */
4861 nPhys = pIoc2->NumActivePhysDisks;
4862 if (nPhys == 0) {
4863 /* No physical disks.
4864 */
4865 } else {
4866 mpt_read_ioc_pg_3(ioc);
4867 }
4868
4869done_and_free:
4870 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4871
4872 return rc;
4873}
4874
Moore, Ericc972c702006-03-14 09:14:06 -07004875static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4877{
4878 IOCPage3_t *pIoc3;
4879 u8 *mem;
4880 CONFIGPARMS cfg;
4881 ConfigPageHeader_t header;
4882 dma_addr_t ioc3_dma;
4883 int iocpage3sz = 0;
4884
4885 /* Free the old page
4886 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004887 kfree(ioc->raid_data.pIocPg3);
4888 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889
4890 /* There is at least one physical disk.
4891 * Read and save IOC Page 3
4892 */
4893 header.PageVersion = 0;
4894 header.PageLength = 0;
4895 header.PageNumber = 3;
4896 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004897 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 cfg.physAddr = -1;
4899 cfg.pageAddr = 0;
4900 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4901 cfg.dir = 0;
4902 cfg.timeout = 0;
4903 if (mpt_config(ioc, &cfg) != 0)
4904 return 0;
4905
4906 if (header.PageLength == 0)
4907 return 0;
4908
4909 /* Read Header good, alloc memory
4910 */
4911 iocpage3sz = header.PageLength * 4;
4912 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4913 if (!pIoc3)
4914 return 0;
4915
4916 /* Read the Page and save the data
4917 * into malloc'd memory.
4918 */
4919 cfg.physAddr = ioc3_dma;
4920 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4921 if (mpt_config(ioc, &cfg) == 0) {
4922 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4923 if (mem) {
4924 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004925 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 }
4927 }
4928
4929 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4930
4931 return 0;
4932}
4933
4934static void
4935mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4936{
4937 IOCPage4_t *pIoc4;
4938 CONFIGPARMS cfg;
4939 ConfigPageHeader_t header;
4940 dma_addr_t ioc4_dma;
4941 int iocpage4sz;
4942
4943 /* Read and save IOC Page 4
4944 */
4945 header.PageVersion = 0;
4946 header.PageLength = 0;
4947 header.PageNumber = 4;
4948 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004949 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 cfg.physAddr = -1;
4951 cfg.pageAddr = 0;
4952 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4953 cfg.dir = 0;
4954 cfg.timeout = 0;
4955 if (mpt_config(ioc, &cfg) != 0)
4956 return;
4957
4958 if (header.PageLength == 0)
4959 return;
4960
4961 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4962 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4963 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4964 if (!pIoc4)
4965 return;
4966 } else {
4967 ioc4_dma = ioc->spi_data.IocPg4_dma;
4968 iocpage4sz = ioc->spi_data.IocPg4Sz;
4969 }
4970
4971 /* Read the Page into dma memory.
4972 */
4973 cfg.physAddr = ioc4_dma;
4974 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4975 if (mpt_config(ioc, &cfg) == 0) {
4976 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4977 ioc->spi_data.IocPg4_dma = ioc4_dma;
4978 ioc->spi_data.IocPg4Sz = iocpage4sz;
4979 } else {
4980 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4981 ioc->spi_data.pIocPg4 = NULL;
4982 }
4983}
4984
4985static void
4986mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4987{
4988 IOCPage1_t *pIoc1;
4989 CONFIGPARMS cfg;
4990 ConfigPageHeader_t header;
4991 dma_addr_t ioc1_dma;
4992 int iocpage1sz = 0;
4993 u32 tmp;
4994
4995 /* Check the Coalescing Timeout in IOC Page 1
4996 */
4997 header.PageVersion = 0;
4998 header.PageLength = 0;
4999 header.PageNumber = 1;
5000 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005001 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 cfg.physAddr = -1;
5003 cfg.pageAddr = 0;
5004 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5005 cfg.dir = 0;
5006 cfg.timeout = 0;
5007 if (mpt_config(ioc, &cfg) != 0)
5008 return;
5009
5010 if (header.PageLength == 0)
5011 return;
5012
5013 /* Read Header good, alloc memory
5014 */
5015 iocpage1sz = header.PageLength * 4;
5016 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5017 if (!pIoc1)
5018 return;
5019
5020 /* Read the Page and check coalescing timeout
5021 */
5022 cfg.physAddr = ioc1_dma;
5023 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5024 if (mpt_config(ioc, &cfg) == 0) {
5025
5026 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5027 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5028 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5029
5030 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5031 ioc->name, tmp));
5032
5033 if (tmp > MPT_COALESCING_TIMEOUT) {
5034 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5035
5036 /* Write NVRAM and current
5037 */
5038 cfg.dir = 1;
5039 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5040 if (mpt_config(ioc, &cfg) == 0) {
5041 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5042 ioc->name, MPT_COALESCING_TIMEOUT));
5043
5044 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5045 if (mpt_config(ioc, &cfg) == 0) {
5046 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5047 ioc->name, MPT_COALESCING_TIMEOUT));
5048 } else {
5049 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5050 ioc->name));
5051 }
5052
5053 } else {
5054 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5055 ioc->name));
5056 }
5057 }
5058
5059 } else {
5060 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5061 }
5062 }
5063
5064 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5065
5066 return;
5067}
5068
5069/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5070/*
5071 * SendEventNotification - Send EventNotification (on or off) request
5072 * to MPT adapter.
5073 * @ioc: Pointer to MPT_ADAPTER structure
5074 * @EvSwitch: Event switch flags
5075 */
5076static int
5077SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5078{
5079 EventNotification_t *evnp;
5080
5081 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5082 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005083 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 ioc->name));
5085 return 0;
5086 }
5087 memset(evnp, 0, sizeof(*evnp));
5088
Moore, Eric3a892be2006-03-14 09:14:03 -07005089 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090
5091 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5092 evnp->ChainOffset = 0;
5093 evnp->MsgFlags = 0;
5094 evnp->Switch = EvSwitch;
5095
5096 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5097
5098 return 0;
5099}
5100
5101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5102/**
5103 * SendEventAck - Send EventAck request to MPT adapter.
5104 * @ioc: Pointer to MPT_ADAPTER structure
5105 * @evnp: Pointer to original EventNotification request
5106 */
5107static int
5108SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5109{
5110 EventAck_t *pAck;
5111
5112 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005113 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5114 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5115 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5116 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 return -1;
5118 }
5119 memset(pAck, 0, sizeof(*pAck));
5120
5121 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5122
5123 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5124 pAck->ChainOffset = 0;
5125 pAck->MsgFlags = 0;
5126 pAck->Event = evnp->Event;
5127 pAck->EventContext = evnp->EventContext;
5128
5129 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5130
5131 return 0;
5132}
5133
5134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5135/**
5136 * mpt_config - Generic function to issue config message
5137 * @ioc - Pointer to an adapter structure
5138 * @cfg - Pointer to a configuration structure. Struct contains
5139 * action, page address, direction, physical address
5140 * and pointer to a configuration page header
5141 * Page header is updated.
5142 *
5143 * Returns 0 for success
5144 * -EPERM if not allowed due to ISR context
5145 * -EAGAIN if no msg frames currently available
5146 * -EFAULT for non-successful reply or no reply (timeout)
5147 */
5148int
5149mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5150{
5151 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005152 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 MPT_FRAME_HDR *mf;
5154 unsigned long flags;
5155 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005156 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 int in_isr;
5158
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005159 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 * to be in ISR context, because that is fatal!
5161 */
5162 in_isr = in_interrupt();
5163 if (in_isr) {
5164 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5165 ioc->name));
5166 return -EPERM;
5167 }
5168
5169 /* Get and Populate a free Frame
5170 */
5171 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5172 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5173 ioc->name));
5174 return -EAGAIN;
5175 }
5176 pReq = (Config_t *)mf;
5177 pReq->Action = pCfg->action;
5178 pReq->Reserved = 0;
5179 pReq->ChainOffset = 0;
5180 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005181
5182 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 pReq->ExtPageLength = 0;
5184 pReq->ExtPageType = 0;
5185 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005186
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 for (ii=0; ii < 8; ii++)
5188 pReq->Reserved2[ii] = 0;
5189
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005190 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5191 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5192 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5193 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5194
5195 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5196 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5197 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5198 pReq->ExtPageType = pExtHdr->ExtPageType;
5199 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5200
5201 /* Page Length must be treated as a reserved field for the extended header. */
5202 pReq->Header.PageLength = 0;
5203 }
5204
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5206
5207 /* Add a SGE to the config request.
5208 */
5209 if (pCfg->dir)
5210 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5211 else
5212 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5213
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005214 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5215 flagsLength |= pExtHdr->ExtPageLength * 4;
5216
5217 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5218 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5219 }
5220 else {
5221 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5222
5223 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5224 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226
5227 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5228
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 /* Append pCfg pointer to end of mf
5230 */
5231 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5232
5233 /* Initalize the timer
5234 */
5235 init_timer(&pCfg->timer);
5236 pCfg->timer.data = (unsigned long) ioc;
5237 pCfg->timer.function = mpt_timer_expired;
5238 pCfg->wait_done = 0;
5239
5240 /* Set the timer; ensure 10 second minimum */
5241 if (pCfg->timeout < 10)
5242 pCfg->timer.expires = jiffies + HZ*10;
5243 else
5244 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5245
5246 /* Add to end of Q, set timer and then issue this command */
5247 spin_lock_irqsave(&ioc->FreeQlock, flags);
5248 list_add_tail(&pCfg->linkage, &ioc->configQ);
5249 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5250
5251 add_timer(&pCfg->timer);
5252 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5253 wait_event(mpt_waitq, pCfg->wait_done);
5254
5255 /* mf has been freed - do not access */
5256
5257 rc = pCfg->status;
5258
5259 return rc;
5260}
5261
5262/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263/*
5264 * mpt_timer_expired - Call back for timer process.
5265 * Used only internal config functionality.
5266 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5267 */
5268static void
5269mpt_timer_expired(unsigned long data)
5270{
5271 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5272
5273 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5274
5275 /* Perform a FW reload */
5276 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5277 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5278
5279 /* No more processing.
5280 * Hard reset clean-up will wake up
5281 * process and free all resources.
5282 */
5283 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5284
5285 return;
5286}
5287
5288/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5289/*
5290 * mpt_ioc_reset - Base cleanup for hard reset
5291 * @ioc: Pointer to the adapter structure
5292 * @reset_phase: Indicates pre- or post-reset functionality
5293 *
5294 * Remark: Free's resources with internally generated commands.
5295 */
5296static int
5297mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5298{
5299 CONFIGPARMS *pCfg;
5300 unsigned long flags;
5301
5302 dprintk((KERN_WARNING MYNAM
5303 ": IOC %s_reset routed to MPT base driver!\n",
5304 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5305 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5306
5307 if (reset_phase == MPT_IOC_SETUP_RESET) {
5308 ;
5309 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5310 /* If the internal config Q is not empty -
5311 * delete timer. MF resources will be freed when
5312 * the FIFO's are primed.
5313 */
5314 spin_lock_irqsave(&ioc->FreeQlock, flags);
5315 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5316 del_timer(&pCfg->timer);
5317 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5318
5319 } else {
5320 CONFIGPARMS *pNext;
5321
5322 /* Search the configQ for internal commands.
5323 * Flush the Q, and wake up all suspended threads.
5324 */
5325 spin_lock_irqsave(&ioc->FreeQlock, flags);
5326 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5327 list_del(&pCfg->linkage);
5328
5329 pCfg->status = MPT_CONFIG_ERROR;
5330 pCfg->wait_done = 1;
5331 wake_up(&mpt_waitq);
5332 }
5333 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5334 }
5335
5336 return 1; /* currently means nothing really */
5337}
5338
5339
5340#ifdef CONFIG_PROC_FS /* { */
5341/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5342/*
5343 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5344 */
5345/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5346/*
5347 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5348 *
5349 * Returns 0 for success, non-zero for failure.
5350 */
5351static int
5352procmpt_create(void)
5353{
5354 struct proc_dir_entry *ent;
5355
5356 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5357 if (mpt_proc_root_dir == NULL)
5358 return -ENOTDIR;
5359
5360 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5361 if (ent)
5362 ent->read_proc = procmpt_summary_read;
5363
5364 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5365 if (ent)
5366 ent->read_proc = procmpt_version_read;
5367
5368 return 0;
5369}
5370
5371/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5372/*
5373 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5374 *
5375 * Returns 0 for success, non-zero for failure.
5376 */
5377static void
5378procmpt_destroy(void)
5379{
5380 remove_proc_entry("version", mpt_proc_root_dir);
5381 remove_proc_entry("summary", mpt_proc_root_dir);
5382 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5383}
5384
5385/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5386/*
5387 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5388 * or from /proc/mpt/iocN/summary.
5389 * @buf: Pointer to area to write information
5390 * @start: Pointer to start pointer
5391 * @offset: Offset to start writing
5392 * @request:
5393 * @eof: Pointer to EOF integer
5394 * @data: Pointer
5395 *
5396 * Returns number of characters written to process performing the read.
5397 */
5398static int
5399procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5400{
5401 MPT_ADAPTER *ioc;
5402 char *out = buf;
5403 int len;
5404
5405 if (data) {
5406 int more = 0;
5407
5408 ioc = data;
5409 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5410
5411 out += more;
5412 } else {
5413 list_for_each_entry(ioc, &ioc_list, list) {
5414 int more = 0;
5415
5416 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5417
5418 out += more;
5419 if ((out-buf) >= request)
5420 break;
5421 }
5422 }
5423
5424 len = out - buf;
5425
5426 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5427}
5428
5429/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5430/*
5431 * procmpt_version_read - Handle read request from /proc/mpt/version.
5432 * @buf: Pointer to area to write information
5433 * @start: Pointer to start pointer
5434 * @offset: Offset to start writing
5435 * @request:
5436 * @eof: Pointer to EOF integer
5437 * @data: Pointer
5438 *
5439 * Returns number of characters written to process performing the read.
5440 */
5441static int
5442procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5443{
5444 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005445 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 char *drvname;
5447 int len;
5448
5449 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5450 len += sprintf(buf+len, " Fusion MPT base driver\n");
5451
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005452 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5454 drvname = NULL;
5455 if (MptCallbacks[ii]) {
5456 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005457 case MPTSPI_DRIVER:
5458 if (!scsi++) drvname = "SPI host";
5459 break;
5460 case MPTFC_DRIVER:
5461 if (!fc++) drvname = "FC host";
5462 break;
5463 case MPTSAS_DRIVER:
5464 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 break;
5466 case MPTLAN_DRIVER:
5467 if (!lan++) drvname = "LAN";
5468 break;
5469 case MPTSTM_DRIVER:
5470 if (!targ++) drvname = "SCSI target";
5471 break;
5472 case MPTCTL_DRIVER:
5473 if (!ctl++) drvname = "ioctl";
5474 break;
5475 }
5476
5477 if (drvname)
5478 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5479 }
5480 }
5481
5482 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5483}
5484
5485/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5486/*
5487 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5488 * @buf: Pointer to area to write information
5489 * @start: Pointer to start pointer
5490 * @offset: Offset to start writing
5491 * @request:
5492 * @eof: Pointer to EOF integer
5493 * @data: Pointer
5494 *
5495 * Returns number of characters written to process performing the read.
5496 */
5497static int
5498procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5499{
5500 MPT_ADAPTER *ioc = data;
5501 int len;
5502 char expVer[32];
5503 int sz;
5504 int p;
5505
5506 mpt_get_fw_exp_ver(expVer, ioc);
5507
5508 len = sprintf(buf, "%s:", ioc->name);
5509 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5510 len += sprintf(buf+len, " (f/w download boot flag set)");
5511// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5512// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5513
5514 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5515 ioc->facts.ProductID,
5516 ioc->prod_name);
5517 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5518 if (ioc->facts.FWImageSize)
5519 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5520 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5521 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5522 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5523
5524 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5525 ioc->facts.CurrentHostMfaHighAddr);
5526 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5527 ioc->facts.CurrentSenseBufferHighAddr);
5528
5529 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5530 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5531
5532 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5533 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5534 /*
5535 * Rounding UP to nearest 4-kB boundary here...
5536 */
5537 sz = (ioc->req_sz * ioc->req_depth) + 128;
5538 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5539 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5540 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5541 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5542 4*ioc->facts.RequestFrameSize,
5543 ioc->facts.GlobalCredits);
5544
5545 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5546 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5547 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5548 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5549 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5550 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5551 ioc->facts.CurReplyFrameSize,
5552 ioc->facts.ReplyQueueDepth);
5553
5554 len += sprintf(buf+len, " MaxDevices = %d\n",
5555 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5556 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5557
5558 /* per-port info */
5559 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5560 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5561 p+1,
5562 ioc->facts.NumberOfPorts);
5563 if (ioc->bus_type == FC) {
5564 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5565 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5566 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5567 a[5], a[4], a[3], a[2], a[1], a[0]);
5568 }
5569 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5570 ioc->fc_port_page0[p].WWNN.High,
5571 ioc->fc_port_page0[p].WWNN.Low,
5572 ioc->fc_port_page0[p].WWPN.High,
5573 ioc->fc_port_page0[p].WWPN.Low);
5574 }
5575 }
5576
5577 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5578}
5579
5580#endif /* CONFIG_PROC_FS } */
5581
5582/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5583static void
5584mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5585{
5586 buf[0] ='\0';
5587 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5588 sprintf(buf, " (Exp %02d%02d)",
5589 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5590 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5591
5592 /* insider hack! */
5593 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5594 strcat(buf, " [MDBG]");
5595 }
5596}
5597
5598/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5599/**
5600 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5601 * @ioc: Pointer to MPT_ADAPTER structure
5602 * @buffer: Pointer to buffer where IOC summary info should be written
5603 * @size: Pointer to number of bytes we wrote (set by this routine)
5604 * @len: Offset at which to start writing in buffer
5605 * @showlan: Display LAN stuff?
5606 *
5607 * This routine writes (english readable) ASCII text, which represents
5608 * a summary of IOC information, to a buffer.
5609 */
5610void
5611mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5612{
5613 char expVer[32];
5614 int y;
5615
5616 mpt_get_fw_exp_ver(expVer, ioc);
5617
5618 /*
5619 * Shorter summary of attached ioc's...
5620 */
5621 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5622 ioc->name,
5623 ioc->prod_name,
5624 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5625 ioc->facts.FWVersion.Word,
5626 expVer,
5627 ioc->facts.NumberOfPorts,
5628 ioc->req_depth);
5629
5630 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5631 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5632 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5633 a[5], a[4], a[3], a[2], a[1], a[0]);
5634 }
5635
5636#ifndef __sparc__
5637 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
5638#else
5639 y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
5640#endif
5641
5642 if (!ioc->active)
5643 y += sprintf(buffer+len+y, " (disabled)");
5644
5645 y += sprintf(buffer+len+y, "\n");
5646
5647 *size = y;
5648}
5649
5650/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5651/*
5652 * Reset Handling
5653 */
5654/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5655/**
5656 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5657 * Management call based on input arg values. If TaskMgmt fails,
5658 * return associated SCSI request.
5659 * @ioc: Pointer to MPT_ADAPTER structure
5660 * @sleepFlag: Indicates if sleep or schedule must be called.
5661 *
5662 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5663 * or a non-interrupt thread. In the former, must not call schedule().
5664 *
5665 * Remark: A return of -1 is a FATAL error case, as it means a
5666 * FW reload/initialization failed.
5667 *
5668 * Returns 0 for SUCCESS or -1 if FAILED.
5669 */
5670int
5671mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5672{
5673 int rc;
5674 unsigned long flags;
5675
5676 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5677#ifdef MFCNT
5678 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5679 printk("MF count 0x%x !\n", ioc->mfcnt);
5680#endif
5681
5682 /* Reset the adapter. Prevent more than 1 call to
5683 * mpt_do_ioc_recovery at any instant in time.
5684 */
5685 spin_lock_irqsave(&ioc->diagLock, flags);
5686 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5687 spin_unlock_irqrestore(&ioc->diagLock, flags);
5688 return 0;
5689 } else {
5690 ioc->diagPending = 1;
5691 }
5692 spin_unlock_irqrestore(&ioc->diagLock, flags);
5693
5694 /* FIXME: If do_ioc_recovery fails, repeat....
5695 */
5696
5697 /* The SCSI driver needs to adjust timeouts on all current
5698 * commands prior to the diagnostic reset being issued.
5699 * Prevents timeouts occuring during a diagnostic reset...very bad.
5700 * For all other protocol drivers, this is a no-op.
5701 */
5702 {
5703 int ii;
5704 int r = 0;
5705
5706 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5707 if (MptResetHandlers[ii]) {
5708 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5709 ioc->name, ii));
5710 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
5711 if (ioc->alt_ioc) {
5712 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5713 ioc->name, ioc->alt_ioc->name, ii));
5714 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
5715 }
5716 }
5717 }
5718 }
5719
5720 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5721 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5722 rc, ioc->name);
5723 }
5724 ioc->reload_fw = 0;
5725 if (ioc->alt_ioc)
5726 ioc->alt_ioc->reload_fw = 0;
5727
5728 spin_lock_irqsave(&ioc->diagLock, flags);
5729 ioc->diagPending = 0;
5730 if (ioc->alt_ioc)
5731 ioc->alt_ioc->diagPending = 0;
5732 spin_unlock_irqrestore(&ioc->diagLock, flags);
5733
5734 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5735
5736 return rc;
5737}
5738
5739/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005740static void
5741EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742{
5743 char *ds;
5744
5745 switch(event) {
5746 case MPI_EVENT_NONE:
5747 ds = "None";
5748 break;
5749 case MPI_EVENT_LOG_DATA:
5750 ds = "Log Data";
5751 break;
5752 case MPI_EVENT_STATE_CHANGE:
5753 ds = "State Change";
5754 break;
5755 case MPI_EVENT_UNIT_ATTENTION:
5756 ds = "Unit Attention";
5757 break;
5758 case MPI_EVENT_IOC_BUS_RESET:
5759 ds = "IOC Bus Reset";
5760 break;
5761 case MPI_EVENT_EXT_BUS_RESET:
5762 ds = "External Bus Reset";
5763 break;
5764 case MPI_EVENT_RESCAN:
5765 ds = "Bus Rescan Event";
5766 /* Ok, do we need to do anything here? As far as
5767 I can tell, this is when a new device gets added
5768 to the loop. */
5769 break;
5770 case MPI_EVENT_LINK_STATUS_CHANGE:
5771 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5772 ds = "Link Status(FAILURE) Change";
5773 else
5774 ds = "Link Status(ACTIVE) Change";
5775 break;
5776 case MPI_EVENT_LOOP_STATE_CHANGE:
5777 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5778 ds = "Loop State(LIP) Change";
5779 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
5780 ds = "Loop State(LPE) Change"; /* ??? */
5781 else
5782 ds = "Loop State(LPB) Change"; /* ??? */
5783 break;
5784 case MPI_EVENT_LOGOUT:
5785 ds = "Logout";
5786 break;
5787 case MPI_EVENT_EVENT_CHANGE:
5788 if (evData0)
5789 ds = "Events(ON) Change";
5790 else
5791 ds = "Events(OFF) Change";
5792 break;
5793 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005794 {
5795 u8 ReasonCode = (u8)(evData0 >> 16);
5796 switch (ReasonCode) {
5797 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5798 ds = "Integrated Raid: Volume Created";
5799 break;
5800 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5801 ds = "Integrated Raid: Volume Deleted";
5802 break;
5803 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5804 ds = "Integrated Raid: Volume Settings Changed";
5805 break;
5806 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5807 ds = "Integrated Raid: Volume Status Changed";
5808 break;
5809 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5810 ds = "Integrated Raid: Volume Physdisk Changed";
5811 break;
5812 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5813 ds = "Integrated Raid: Physdisk Created";
5814 break;
5815 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5816 ds = "Integrated Raid: Physdisk Deleted";
5817 break;
5818 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5819 ds = "Integrated Raid: Physdisk Settings Changed";
5820 break;
5821 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5822 ds = "Integrated Raid: Physdisk Status Changed";
5823 break;
5824 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5825 ds = "Integrated Raid: Domain Validation Needed";
5826 break;
5827 case MPI_EVENT_RAID_RC_SMART_DATA :
5828 ds = "Integrated Raid; Smart Data";
5829 break;
5830 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5831 ds = "Integrated Raid: Replace Action Started";
5832 break;
5833 default:
5834 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005836 }
5837 break;
5838 }
5839 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5840 ds = "SCSI Device Status Change";
5841 break;
5842 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5843 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005844 char buf[50];
5845 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:
Moore, Eric3a892be2006-03-14 09:14:03 -07005849 sprintf(buf,"SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005850 break;
5851 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Moore, Eric3a892be2006-03-14 09:14:03 -07005852 sprintf(buf,"SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005853 break;
5854 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Moore, Eric3a892be2006-03-14 09:14:03 -07005855 sprintf(buf,"SAS Device Status Change: SMART Data: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005856 break;
5857 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Moore, Eric3a892be2006-03-14 09:14:03 -07005858 sprintf(buf,"SAS Device Status Change: No Persistancy Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005859 break;
5860 default:
Moore, Eric3a892be2006-03-14 09:14:03 -07005861 sprintf(buf,"SAS Device Status Change: Unknown: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005862 break;
5863 }
Moore, Eric3a892be2006-03-14 09:14:03 -07005864 ds = buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005865 break;
5866 }
5867 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5868 ds = "Bus Timer Expired";
5869 break;
5870 case MPI_EVENT_QUEUE_FULL:
5871 ds = "Queue Full";
5872 break;
5873 case MPI_EVENT_SAS_SES:
5874 ds = "SAS SES Event";
5875 break;
5876 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5877 ds = "Persistent Table Full";
5878 break;
5879 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005880 {
5881 char buf[50];
5882 u8 LinkRates = (u8)(evData0 >> 8);
5883 u8 PhyNumber = (u8)(evData0);
5884 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5885 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5886 switch (LinkRates) {
5887 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
5888 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5889 " Rate Unknown",PhyNumber);
5890 break;
5891 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
5892 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5893 " Phy Disabled",PhyNumber);
5894 break;
5895 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
5896 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5897 " Failed Speed Nego",PhyNumber);
5898 break;
5899 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
5900 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5901 " Sata OOB Completed",PhyNumber);
5902 break;
5903 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
5904 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5905 " Rate 1.5 Gbps",PhyNumber);
5906 break;
5907 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
5908 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5909 " Rate 3.0 Gpbs",PhyNumber);
5910 break;
5911 default:
5912 sprintf(buf,"SAS PHY Link Status: Phy=%d", PhyNumber);
5913 break;
5914 }
5915 ds = buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005916 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005917 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005918 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5919 ds = "SAS Discovery Error";
5920 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005921 case MPI_EVENT_IR_RESYNC_UPDATE:
5922 {
5923 u8 resync_complete = (u8)(evData0 >> 16);
5924 char buf[40];
5925 sprintf(buf,"IR Resync Update: Complete = %d:",resync_complete);
5926 ds = buf;
5927 break;
5928 }
5929 case MPI_EVENT_IR2:
5930 {
5931 u8 ReasonCode = (u8)(evData0 >> 16);
5932 switch (ReasonCode) {
5933 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5934 ds = "IR2: LD State Changed";
5935 break;
5936 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5937 ds = "IR2: PD State Changed";
5938 break;
5939 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5940 ds = "IR2: Bad Block Table Full";
5941 break;
5942 case MPI_EVENT_IR2_RC_PD_INSERTED:
5943 ds = "IR2: PD Inserted";
5944 break;
5945 case MPI_EVENT_IR2_RC_PD_REMOVED:
5946 ds = "IR2: PD Removed";
5947 break;
5948 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5949 ds = "IR2: Foreign CFG Detected";
5950 break;
5951 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5952 ds = "IR2: Rebuild Medium Error";
5953 break;
5954 default:
5955 ds = "IR2";
5956 break;
5957 }
5958 break;
5959 }
5960 case MPI_EVENT_SAS_DISCOVERY:
5961 {
5962 if (evData0)
5963 ds = "SAS Discovery: Start";
5964 else
5965 ds = "SAS Discovery: Stop";
5966 break;
5967 }
5968 case MPI_EVENT_LOG_ENTRY_ADDED:
5969 ds = "SAS Log Entry Added";
5970 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005971
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 /*
5973 * MPT base "custom" events may be added here...
5974 */
5975 default:
5976 ds = "Unknown";
5977 break;
5978 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005979 strcpy(evStr,ds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980}
5981
5982/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5983/*
5984 * ProcessEventNotification - Route a received EventNotificationReply to
5985 * all currently regeistered event handlers.
5986 * @ioc: Pointer to MPT_ADAPTER structure
5987 * @pEventReply: Pointer to EventNotification reply frame
5988 * @evHandlers: Pointer to integer, number of event handlers
5989 *
5990 * Returns sum of event handlers return values.
5991 */
5992static int
5993ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5994{
5995 u16 evDataLen;
5996 u32 evData0 = 0;
5997// u32 evCtx;
5998 int ii;
5999 int r = 0;
6000 int handlers = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006001 char evStr[100];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002 u8 event;
6003
6004 /*
6005 * Do platform normalization of values
6006 */
6007 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6008// evCtx = le32_to_cpu(pEventReply->EventContext);
6009 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6010 if (evDataLen) {
6011 evData0 = le32_to_cpu(pEventReply->Data[0]);
6012 }
6013
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006014 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07006015 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006017 event,
6018 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019
Moore, Eric3a892be2006-03-14 09:14:03 -07006020#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6022 for (ii = 0; ii < evDataLen; ii++)
6023 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6024 printk("\n");
6025#endif
6026
6027 /*
6028 * Do general / base driver event processing
6029 */
6030 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6032 if (evDataLen) {
6033 u8 evState = evData0 & 0xFF;
6034
6035 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6036
6037 /* Update EventState field in cached IocFacts */
6038 if (ioc->facts.Function) {
6039 ioc->facts.EventState = evState;
6040 }
6041 }
6042 break;
Moore, Ericece50912006-01-16 18:53:19 -07006043 case MPI_EVENT_INTEGRATED_RAID:
6044 mptbase_raid_process_event_data(ioc,
6045 (MpiEventDataRaid_t *)pEventReply->Data);
6046 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006047 default:
6048 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049 }
6050
6051 /*
6052 * Should this event be logged? Events are written sequentially.
6053 * When buffer is full, start again at the top.
6054 */
6055 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6056 int idx;
6057
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006058 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059
6060 ioc->events[idx].event = event;
6061 ioc->events[idx].eventContext = ioc->eventContext;
6062
6063 for (ii = 0; ii < 2; ii++) {
6064 if (ii < evDataLen)
6065 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6066 else
6067 ioc->events[idx].data[ii] = 0;
6068 }
6069
6070 ioc->eventContext++;
6071 }
6072
6073
6074 /*
6075 * Call each currently registered protocol event handler.
6076 */
6077 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6078 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006079 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 ioc->name, ii));
6081 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6082 handlers++;
6083 }
6084 }
6085 /* FIXME? Examine results here? */
6086
6087 /*
6088 * If needed, send (a single) EventAck.
6089 */
6090 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006091 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006092 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006094 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 ioc->name, ii));
6096 }
6097 }
6098
6099 *evHandlers = handlers;
6100 return r;
6101}
6102
6103/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6104/*
6105 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6106 * @ioc: Pointer to MPT_ADAPTER structure
6107 * @log_info: U32 LogInfo reply word from the IOC
6108 *
6109 * Refer to lsi/fc_log.h.
6110 */
6111static void
6112mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6113{
6114 static char *subcl_str[8] = {
6115 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6116 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6117 };
6118 u8 subcl = (log_info >> 24) & 0x7;
6119
6120 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6121 ioc->name, log_info, subcl_str[subcl]);
6122}
6123
6124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6125/*
Moore, Eric335a9412006-01-17 17:06:23 -07006126 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 * @ioc: Pointer to MPT_ADAPTER structure
6128 * @mr: Pointer to MPT reply frame
6129 * @log_info: U32 LogInfo word from the IOC
6130 *
6131 * Refer to lsi/sp_log.h.
6132 */
6133static void
Moore, Eric335a9412006-01-17 17:06:23 -07006134mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135{
6136 u32 info = log_info & 0x00FF0000;
6137 char *desc = "unknown";
6138
6139 switch (info) {
6140 case 0x00010000:
6141 desc = "bug! MID not found";
6142 if (ioc->reload_fw == 0)
6143 ioc->reload_fw++;
6144 break;
6145
6146 case 0x00020000:
6147 desc = "Parity Error";
6148 break;
6149
6150 case 0x00030000:
6151 desc = "ASYNC Outbound Overrun";
6152 break;
6153
6154 case 0x00040000:
6155 desc = "SYNC Offset Error";
6156 break;
6157
6158 case 0x00050000:
6159 desc = "BM Change";
6160 break;
6161
6162 case 0x00060000:
6163 desc = "Msg In Overflow";
6164 break;
6165
6166 case 0x00070000:
6167 desc = "DMA Error";
6168 break;
6169
6170 case 0x00080000:
6171 desc = "Outbound DMA Overrun";
6172 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006173
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174 case 0x00090000:
6175 desc = "Task Management";
6176 break;
6177
6178 case 0x000A0000:
6179 desc = "Device Problem";
6180 break;
6181
6182 case 0x000B0000:
6183 desc = "Invalid Phase Change";
6184 break;
6185
6186 case 0x000C0000:
6187 desc = "Untagged Table Size";
6188 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006189
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190 }
6191
6192 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6193}
6194
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006195/* strings for sas loginfo */
6196 static char *originator_str[] = {
6197 "IOP", /* 00h */
6198 "PL", /* 01h */
6199 "IR" /* 02h */
6200 };
6201 static char *iop_code_str[] = {
6202 NULL, /* 00h */
6203 "Invalid SAS Address", /* 01h */
6204 NULL, /* 02h */
6205 "Invalid Page", /* 03h */
6206 NULL, /* 04h */
6207 "Task Terminated" /* 05h */
6208 };
6209 static char *pl_code_str[] = {
6210 NULL, /* 00h */
6211 "Open Failure", /* 01h */
6212 "Invalid Scatter Gather List", /* 02h */
6213 "Wrong Relative Offset or Frame Length", /* 03h */
6214 "Frame Transfer Error", /* 04h */
6215 "Transmit Frame Connected Low", /* 05h */
6216 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6217 "SATA Read Log Receive Data Error", /* 07h */
6218 "SATA NCQ Fail All Commands After Error", /* 08h */
6219 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6220 "Receive Frame Invalid Message", /* 0Ah */
6221 "Receive Context Message Valid Error", /* 0Bh */
6222 "Receive Frame Current Frame Error", /* 0Ch */
6223 "SATA Link Down", /* 0Dh */
6224 "Discovery SATA Init W IOS", /* 0Eh */
6225 "Config Invalid Page", /* 0Fh */
6226 "Discovery SATA Init Timeout", /* 10h */
6227 "Reset", /* 11h */
6228 "Abort", /* 12h */
6229 "IO Not Yet Executed", /* 13h */
6230 "IO Executed", /* 14h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006231 "Persistant Reservation Out Not Affiliation Owner", /* 15h */
6232 "Open Transmit DMA Abort", /* 16h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006233 NULL, /* 17h */
6234 NULL, /* 18h */
6235 NULL, /* 19h */
6236 NULL, /* 1Ah */
6237 NULL, /* 1Bh */
6238 NULL, /* 1Ch */
6239 NULL, /* 1Dh */
6240 NULL, /* 1Eh */
6241 NULL, /* 1Fh */
6242 "Enclosure Management" /* 20h */
6243 };
6244
6245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6246/*
6247 * mpt_sas_log_info - Log information returned from SAS IOC.
6248 * @ioc: Pointer to MPT_ADAPTER structure
6249 * @log_info: U32 LogInfo reply word from the IOC
6250 *
6251 * Refer to lsi/mpi_log_sas.h.
6252 */
6253static void
6254mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6255{
6256union loginfo_type {
6257 u32 loginfo;
6258 struct {
6259 u32 subcode:16;
6260 u32 code:8;
6261 u32 originator:4;
6262 u32 bus_type:4;
6263 }dw;
6264};
6265 union loginfo_type sas_loginfo;
6266 char *code_desc = NULL;
6267
6268 sas_loginfo.loginfo = log_info;
6269 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6270 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6271 return;
6272 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6273 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6274 code_desc = iop_code_str[sas_loginfo.dw.code];
6275 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6276 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6277 code_desc = pl_code_str[sas_loginfo.dw.code];
6278 }
6279
6280 if (code_desc != NULL)
6281 printk(MYIOC_s_INFO_FMT
6282 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6283 " SubCode(0x%04x)\n",
6284 ioc->name,
6285 log_info,
6286 originator_str[sas_loginfo.dw.originator],
6287 code_desc,
6288 sas_loginfo.dw.subcode);
6289 else
6290 printk(MYIOC_s_INFO_FMT
6291 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6292 " SubCode(0x%04x)\n",
6293 ioc->name,
6294 log_info,
6295 originator_str[sas_loginfo.dw.originator],
6296 sas_loginfo.dw.code,
6297 sas_loginfo.dw.subcode);
6298}
6299
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6301/*
6302 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6303 * @ioc: Pointer to MPT_ADAPTER structure
6304 * @ioc_status: U32 IOCStatus word from IOC
6305 * @mf: Pointer to MPT request frame
6306 *
6307 * Refer to lsi/mpi.h.
6308 */
6309static void
6310mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6311{
6312 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
6313 char *desc = "";
6314
6315 switch (status) {
6316 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6317 desc = "Invalid Function";
6318 break;
6319
6320 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6321 desc = "Busy";
6322 break;
6323
6324 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6325 desc = "Invalid SGL";
6326 break;
6327
6328 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6329 desc = "Internal Error";
6330 break;
6331
6332 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6333 desc = "Reserved";
6334 break;
6335
6336 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6337 desc = "Insufficient Resources";
6338 break;
6339
6340 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6341 desc = "Invalid Field";
6342 break;
6343
6344 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6345 desc = "Invalid State";
6346 break;
6347
6348 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6349 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6350 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6351 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6352 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6353 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6354 /* No message for Config IOCStatus values */
6355 break;
6356
6357 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6358 /* No message for recovered error
6359 desc = "SCSI Recovered Error";
6360 */
6361 break;
6362
6363 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6364 desc = "SCSI Invalid Bus";
6365 break;
6366
6367 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6368 desc = "SCSI Invalid TargetID";
6369 break;
6370
6371 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6372 {
6373 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6374 U8 cdb = pScsiReq->CDB[0];
6375 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6376 desc = "SCSI Device Not There";
6377 }
6378 break;
6379 }
6380
6381 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6382 desc = "SCSI Data Overrun";
6383 break;
6384
6385 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006386 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387 desc = "SCSI Data Underrun";
6388 */
6389 break;
6390
6391 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6392 desc = "SCSI I/O Data Error";
6393 break;
6394
6395 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6396 desc = "SCSI Protocol Error";
6397 break;
6398
6399 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6400 desc = "SCSI Task Terminated";
6401 break;
6402
6403 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6404 desc = "SCSI Residual Mismatch";
6405 break;
6406
6407 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6408 desc = "SCSI Task Management Failed";
6409 break;
6410
6411 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6412 desc = "SCSI IOC Terminated";
6413 break;
6414
6415 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6416 desc = "SCSI Ext Terminated";
6417 break;
6418
6419 default:
6420 desc = "Others";
6421 break;
6422 }
6423 if (desc != "")
6424 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6425}
6426
6427/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006428EXPORT_SYMBOL(mpt_attach);
6429EXPORT_SYMBOL(mpt_detach);
6430#ifdef CONFIG_PM
6431EXPORT_SYMBOL(mpt_resume);
6432EXPORT_SYMBOL(mpt_suspend);
6433#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006435EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006436EXPORT_SYMBOL(mpt_register);
6437EXPORT_SYMBOL(mpt_deregister);
6438EXPORT_SYMBOL(mpt_event_register);
6439EXPORT_SYMBOL(mpt_event_deregister);
6440EXPORT_SYMBOL(mpt_reset_register);
6441EXPORT_SYMBOL(mpt_reset_deregister);
6442EXPORT_SYMBOL(mpt_device_driver_register);
6443EXPORT_SYMBOL(mpt_device_driver_deregister);
6444EXPORT_SYMBOL(mpt_get_msg_frame);
6445EXPORT_SYMBOL(mpt_put_msg_frame);
6446EXPORT_SYMBOL(mpt_free_msg_frame);
6447EXPORT_SYMBOL(mpt_add_sge);
6448EXPORT_SYMBOL(mpt_send_handshake_request);
6449EXPORT_SYMBOL(mpt_verify_adapter);
6450EXPORT_SYMBOL(mpt_GetIocState);
6451EXPORT_SYMBOL(mpt_print_ioc_summary);
6452EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006453EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006454EXPORT_SYMBOL(mpt_HardResetHandler);
6455EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006457EXPORT_SYMBOL(mpt_alloc_fw_memory);
6458EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006459EXPORT_SYMBOL(mptbase_sas_persist_operation);
Michael Reed05e8ec12006-01-13 14:31:54 -06006460EXPORT_SYMBOL(mptbase_GetFcPortPage0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006461
Linus Torvalds1da177e2005-04-16 15:20:36 -07006462
6463/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6464/*
6465 * fusion_init - Fusion MPT base driver initialization routine.
6466 *
6467 * Returns 0 for success, non-zero for failure.
6468 */
6469static int __init
6470fusion_init(void)
6471{
6472 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473
6474 show_mptmod_ver(my_NAME, my_VERSION);
6475 printk(KERN_INFO COPYRIGHT "\n");
6476
6477 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6478 MptCallbacks[i] = NULL;
6479 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6480 MptEvHandlers[i] = NULL;
6481 MptResetHandlers[i] = NULL;
6482 }
6483
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006484 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006485 * EventNotification handling.
6486 */
6487 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6488
6489 /* Register for hard reset handling callbacks.
6490 */
6491 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6492 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6493 } else {
6494 /* FIXME! */
6495 }
6496
6497#ifdef CONFIG_PROC_FS
6498 (void) procmpt_create();
6499#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006500 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006501}
6502
6503/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6504/*
6505 * fusion_exit - Perform driver unload cleanup.
6506 *
6507 * This routine frees all resources associated with each MPT adapter
6508 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6509 */
6510static void __exit
6511fusion_exit(void)
6512{
6513
6514 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6515
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516 mpt_reset_deregister(mpt_base_index);
6517
6518#ifdef CONFIG_PROC_FS
6519 procmpt_destroy();
6520#endif
6521}
6522
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523module_init(fusion_init);
6524module_exit(fusion_exit);