blob: bb7ad4d0678a0146aa801da38672e13965883000 [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
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001390 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 */
1392 mpt_detect_bound_ports(ioc, pdev);
1393
James Bottomleyc92f2222006-03-01 09:02:49 -06001394 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1395 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 printk(KERN_WARNING MYNAM
1397 ": WARNING - %s did not initialize properly! (%d)\n",
1398 ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001400 if (ioc->alt_ioc)
1401 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 iounmap(mem);
1403 kfree(ioc);
1404 pci_set_drvdata(pdev, NULL);
1405 return r;
1406 }
1407
1408 /* call per device driver probe entry point */
1409 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1410 if(MptDeviceDriverHandlers[ii] &&
1411 MptDeviceDriverHandlers[ii]->probe) {
1412 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1413 }
1414 }
1415
1416#ifdef CONFIG_PROC_FS
1417 /*
1418 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1419 */
1420 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1421 if (dent) {
1422 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1423 if (ent) {
1424 ent->read_proc = procmpt_iocinfo_read;
1425 ent->data = ioc;
1426 }
1427 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1428 if (ent) {
1429 ent->read_proc = procmpt_summary_read;
1430 ent->data = ioc;
1431 }
1432 }
1433#endif
1434
1435 return 0;
1436}
1437
1438/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1439/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001440 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 * @pdev: Pointer to pci_dev structure
1442 *
1443 */
1444
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001445void
1446mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447{
1448 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1449 char pname[32];
1450 int ii;
1451
1452 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1453 remove_proc_entry(pname, NULL);
1454 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1455 remove_proc_entry(pname, NULL);
1456 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1457 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001458
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 /* call per device driver remove entry point */
1460 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1461 if(MptDeviceDriverHandlers[ii] &&
1462 MptDeviceDriverHandlers[ii]->remove) {
1463 MptDeviceDriverHandlers[ii]->remove(pdev);
1464 }
1465 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001466
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 /* Disable interrupts! */
1468 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1469
1470 ioc->active = 0;
1471 synchronize_irq(pdev->irq);
1472
1473 /* Clear any lingering interrupt */
1474 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1475
1476 CHIPREG_READ32(&ioc->chip->IntStatus);
1477
1478 mpt_adapter_dispose(ioc);
1479
1480 pci_set_drvdata(pdev, NULL);
1481}
1482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483/**************************************************************************
1484 * Power Management
1485 */
1486#ifdef CONFIG_PM
1487/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1488/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001489 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 *
1491 *
1492 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001493int
1494mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495{
1496 u32 device_state;
1497 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
Pavel Machek2a569572005-07-07 17:56:40 -07001499 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
1501 printk(MYIOC_s_INFO_FMT
1502 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1503 ioc->name, pdev, pci_name(pdev), device_state);
1504
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 pci_save_state(pdev);
1506
1507 /* put ioc into READY_STATE */
1508 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1509 printk(MYIOC_s_ERR_FMT
1510 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1511 }
1512
1513 /* disable interrupts */
1514 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1515 ioc->active = 0;
1516
1517 /* Clear any lingering interrupt */
1518 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1519
1520 pci_disable_device(pdev);
1521 pci_set_power_state(pdev, device_state);
1522
1523 return 0;
1524}
1525
1526/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1527/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001528 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 *
1530 *
1531 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001532int
1533mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534{
1535 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1536 u32 device_state = pdev->current_state;
1537 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 printk(MYIOC_s_INFO_FMT
1540 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1541 ioc->name, pdev, pci_name(pdev), device_state);
1542
1543 pci_set_power_state(pdev, 0);
1544 pci_restore_state(pdev);
1545 pci_enable_device(pdev);
1546
1547 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001548 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 ioc->active = 1;
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 printk(MYIOC_s_INFO_FMT
1552 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1553 ioc->name,
1554 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1555 CHIPREG_READ32(&ioc->chip->Doorbell));
1556
1557 /* bring ioc to operational state */
1558 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1559 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1560 printk(MYIOC_s_INFO_FMT
1561 "pci-resume: Cannot recover, error:[%x]\n",
1562 ioc->name, recovery_state);
1563 } else {
1564 printk(MYIOC_s_INFO_FMT
1565 "pci-resume: success\n", ioc->name);
1566 }
1567
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 return 0;
1569}
1570#endif
1571
1572/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1573/*
1574 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1575 * @ioc: Pointer to MPT adapter structure
1576 * @reason: Event word / reason
1577 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1578 *
1579 * This routine performs all the steps necessary to bring the IOC
1580 * to a OPERATIONAL state.
1581 *
1582 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1583 * MPT adapter.
1584 *
1585 * Returns:
1586 * 0 for success
1587 * -1 if failed to get board READY
1588 * -2 if READY but IOCFacts Failed
1589 * -3 if READY but PrimeIOCFifos Failed
1590 * -4 if READY but IOCInit Failed
1591 */
1592static int
1593mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1594{
1595 int hard_reset_done = 0;
1596 int alt_ioc_ready = 0;
1597 int hard;
1598 int rc=0;
1599 int ii;
1600 int handlers;
1601 int ret = 0;
1602 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001603 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
1605 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1606 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1607
1608 /* Disable reply interrupts (also blocks FreeQ) */
1609 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1610 ioc->active = 0;
1611
1612 if (ioc->alt_ioc) {
1613 if (ioc->alt_ioc->active)
1614 reset_alt_ioc_active = 1;
1615
1616 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1617 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1618 ioc->alt_ioc->active = 0;
1619 }
1620
1621 hard = 1;
1622 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1623 hard = 0;
1624
1625 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1626 if (hard_reset_done == -4) {
1627 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1628 ioc->name);
1629
1630 if (reset_alt_ioc_active && ioc->alt_ioc) {
1631 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1632 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1633 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001634 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 ioc->alt_ioc->active = 1;
1636 }
1637
1638 } else {
1639 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1640 ioc->name);
1641 }
1642 return -1;
1643 }
1644
1645 /* hard_reset_done = 0 if a soft reset was performed
1646 * and 1 if a hard reset was performed.
1647 */
1648 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1649 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1650 alt_ioc_ready = 1;
1651 else
1652 printk(KERN_WARNING MYNAM
1653 ": alt-%s: Not ready WARNING!\n",
1654 ioc->alt_ioc->name);
1655 }
1656
1657 for (ii=0; ii<5; ii++) {
1658 /* Get IOC facts! Allow 5 retries */
1659 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1660 break;
1661 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
1664 if (ii == 5) {
1665 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1666 ret = -2;
1667 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1668 MptDisplayIocCapabilities(ioc);
1669 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001670
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 if (alt_ioc_ready) {
1672 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1673 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1674 /* Retry - alt IOC was initialized once
1675 */
1676 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1677 }
1678 if (rc) {
1679 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1680 alt_ioc_ready = 0;
1681 reset_alt_ioc_active = 0;
1682 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1683 MptDisplayIocCapabilities(ioc->alt_ioc);
1684 }
1685 }
1686
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001687 /*
1688 * Device is reset now. It must have de-asserted the interrupt line
1689 * (if it was asserted) and it should be safe to register for the
1690 * interrupt now.
1691 */
1692 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1693 ioc->pci_irq = -1;
1694 if (ioc->pcidev->irq) {
1695 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1696 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1697 ioc->name);
1698 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
1699 SA_SHIRQ, ioc->name, ioc);
1700 if (rc < 0) {
1701#ifndef __sparc__
1702 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1703 "interrupt %d!\n", ioc->name,
1704 ioc->pcidev->irq);
1705#else
1706 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1707 "interrupt %s!\n", ioc->name,
1708 __irq_itoa(ioc->pcidev->irq));
1709#endif
1710 if (mpt_msi_enable)
1711 pci_disable_msi(ioc->pcidev);
1712 return -EBUSY;
1713 }
1714 irq_allocated = 1;
1715 ioc->pci_irq = ioc->pcidev->irq;
1716 pci_set_master(ioc->pcidev); /* ?? */
1717 pci_set_drvdata(ioc->pcidev, ioc);
1718#ifndef __sparc__
1719 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1720 "%d\n", ioc->name, ioc->pcidev->irq));
1721#else
1722 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1723 "%s\n", ioc->name,
1724 __irq_itoa(ioc->pcidev->irq)));
1725#endif
1726 }
1727 }
1728
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 /* Prime reply & request queues!
1730 * (mucho alloc's) Must be done prior to
1731 * init as upper addresses are needed for init.
1732 * If fails, continue with alt-ioc processing
1733 */
1734 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1735 ret = -3;
1736
1737 /* May need to check/upload firmware & data here!
1738 * If fails, continue with alt-ioc processing
1739 */
1740 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1741 ret = -4;
1742// NEW!
1743 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1744 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1745 ioc->alt_ioc->name, rc);
1746 alt_ioc_ready = 0;
1747 reset_alt_ioc_active = 0;
1748 }
1749
1750 if (alt_ioc_ready) {
1751 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1752 alt_ioc_ready = 0;
1753 reset_alt_ioc_active = 0;
1754 printk(KERN_WARNING MYNAM
1755 ": alt-%s: (%d) init failure WARNING!\n",
1756 ioc->alt_ioc->name, rc);
1757 }
1758 }
1759
1760 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1761 if (ioc->upload_fw) {
1762 ddlprintk((MYIOC_s_INFO_FMT
1763 "firmware upload required!\n", ioc->name));
1764
1765 /* Controller is not operational, cannot do upload
1766 */
1767 if (ret == 0) {
1768 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001769 if (rc == 0) {
1770 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1771 /*
1772 * Maintain only one pointer to FW memory
1773 * so there will not be two attempt to
1774 * downloadboot onboard dual function
1775 * chips (mpt_adapter_disable,
1776 * mpt_diag_reset)
1777 */
1778 ioc->cached_fw = NULL;
1779 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1780 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1781 }
1782 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001784 ret = -5;
1785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 }
1787 }
1788 }
1789
1790 if (ret == 0) {
1791 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001792 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 ioc->active = 1;
1794 }
1795
1796 if (reset_alt_ioc_active && ioc->alt_ioc) {
1797 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001798 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001800 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 ioc->alt_ioc->active = 1;
1802 }
1803
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001804 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 * and EventAck handling.
1806 */
1807 if ((ret == 0) && (!ioc->facts.EventState))
1808 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1809
1810 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1811 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1812
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001813 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1815 * recursive scenario; GetLanConfigPages times out, timer expired
1816 * routine calls HardResetHandler, which calls into here again,
1817 * and we try GetLanConfigPages again...
1818 */
1819 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001820 if (ioc->bus_type == SAS) {
1821
1822 /* clear persistency table */
1823 if(ioc->facts.IOCExceptions &
1824 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1825 ret = mptbase_sas_persist_operation(ioc,
1826 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1827 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001828 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001829 }
1830
1831 /* Find IM volumes
1832 */
1833 mpt_findImVolumes(ioc);
1834
1835 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 /*
1837 * Pre-fetch FC port WWN and stuff...
1838 * (FCPortPage0_t stuff)
1839 */
1840 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
Michael Reed05e8ec12006-01-13 14:31:54 -06001841 (void) mptbase_GetFcPortPage0(ioc, ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 }
1843
1844 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1845 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1846 /*
1847 * Pre-fetch the ports LAN MAC address!
1848 * (LANPage1_t stuff)
1849 */
1850 (void) GetLanConfigPages(ioc);
1851#ifdef MPT_DEBUG
1852 {
1853 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1854 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1855 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1856 }
1857#endif
1858 }
1859 } else {
1860 /* Get NVRAM and adapter maximums from SPP 0 and 2
1861 */
1862 mpt_GetScsiPortSettings(ioc, 0);
1863
1864 /* Get version and length of SDP 1
1865 */
1866 mpt_readScsiDevicePageHeaders(ioc, 0);
1867
1868 /* Find IM volumes
1869 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001870 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 mpt_findImVolumes(ioc);
1872
1873 /* Check, and possibly reset, the coalescing value
1874 */
1875 mpt_read_ioc_pg_1(ioc);
1876
1877 mpt_read_ioc_pg_4(ioc);
1878 }
1879
1880 GetIoUnitPage2(ioc);
1881 }
1882
1883 /*
1884 * Call each currently registered protocol IOC reset handler
1885 * with post-reset indication.
1886 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1887 * MptResetHandlers[] registered yet.
1888 */
1889 if (hard_reset_done) {
1890 rc = handlers = 0;
1891 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1892 if ((ret == 0) && MptResetHandlers[ii]) {
1893 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1894 ioc->name, ii));
1895 rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
1896 handlers++;
1897 }
1898
1899 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001900 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 ioc->name, ioc->alt_ioc->name, ii));
1902 rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
1903 handlers++;
1904 }
1905 }
1906 /* FIXME? Examine results here? */
1907 }
1908
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001909out:
1910 if ((ret != 0) && irq_allocated) {
1911 free_irq(ioc->pci_irq, ioc);
1912 if (mpt_msi_enable)
1913 pci_disable_msi(ioc->pcidev);
1914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 return ret;
1916}
1917
1918/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1919/*
1920 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1921 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1922 * 929X, 1030 or 1035.
1923 * @ioc: Pointer to MPT adapter structure
1924 * @pdev: Pointer to (struct pci_dev) structure
1925 *
1926 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1927 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1928 */
1929static void
1930mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1931{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001932 struct pci_dev *peer=NULL;
1933 unsigned int slot = PCI_SLOT(pdev->devfn);
1934 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 MPT_ADAPTER *ioc_srch;
1936
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001937 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1938 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001939 ioc->name, pci_name(pdev), pdev->bus->number,
1940 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001941
1942 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1943 if (!peer) {
1944 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1945 if (!peer)
1946 return;
1947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
1949 list_for_each_entry(ioc_srch, &ioc_list, list) {
1950 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001951 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 /* Paranoia checks */
1953 if (ioc->alt_ioc != NULL) {
1954 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001955 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 break;
1957 } else if (ioc_srch->alt_ioc != NULL) {
1958 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001959 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 break;
1961 }
1962 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001963 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 ioc_srch->alt_ioc = ioc;
1965 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 }
1967 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001968 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969}
1970
1971/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1972/*
1973 * mpt_adapter_disable - Disable misbehaving MPT adapter.
1974 * @this: Pointer to MPT adapter structure
1975 */
1976static void
1977mpt_adapter_disable(MPT_ADAPTER *ioc)
1978{
1979 int sz;
1980 int ret;
1981
1982 if (ioc->cached_fw != NULL) {
1983 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001984 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 printk(KERN_WARNING MYNAM
1986 ": firmware downloadboot failure (%d)!\n", ret);
1987 }
1988 }
1989
1990 /* Disable adapter interrupts! */
1991 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1992 ioc->active = 0;
1993 /* Clear any lingering interrupt */
1994 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1995
1996 if (ioc->alloc != NULL) {
1997 sz = ioc->alloc_sz;
1998 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1999 ioc->name, ioc->alloc, ioc->alloc_sz));
2000 pci_free_consistent(ioc->pcidev, sz,
2001 ioc->alloc, ioc->alloc_dma);
2002 ioc->reply_frames = NULL;
2003 ioc->req_frames = NULL;
2004 ioc->alloc = NULL;
2005 ioc->alloc_total -= sz;
2006 }
2007
2008 if (ioc->sense_buf_pool != NULL) {
2009 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2010 pci_free_consistent(ioc->pcidev, sz,
2011 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2012 ioc->sense_buf_pool = NULL;
2013 ioc->alloc_total -= sz;
2014 }
2015
2016 if (ioc->events != NULL){
2017 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2018 kfree(ioc->events);
2019 ioc->events = NULL;
2020 ioc->alloc_total -= sz;
2021 }
2022
2023 if (ioc->cached_fw != NULL) {
2024 sz = ioc->facts.FWImageSize;
2025 pci_free_consistent(ioc->pcidev, sz,
2026 ioc->cached_fw, ioc->cached_fw_dma);
2027 ioc->cached_fw = NULL;
2028 ioc->alloc_total -= sz;
2029 }
2030
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002031 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002032 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002033 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002034 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
2036 if (ioc->spi_data.pIocPg4 != NULL) {
2037 sz = ioc->spi_data.IocPg4Sz;
2038 pci_free_consistent(ioc->pcidev, sz,
2039 ioc->spi_data.pIocPg4,
2040 ioc->spi_data.IocPg4_dma);
2041 ioc->spi_data.pIocPg4 = NULL;
2042 ioc->alloc_total -= sz;
2043 }
2044
2045 if (ioc->ReqToChain != NULL) {
2046 kfree(ioc->ReqToChain);
2047 kfree(ioc->RequestNB);
2048 ioc->ReqToChain = NULL;
2049 }
2050
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002051 kfree(ioc->ChainToChain);
2052 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002053
2054 if (ioc->HostPageBuffer != NULL) {
2055 if((ret = mpt_host_page_access_control(ioc,
2056 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2057 printk(KERN_ERR MYNAM
2058 ": %s: host page buffers free failed (%d)!\n",
2059 __FUNCTION__, ret);
2060 }
2061 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2062 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2063 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2064 ioc->HostPageBuffer,
2065 ioc->HostPageBuffer_dma);
2066 ioc->HostPageBuffer = NULL;
2067 ioc->HostPageBuffer_sz = 0;
2068 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070}
2071
2072/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2073/*
2074 * mpt_adapter_dispose - Free all resources associated with a MPT
2075 * adapter.
2076 * @ioc: Pointer to MPT adapter structure
2077 *
2078 * This routine unregisters h/w resources and frees all alloc'd memory
2079 * associated with a MPT adapter structure.
2080 */
2081static void
2082mpt_adapter_dispose(MPT_ADAPTER *ioc)
2083{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002084 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002086 if (ioc == NULL)
2087 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002089 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002091 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002093 if (ioc->pci_irq != -1) {
2094 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002095 if (mpt_msi_enable)
2096 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002097 ioc->pci_irq = -1;
2098 }
2099
2100 if (ioc->memmap != NULL) {
2101 iounmap(ioc->memmap);
2102 ioc->memmap = NULL;
2103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
2105#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002106 if (ioc->mtrr_reg > 0) {
2107 mtrr_del(ioc->mtrr_reg, 0, 0);
2108 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110#endif
2111
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002112 /* Zap the adapter lookup ptr! */
2113 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002115 sz_last = ioc->alloc_total;
2116 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2117 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002118
2119 if (ioc->alt_ioc)
2120 ioc->alt_ioc->alt_ioc = NULL;
2121
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002122 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123}
2124
2125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2126/*
2127 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2128 * @ioc: Pointer to MPT adapter structure
2129 */
2130static void
2131MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2132{
2133 int i = 0;
2134
2135 printk(KERN_INFO "%s: ", ioc->name);
2136 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2137 printk("%s: ", ioc->prod_name+3);
2138 printk("Capabilities={");
2139
2140 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2141 printk("Initiator");
2142 i++;
2143 }
2144
2145 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2146 printk("%sTarget", i ? "," : "");
2147 i++;
2148 }
2149
2150 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2151 printk("%sLAN", i ? "," : "");
2152 i++;
2153 }
2154
2155#if 0
2156 /*
2157 * This would probably evoke more questions than it's worth
2158 */
2159 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2160 printk("%sLogBusAddr", i ? "," : "");
2161 i++;
2162 }
2163#endif
2164
2165 printk("}\n");
2166}
2167
2168/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2169/*
2170 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2171 * @ioc: Pointer to MPT_ADAPTER structure
2172 * @force: Force hard KickStart of IOC
2173 * @sleepFlag: Specifies whether the process can sleep
2174 *
2175 * Returns:
2176 * 1 - DIAG reset and READY
2177 * 0 - READY initially OR soft reset and READY
2178 * -1 - Any failure on KickStart
2179 * -2 - Msg Unit Reset Failed
2180 * -3 - IO Unit Reset Failed
2181 * -4 - IOC owned by a PEER
2182 */
2183static int
2184MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2185{
2186 u32 ioc_state;
2187 int statefault = 0;
2188 int cntdn;
2189 int hard_reset_done = 0;
2190 int r;
2191 int ii;
2192 int whoinit;
2193
2194 /* Get current [raw] IOC state */
2195 ioc_state = mpt_GetIocState(ioc, 0);
2196 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2197
2198 /*
2199 * Check to see if IOC got left/stuck in doorbell handshake
2200 * grip of death. If so, hard reset the IOC.
2201 */
2202 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2203 statefault = 1;
2204 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2205 ioc->name);
2206 }
2207
2208 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002209 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 return 0;
2211
2212 /*
2213 * Check to see if IOC is in FAULT state.
2214 */
2215 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2216 statefault = 2;
2217 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2218 ioc->name);
2219 printk(KERN_WARNING " FAULT code = %04xh\n",
2220 ioc_state & MPI_DOORBELL_DATA_MASK);
2221 }
2222
2223 /*
2224 * Hmmm... Did it get left operational?
2225 */
2226 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002227 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 ioc->name));
2229
2230 /* Check WhoInit.
2231 * If PCI Peer, exit.
2232 * Else, if no fault conditions are present, issue a MessageUnitReset
2233 * Else, fall through to KickStart case
2234 */
2235 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002236 dinitprintk((KERN_INFO MYNAM
2237 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 whoinit, statefault, force));
2239 if (whoinit == MPI_WHOINIT_PCI_PEER)
2240 return -4;
2241 else {
2242 if ((statefault == 0 ) && (force == 0)) {
2243 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2244 return 0;
2245 }
2246 statefault = 3;
2247 }
2248 }
2249
2250 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2251 if (hard_reset_done < 0)
2252 return -1;
2253
2254 /*
2255 * Loop here waiting for IOC to come READY.
2256 */
2257 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002258 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259
2260 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2261 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2262 /*
2263 * BIOS or previous driver load left IOC in OP state.
2264 * Reset messaging FIFOs.
2265 */
2266 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2267 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2268 return -2;
2269 }
2270 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2271 /*
2272 * Something is wrong. Try to get IOC back
2273 * to a known state.
2274 */
2275 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2276 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2277 return -3;
2278 }
2279 }
2280
2281 ii++; cntdn--;
2282 if (!cntdn) {
2283 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2284 ioc->name, (int)((ii+5)/HZ));
2285 return -ETIME;
2286 }
2287
2288 if (sleepFlag == CAN_SLEEP) {
2289 msleep_interruptible(1);
2290 } else {
2291 mdelay (1); /* 1 msec delay */
2292 }
2293
2294 }
2295
2296 if (statefault < 3) {
2297 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2298 ioc->name,
2299 statefault==1 ? "stuck handshake" : "IOC FAULT");
2300 }
2301
2302 return hard_reset_done;
2303}
2304
2305/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2306/*
2307 * mpt_GetIocState - Get the current state of a MPT adapter.
2308 * @ioc: Pointer to MPT_ADAPTER structure
2309 * @cooked: Request raw or cooked IOC state
2310 *
2311 * Returns all IOC Doorbell register bits if cooked==0, else just the
2312 * Doorbell bits in MPI_IOC_STATE_MASK.
2313 */
2314u32
2315mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2316{
2317 u32 s, sc;
2318
2319 /* Get! */
2320 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2321// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2322 sc = s & MPI_IOC_STATE_MASK;
2323
2324 /* Save! */
2325 ioc->last_state = sc;
2326
2327 return cooked ? sc : s;
2328}
2329
2330/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2331/*
2332 * GetIocFacts - Send IOCFacts request to MPT adapter.
2333 * @ioc: Pointer to MPT_ADAPTER structure
2334 * @sleepFlag: Specifies whether the process can sleep
2335 * @reason: If recovery, only update facts.
2336 *
2337 * Returns 0 for success, non-zero for failure.
2338 */
2339static int
2340GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2341{
2342 IOCFacts_t get_facts;
2343 IOCFactsReply_t *facts;
2344 int r;
2345 int req_sz;
2346 int reply_sz;
2347 int sz;
2348 u32 status, vv;
2349 u8 shiftFactor=1;
2350
2351 /* IOC *must* NOT be in RESET state! */
2352 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2353 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2354 ioc->name,
2355 ioc->last_state );
2356 return -44;
2357 }
2358
2359 facts = &ioc->facts;
2360
2361 /* Destination (reply area)... */
2362 reply_sz = sizeof(*facts);
2363 memset(facts, 0, reply_sz);
2364
2365 /* Request area (get_facts on the stack right now!) */
2366 req_sz = sizeof(get_facts);
2367 memset(&get_facts, 0, req_sz);
2368
2369 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2370 /* Assert: All other get_facts fields are zero! */
2371
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002372 dinitprintk((MYIOC_s_INFO_FMT
2373 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 ioc->name, req_sz, reply_sz));
2375
2376 /* No non-zero fields in the get_facts request are greater than
2377 * 1 byte in size, so we can just fire it off as is.
2378 */
2379 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2380 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2381 if (r != 0)
2382 return r;
2383
2384 /*
2385 * Now byte swap (GRRR) the necessary fields before any further
2386 * inspection of reply contents.
2387 *
2388 * But need to do some sanity checks on MsgLength (byte) field
2389 * to make sure we don't zero IOC's req_sz!
2390 */
2391 /* Did we get a valid reply? */
2392 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2393 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2394 /*
2395 * If not been here, done that, save off first WhoInit value
2396 */
2397 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2398 ioc->FirstWhoInit = facts->WhoInit;
2399 }
2400
2401 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2402 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2403 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2404 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2405 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002406 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 /* CHECKME! IOCStatus, IOCLogInfo */
2408
2409 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2410 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2411
2412 /*
2413 * FC f/w version changed between 1.1 and 1.2
2414 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2415 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2416 */
2417 if (facts->MsgVersion < 0x0102) {
2418 /*
2419 * Handle old FC f/w style, convert to new...
2420 */
2421 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2422 facts->FWVersion.Word =
2423 ((oldv<<12) & 0xFF000000) |
2424 ((oldv<<8) & 0x000FFF00);
2425 } else
2426 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2427
2428 facts->ProductID = le16_to_cpu(facts->ProductID);
2429 facts->CurrentHostMfaHighAddr =
2430 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2431 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2432 facts->CurrentSenseBufferHighAddr =
2433 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2434 facts->CurReplyFrameSize =
2435 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002436 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
2438 /*
2439 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2440 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2441 * to 14 in MPI-1.01.0x.
2442 */
2443 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2444 facts->MsgVersion > 0x0100) {
2445 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2446 }
2447
2448 sz = facts->FWImageSize;
2449 if ( sz & 0x01 )
2450 sz += 1;
2451 if ( sz & 0x02 )
2452 sz += 2;
2453 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002454
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 if (!facts->RequestFrameSize) {
2456 /* Something is wrong! */
2457 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2458 ioc->name);
2459 return -55;
2460 }
2461
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002462 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 vv = ((63 / (sz * 4)) + 1) & 0x03;
2464 ioc->NB_for_64_byte_frame = vv;
2465 while ( sz )
2466 {
2467 shiftFactor++;
2468 sz = sz >> 1;
2469 }
2470 ioc->NBShiftFactor = shiftFactor;
2471 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2472 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002473
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2475 /*
2476 * Set values for this IOC's request & reply frame sizes,
2477 * and request & reply queue depths...
2478 */
2479 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2480 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2481 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2482 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2483
2484 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2485 ioc->name, ioc->reply_sz, ioc->reply_depth));
2486 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2487 ioc->name, ioc->req_sz, ioc->req_depth));
2488
2489 /* Get port facts! */
2490 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2491 return r;
2492 }
2493 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002494 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2496 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2497 RequestFrameSize)/sizeof(u32)));
2498 return -66;
2499 }
2500
2501 return 0;
2502}
2503
2504/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2505/*
2506 * GetPortFacts - Send PortFacts request to MPT adapter.
2507 * @ioc: Pointer to MPT_ADAPTER structure
2508 * @portnum: Port number
2509 * @sleepFlag: Specifies whether the process can sleep
2510 *
2511 * Returns 0 for success, non-zero for failure.
2512 */
2513static int
2514GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2515{
2516 PortFacts_t get_pfacts;
2517 PortFactsReply_t *pfacts;
2518 int ii;
2519 int req_sz;
2520 int reply_sz;
2521
2522 /* IOC *must* NOT be in RESET state! */
2523 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2524 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2525 ioc->name,
2526 ioc->last_state );
2527 return -4;
2528 }
2529
2530 pfacts = &ioc->pfacts[portnum];
2531
2532 /* Destination (reply area)... */
2533 reply_sz = sizeof(*pfacts);
2534 memset(pfacts, 0, reply_sz);
2535
2536 /* Request area (get_pfacts on the stack right now!) */
2537 req_sz = sizeof(get_pfacts);
2538 memset(&get_pfacts, 0, req_sz);
2539
2540 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2541 get_pfacts.PortNumber = portnum;
2542 /* Assert: All other get_pfacts fields are zero! */
2543
2544 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2545 ioc->name, portnum));
2546
2547 /* No non-zero fields in the get_pfacts request are greater than
2548 * 1 byte in size, so we can just fire it off as is.
2549 */
2550 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2551 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2552 if (ii != 0)
2553 return ii;
2554
2555 /* Did we get a valid reply? */
2556
2557 /* Now byte swap the necessary fields in the response. */
2558 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2559 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2560 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2561 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2562 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2563 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2564 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2565 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2566 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2567
2568 return 0;
2569}
2570
2571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2572/*
2573 * SendIocInit - Send IOCInit request to MPT adapter.
2574 * @ioc: Pointer to MPT_ADAPTER structure
2575 * @sleepFlag: Specifies whether the process can sleep
2576 *
2577 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2578 *
2579 * Returns 0 for success, non-zero for failure.
2580 */
2581static int
2582SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2583{
2584 IOCInit_t ioc_init;
2585 MPIDefaultReply_t init_reply;
2586 u32 state;
2587 int r;
2588 int count;
2589 int cntdn;
2590
2591 memset(&ioc_init, 0, sizeof(ioc_init));
2592 memset(&init_reply, 0, sizeof(init_reply));
2593
2594 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2595 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2596
2597 /* If we are in a recovery mode and we uploaded the FW image,
2598 * then this pointer is not NULL. Skip the upload a second time.
2599 * Set this flag if cached_fw set for either IOC.
2600 */
2601 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2602 ioc->upload_fw = 1;
2603 else
2604 ioc->upload_fw = 0;
2605 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2606 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2607
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002608 if(ioc->bus_type == SAS)
2609 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2610 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2612 else
2613 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002615 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2616 ioc->name, ioc->facts.MsgVersion));
2617 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2618 // set MsgVersion and HeaderVersion host driver was built with
2619 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2620 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002622 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2623 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2624 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2625 return -99;
2626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2628
2629 if (sizeof(dma_addr_t) == sizeof(u64)) {
2630 /* Save the upper 32-bits of the request
2631 * (reply) and sense buffers.
2632 */
2633 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2634 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2635 } else {
2636 /* Force 32-bit addressing */
2637 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2638 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2639 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2642 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002643 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2644 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
2646 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2647 ioc->name, &ioc_init));
2648
2649 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2650 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002651 if (r != 0) {
2652 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
2656 /* No need to byte swap the multibyte fields in the reply
2657 * since we don't even look at it's contents.
2658 */
2659
2660 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2661 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002662
2663 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2664 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667
2668 /* YIKES! SUPER IMPORTANT!!!
2669 * Poll IocState until _OPERATIONAL while IOC is doing
2670 * LoopInit and TargetDiscovery!
2671 */
2672 count = 0;
2673 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2674 state = mpt_GetIocState(ioc, 1);
2675 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2676 if (sleepFlag == CAN_SLEEP) {
2677 msleep_interruptible(1);
2678 } else {
2679 mdelay(1);
2680 }
2681
2682 if (!cntdn) {
2683 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2684 ioc->name, (int)((count+5)/HZ));
2685 return -9;
2686 }
2687
2688 state = mpt_GetIocState(ioc, 1);
2689 count++;
2690 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002691 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 ioc->name, count));
2693
2694 return r;
2695}
2696
2697/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2698/*
2699 * SendPortEnable - Send PortEnable request to MPT adapter port.
2700 * @ioc: Pointer to MPT_ADAPTER structure
2701 * @portnum: Port number to enable
2702 * @sleepFlag: Specifies whether the process can sleep
2703 *
2704 * Send PortEnable to bring IOC to OPERATIONAL state.
2705 *
2706 * Returns 0 for success, non-zero for failure.
2707 */
2708static int
2709SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2710{
2711 PortEnable_t port_enable;
2712 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002713 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 int req_sz;
2715 int reply_sz;
2716
2717 /* Destination... */
2718 reply_sz = sizeof(MPIDefaultReply_t);
2719 memset(&reply_buf, 0, reply_sz);
2720
2721 req_sz = sizeof(PortEnable_t);
2722 memset(&port_enable, 0, req_sz);
2723
2724 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2725 port_enable.PortNumber = portnum;
2726/* port_enable.ChainOffset = 0; */
2727/* port_enable.MsgFlags = 0; */
2728/* port_enable.MsgContext = 0; */
2729
2730 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2731 ioc->name, portnum, &port_enable));
2732
2733 /* RAID FW may take a long time to enable
2734 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002735 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2736 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2737 (ioc->bus_type == SAS)) {
2738 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2739 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2740 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002741 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002742 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2743 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2744 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002746 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747}
2748
2749/*
2750 * ioc: Pointer to MPT_ADAPTER structure
2751 * size - total FW bytes
2752 */
2753void
2754mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2755{
2756 if (ioc->cached_fw)
2757 return; /* use already allocated memory */
2758 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2759 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2760 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2761 } else {
2762 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2763 ioc->alloc_total += size;
2764 }
2765}
2766/*
2767 * If alt_img is NULL, delete from ioc structure.
2768 * Else, delete a secondary image in same format.
2769 */
2770void
2771mpt_free_fw_memory(MPT_ADAPTER *ioc)
2772{
2773 int sz;
2774
2775 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002776 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2778 pci_free_consistent(ioc->pcidev, sz,
2779 ioc->cached_fw, ioc->cached_fw_dma);
2780 ioc->cached_fw = NULL;
2781
2782 return;
2783}
2784
2785
2786/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2787/*
2788 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2789 * @ioc: Pointer to MPT_ADAPTER structure
2790 * @sleepFlag: Specifies whether the process can sleep
2791 *
2792 * Returns 0 for success, >0 for handshake failure
2793 * <0 for fw upload failure.
2794 *
2795 * Remark: If bound IOC and a successful FWUpload was performed
2796 * on the bound IOC, the second image is discarded
2797 * and memory is free'd. Both channels must upload to prevent
2798 * IOC from running in degraded mode.
2799 */
2800static int
2801mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2802{
2803 u8 request[ioc->req_sz];
2804 u8 reply[sizeof(FWUploadReply_t)];
2805 FWUpload_t *prequest;
2806 FWUploadReply_t *preply;
2807 FWUploadTCSGE_t *ptcsge;
2808 int sgeoffset;
2809 u32 flagsLength;
2810 int ii, sz, reply_sz;
2811 int cmdStatus;
2812
2813 /* If the image size is 0, we are done.
2814 */
2815 if ((sz = ioc->facts.FWImageSize) == 0)
2816 return 0;
2817
2818 mpt_alloc_fw_memory(ioc, sz);
2819
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002820 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002822
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 if (ioc->cached_fw == NULL) {
2824 /* Major Failure.
2825 */
2826 return -ENOMEM;
2827 }
2828
2829 prequest = (FWUpload_t *)&request;
2830 preply = (FWUploadReply_t *)&reply;
2831
2832 /* Destination... */
2833 memset(prequest, 0, ioc->req_sz);
2834
2835 reply_sz = sizeof(reply);
2836 memset(preply, 0, reply_sz);
2837
2838 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2839 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2840
2841 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2842 ptcsge->DetailsLength = 12;
2843 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2844 ptcsge->ImageSize = cpu_to_le32(sz);
2845
2846 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2847
2848 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2849 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2850
2851 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002852 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 prequest, sgeoffset));
2854 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2855
2856 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2857 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2858
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002859 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860
2861 cmdStatus = -EFAULT;
2862 if (ii == 0) {
2863 /* Handshake transfer was complete and successful.
2864 * Check the Reply Frame.
2865 */
2866 int status, transfer_sz;
2867 status = le16_to_cpu(preply->IOCStatus);
2868 if (status == MPI_IOCSTATUS_SUCCESS) {
2869 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2870 if (transfer_sz == sz)
2871 cmdStatus = 0;
2872 }
2873 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002874 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 ioc->name, cmdStatus));
2876
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002877
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 if (cmdStatus) {
2879
2880 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2881 ioc->name));
2882 mpt_free_fw_memory(ioc);
2883 }
2884
2885 return cmdStatus;
2886}
2887
2888/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2889/*
2890 * mpt_downloadboot - DownloadBoot code
2891 * @ioc: Pointer to MPT_ADAPTER structure
2892 * @flag: Specify which part of IOC memory is to be uploaded.
2893 * @sleepFlag: Specifies whether the process can sleep
2894 *
2895 * FwDownloadBoot requires Programmed IO access.
2896 *
2897 * Returns 0 for success
2898 * -1 FW Image size is 0
2899 * -2 No valid cached_fw Pointer
2900 * <0 for fw upload failure.
2901 */
2902static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002903mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 MpiExtImageHeader_t *pExtImage;
2906 u32 fwSize;
2907 u32 diag0val;
2908 int count;
2909 u32 *ptrFw;
2910 u32 diagRwData;
2911 u32 nextImage;
2912 u32 load_addr;
2913 u32 ioc_state=0;
2914
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002915 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2916 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002917
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2919 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2920 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2921 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2922 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2923 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2924
2925 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2926
2927 /* wait 1 msec */
2928 if (sleepFlag == CAN_SLEEP) {
2929 msleep_interruptible(1);
2930 } else {
2931 mdelay (1);
2932 }
2933
2934 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2935 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2936
2937 for (count = 0; count < 30; count ++) {
2938 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2939 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2940 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2941 ioc->name, count));
2942 break;
2943 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002944 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002946 msleep_interruptible (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002948 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 }
2950 }
2951
2952 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002953 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2954 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 ioc->name, diag0val));
2956 return -3;
2957 }
2958
2959 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2960 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2961 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2962 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2963 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2964 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2965
2966 /* Set the DiagRwEn and Disable ARM bits */
2967 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2968
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 fwSize = (pFwHeader->ImageSize + 3)/4;
2970 ptrFw = (u32 *) pFwHeader;
2971
2972 /* Write the LoadStartAddress to the DiagRw Address Register
2973 * using Programmed IO
2974 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002975 if (ioc->errata_flag_1064)
2976 pci_enable_io_access(ioc->pcidev);
2977
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2979 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2980 ioc->name, pFwHeader->LoadStartAddress));
2981
2982 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2983 ioc->name, fwSize*4, ptrFw));
2984 while (fwSize--) {
2985 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2986 }
2987
2988 nextImage = pFwHeader->NextImageHeaderOffset;
2989 while (nextImage) {
2990 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
2991
2992 load_addr = pExtImage->LoadStartAddress;
2993
2994 fwSize = (pExtImage->ImageSize + 3) >> 2;
2995 ptrFw = (u32 *)pExtImage;
2996
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002997 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
2998 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3000
3001 while (fwSize--) {
3002 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3003 }
3004 nextImage = pExtImage->NextImageHeaderOffset;
3005 }
3006
3007 /* Write the IopResetVectorRegAddr */
3008 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3009 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3010
3011 /* Write the IopResetVectorValue */
3012 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3013 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3014
3015 /* Clear the internal flash bad bit - autoincrementing register,
3016 * so must do two writes.
3017 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003018 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003019 /*
3020 * 1030 and 1035 H/W errata, workaround to access
3021 * the ClearFlashBadSignatureBit
3022 */
3023 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3024 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3025 diagRwData |= 0x40000000;
3026 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3027 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3028
3029 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3030 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3031 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3032 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3033
3034 /* wait 1 msec */
3035 if (sleepFlag == CAN_SLEEP) {
3036 msleep_interruptible (1);
3037 } else {
3038 mdelay (1);
3039 }
3040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003042 if (ioc->errata_flag_1064)
3043 pci_disable_io_access(ioc->pcidev);
3044
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003046 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3047 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003049 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3051 ioc->name, diag0val));
3052 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3053
3054 /* Write 0xFF to reset the sequencer */
3055 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3056
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003057 if (ioc->bus_type == SAS) {
3058 ioc_state = mpt_GetIocState(ioc, 0);
3059 if ( (GetIocFacts(ioc, sleepFlag,
3060 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3061 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3062 ioc->name, ioc_state));
3063 return -EFAULT;
3064 }
3065 }
3066
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 for (count=0; count<HZ*20; count++) {
3068 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3069 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3070 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003071 if (ioc->bus_type == SAS) {
3072 return 0;
3073 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3075 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3076 ioc->name));
3077 return -EFAULT;
3078 }
3079 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3080 ioc->name));
3081 return 0;
3082 }
3083 if (sleepFlag == CAN_SLEEP) {
3084 msleep_interruptible (10);
3085 } else {
3086 mdelay (10);
3087 }
3088 }
3089 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3090 ioc->name, ioc_state));
3091 return -EFAULT;
3092}
3093
3094/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3095/*
3096 * KickStart - Perform hard reset of MPT adapter.
3097 * @ioc: Pointer to MPT_ADAPTER structure
3098 * @force: Force hard reset
3099 * @sleepFlag: Specifies whether the process can sleep
3100 *
3101 * This routine places MPT adapter in diagnostic mode via the
3102 * WriteSequence register, and then performs a hard reset of adapter
3103 * via the Diagnostic register.
3104 *
3105 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3106 * or NO_SLEEP (interrupt thread, use mdelay)
3107 * force - 1 if doorbell active, board fault state
3108 * board operational, IOC_RECOVERY or
3109 * IOC_BRINGUP and there is an alt_ioc.
3110 * 0 else
3111 *
3112 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003113 * 1 - hard reset, READY
3114 * 0 - no reset due to History bit, READY
3115 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 * OR reset but failed to come READY
3117 * -2 - no reset, could not enter DIAG mode
3118 * -3 - reset but bad FW bit
3119 */
3120static int
3121KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3122{
3123 int hard_reset_done = 0;
3124 u32 ioc_state=0;
3125 int cnt,cntdn;
3126
3127 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003128 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 /* Always issue a Msg Unit Reset first. This will clear some
3130 * SCSI bus hang conditions.
3131 */
3132 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3133
3134 if (sleepFlag == CAN_SLEEP) {
3135 msleep_interruptible (1000);
3136 } else {
3137 mdelay (1000);
3138 }
3139 }
3140
3141 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3142 if (hard_reset_done < 0)
3143 return hard_reset_done;
3144
3145 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3146 ioc->name));
3147
3148 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3149 for (cnt=0; cnt<cntdn; cnt++) {
3150 ioc_state = mpt_GetIocState(ioc, 1);
3151 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3152 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3153 ioc->name, cnt));
3154 return hard_reset_done;
3155 }
3156 if (sleepFlag == CAN_SLEEP) {
3157 msleep_interruptible (10);
3158 } else {
3159 mdelay (10);
3160 }
3161 }
3162
3163 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3164 ioc->name, ioc_state);
3165 return -1;
3166}
3167
3168/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3169/*
3170 * mpt_diag_reset - Perform hard reset of the adapter.
3171 * @ioc: Pointer to MPT_ADAPTER structure
3172 * @ignore: Set if to honor and clear to ignore
3173 * the reset history bit
3174 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3175 * else set to NO_SLEEP (use mdelay instead)
3176 *
3177 * This routine places the adapter in diagnostic mode via the
3178 * WriteSequence register and then performs a hard reset of adapter
3179 * via the Diagnostic register. Adapter should be in ready state
3180 * upon successful completion.
3181 *
3182 * Returns: 1 hard reset successful
3183 * 0 no reset performed because reset history bit set
3184 * -2 enabling diagnostic mode failed
3185 * -3 diagnostic reset failed
3186 */
3187static int
3188mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3189{
3190 u32 diag0val;
3191 u32 doorbell;
3192 int hard_reset_done = 0;
3193 int count = 0;
3194#ifdef MPT_DEBUG
3195 u32 diag1val = 0;
3196#endif
3197
3198 /* Clear any existing interrupts */
3199 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3200
3201 /* Use "Diagnostic reset" method! (only thing available!) */
3202 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3203
3204#ifdef MPT_DEBUG
3205 if (ioc->alt_ioc)
3206 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3207 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3208 ioc->name, diag0val, diag1val));
3209#endif
3210
3211 /* Do the reset if we are told to ignore the reset history
3212 * or if the reset history is 0
3213 */
3214 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3215 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3216 /* Write magic sequence to WriteSequence register
3217 * Loop until in diagnostic mode
3218 */
3219 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3220 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3221 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3222 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3223 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3224 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3225
3226 /* wait 100 msec */
3227 if (sleepFlag == CAN_SLEEP) {
3228 msleep_interruptible (100);
3229 } else {
3230 mdelay (100);
3231 }
3232
3233 count++;
3234 if (count > 20) {
3235 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3236 ioc->name, diag0val);
3237 return -2;
3238
3239 }
3240
3241 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3242
3243 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3244 ioc->name, diag0val));
3245 }
3246
3247#ifdef MPT_DEBUG
3248 if (ioc->alt_ioc)
3249 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3250 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3251 ioc->name, diag0val, diag1val));
3252#endif
3253 /*
3254 * Disable the ARM (Bug fix)
3255 *
3256 */
3257 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003258 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259
3260 /*
3261 * Now hit the reset bit in the Diagnostic register
3262 * (THE BIG HAMMER!) (Clears DRWE bit).
3263 */
3264 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3265 hard_reset_done = 1;
3266 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3267 ioc->name));
3268
3269 /*
3270 * Call each currently registered protocol IOC reset handler
3271 * with pre-reset indication.
3272 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3273 * MptResetHandlers[] registered yet.
3274 */
3275 {
3276 int ii;
3277 int r = 0;
3278
3279 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3280 if (MptResetHandlers[ii]) {
3281 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3282 ioc->name, ii));
3283 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
3284 if (ioc->alt_ioc) {
3285 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3286 ioc->name, ioc->alt_ioc->name, ii));
3287 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
3288 }
3289 }
3290 }
3291 /* FIXME? Examine results here? */
3292 }
3293
3294 if (ioc->cached_fw) {
3295 /* If the DownloadBoot operation fails, the
3296 * IOC will be left unusable. This is a fatal error
3297 * case. _diag_reset will return < 0
3298 */
3299 for (count = 0; count < 30; count ++) {
3300 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3301 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3302 break;
3303 }
3304
3305 /* wait 1 sec */
3306 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003307 msleep_interruptible (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 } else {
3309 mdelay (1000);
3310 }
3311 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003312 if ((count = mpt_downloadboot(ioc,
3313 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 printk(KERN_WARNING MYNAM
3315 ": firmware downloadboot failure (%d)!\n", count);
3316 }
3317
3318 } else {
3319 /* Wait for FW to reload and for board
3320 * to go to the READY state.
3321 * Maximum wait is 60 seconds.
3322 * If fail, no error will check again
3323 * with calling program.
3324 */
3325 for (count = 0; count < 60; count ++) {
3326 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3327 doorbell &= MPI_IOC_STATE_MASK;
3328
3329 if (doorbell == MPI_IOC_STATE_READY) {
3330 break;
3331 }
3332
3333 /* wait 1 sec */
3334 if (sleepFlag == CAN_SLEEP) {
3335 msleep_interruptible (1000);
3336 } else {
3337 mdelay (1000);
3338 }
3339 }
3340 }
3341 }
3342
3343 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3344#ifdef MPT_DEBUG
3345 if (ioc->alt_ioc)
3346 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3347 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3348 ioc->name, diag0val, diag1val));
3349#endif
3350
3351 /* Clear RESET_HISTORY bit! Place board in the
3352 * diagnostic mode to update the diag register.
3353 */
3354 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3355 count = 0;
3356 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3357 /* Write magic sequence to WriteSequence register
3358 * Loop until in diagnostic mode
3359 */
3360 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3361 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3362 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3363 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3364 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3365 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3366
3367 /* wait 100 msec */
3368 if (sleepFlag == CAN_SLEEP) {
3369 msleep_interruptible (100);
3370 } else {
3371 mdelay (100);
3372 }
3373
3374 count++;
3375 if (count > 20) {
3376 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3377 ioc->name, diag0val);
3378 break;
3379 }
3380 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3381 }
3382 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3383 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3384 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3385 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3386 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3387 ioc->name);
3388 }
3389
3390 /* Disable Diagnostic Mode
3391 */
3392 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3393
3394 /* Check FW reload status flags.
3395 */
3396 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3397 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3398 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3399 ioc->name, diag0val);
3400 return -3;
3401 }
3402
3403#ifdef MPT_DEBUG
3404 if (ioc->alt_ioc)
3405 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3406 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3407 ioc->name, diag0val, diag1val));
3408#endif
3409
3410 /*
3411 * Reset flag that says we've enabled event notification
3412 */
3413 ioc->facts.EventState = 0;
3414
3415 if (ioc->alt_ioc)
3416 ioc->alt_ioc->facts.EventState = 0;
3417
3418 return hard_reset_done;
3419}
3420
3421/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3422/*
3423 * SendIocReset - Send IOCReset request to MPT adapter.
3424 * @ioc: Pointer to MPT_ADAPTER structure
3425 * @reset_type: reset type, expected values are
3426 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3427 *
3428 * Send IOCReset request to the MPT adapter.
3429 *
3430 * Returns 0 for success, non-zero for failure.
3431 */
3432static int
3433SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3434{
3435 int r;
3436 u32 state;
3437 int cntdn, count;
3438
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003439 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 ioc->name, reset_type));
3441 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3442 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3443 return r;
3444
3445 /* FW ACK'd request, wait for READY state
3446 */
3447 count = 0;
3448 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3449
3450 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3451 cntdn--;
3452 count++;
3453 if (!cntdn) {
3454 if (sleepFlag != CAN_SLEEP)
3455 count *= 10;
3456
3457 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3458 ioc->name, (int)((count+5)/HZ));
3459 return -ETIME;
3460 }
3461
3462 if (sleepFlag == CAN_SLEEP) {
3463 msleep_interruptible(1);
3464 } else {
3465 mdelay (1); /* 1 msec delay */
3466 }
3467 }
3468
3469 /* TODO!
3470 * Cleanup all event stuff for this IOC; re-issue EventNotification
3471 * request if needed.
3472 */
3473 if (ioc->facts.Function)
3474 ioc->facts.EventState = 0;
3475
3476 return 0;
3477}
3478
3479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3480/*
3481 * initChainBuffers - Allocate memory for and initialize
3482 * chain buffers, chain buffer control arrays and spinlock.
3483 * @hd: Pointer to MPT_SCSI_HOST structure
3484 * @init: If set, initialize the spin lock.
3485 */
3486static int
3487initChainBuffers(MPT_ADAPTER *ioc)
3488{
3489 u8 *mem;
3490 int sz, ii, num_chain;
3491 int scale, num_sge, numSGE;
3492
3493 /* ReqToChain size must equal the req_depth
3494 * index = req_idx
3495 */
3496 if (ioc->ReqToChain == NULL) {
3497 sz = ioc->req_depth * sizeof(int);
3498 mem = kmalloc(sz, GFP_ATOMIC);
3499 if (mem == NULL)
3500 return -1;
3501
3502 ioc->ReqToChain = (int *) mem;
3503 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3504 ioc->name, mem, sz));
3505 mem = kmalloc(sz, GFP_ATOMIC);
3506 if (mem == NULL)
3507 return -1;
3508
3509 ioc->RequestNB = (int *) mem;
3510 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3511 ioc->name, mem, sz));
3512 }
3513 for (ii = 0; ii < ioc->req_depth; ii++) {
3514 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3515 }
3516
3517 /* ChainToChain size must equal the total number
3518 * of chain buffers to be allocated.
3519 * index = chain_idx
3520 *
3521 * Calculate the number of chain buffers needed(plus 1) per I/O
3522 * then multiply the the maximum number of simultaneous cmds
3523 *
3524 * num_sge = num sge in request frame + last chain buffer
3525 * scale = num sge per chain buffer if no chain element
3526 */
3527 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3528 if (sizeof(dma_addr_t) == sizeof(u64))
3529 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3530 else
3531 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3532
3533 if (sizeof(dma_addr_t) == sizeof(u64)) {
3534 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3535 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3536 } else {
3537 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3538 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3539 }
3540 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3541 ioc->name, num_sge, numSGE));
3542
3543 if ( numSGE > MPT_SCSI_SG_DEPTH )
3544 numSGE = MPT_SCSI_SG_DEPTH;
3545
3546 num_chain = 1;
3547 while (numSGE - num_sge > 0) {
3548 num_chain++;
3549 num_sge += (scale - 1);
3550 }
3551 num_chain++;
3552
3553 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3554 ioc->name, numSGE, num_sge, num_chain));
3555
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003556 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 num_chain *= MPT_SCSI_CAN_QUEUE;
3558 else
3559 num_chain *= MPT_FC_CAN_QUEUE;
3560
3561 ioc->num_chain = num_chain;
3562
3563 sz = num_chain * sizeof(int);
3564 if (ioc->ChainToChain == NULL) {
3565 mem = kmalloc(sz, GFP_ATOMIC);
3566 if (mem == NULL)
3567 return -1;
3568
3569 ioc->ChainToChain = (int *) mem;
3570 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3571 ioc->name, mem, sz));
3572 } else {
3573 mem = (u8 *) ioc->ChainToChain;
3574 }
3575 memset(mem, 0xFF, sz);
3576 return num_chain;
3577}
3578
3579/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3580/*
3581 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3582 * @ioc: Pointer to MPT_ADAPTER structure
3583 *
3584 * This routine allocates memory for the MPT reply and request frame
3585 * pools (if necessary), and primes the IOC reply FIFO with
3586 * reply frames.
3587 *
3588 * Returns 0 for success, non-zero for failure.
3589 */
3590static int
3591PrimeIocFifos(MPT_ADAPTER *ioc)
3592{
3593 MPT_FRAME_HDR *mf;
3594 unsigned long flags;
3595 dma_addr_t alloc_dma;
3596 u8 *mem;
3597 int i, reply_sz, sz, total_size, num_chain;
3598
3599 /* Prime reply FIFO... */
3600
3601 if (ioc->reply_frames == NULL) {
3602 if ( (num_chain = initChainBuffers(ioc)) < 0)
3603 return -1;
3604
3605 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3606 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3607 ioc->name, ioc->reply_sz, ioc->reply_depth));
3608 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3609 ioc->name, reply_sz, reply_sz));
3610
3611 sz = (ioc->req_sz * ioc->req_depth);
3612 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3613 ioc->name, ioc->req_sz, ioc->req_depth));
3614 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3615 ioc->name, sz, sz));
3616 total_size += sz;
3617
3618 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3619 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3620 ioc->name, ioc->req_sz, num_chain));
3621 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3622 ioc->name, sz, sz, num_chain));
3623
3624 total_size += sz;
3625 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3626 if (mem == NULL) {
3627 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3628 ioc->name);
3629 goto out_fail;
3630 }
3631
3632 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3633 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3634
3635 memset(mem, 0, total_size);
3636 ioc->alloc_total += total_size;
3637 ioc->alloc = mem;
3638 ioc->alloc_dma = alloc_dma;
3639 ioc->alloc_sz = total_size;
3640 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3641 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3642
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003643 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3644 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3645
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 alloc_dma += reply_sz;
3647 mem += reply_sz;
3648
3649 /* Request FIFO - WE manage this! */
3650
3651 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3652 ioc->req_frames_dma = alloc_dma;
3653
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003654 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 ioc->name, mem, (void *)(ulong)alloc_dma));
3656
3657 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3658
3659#if defined(CONFIG_MTRR) && 0
3660 /*
3661 * Enable Write Combining MTRR for IOC's memory region.
3662 * (at least as much as we can; "size and base must be
3663 * multiples of 4 kiB"
3664 */
3665 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3666 sz,
3667 MTRR_TYPE_WRCOMB, 1);
3668 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3669 ioc->name, ioc->req_frames_dma, sz));
3670#endif
3671
3672 for (i = 0; i < ioc->req_depth; i++) {
3673 alloc_dma += ioc->req_sz;
3674 mem += ioc->req_sz;
3675 }
3676
3677 ioc->ChainBuffer = mem;
3678 ioc->ChainBufferDMA = alloc_dma;
3679
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003680 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3682
3683 /* Initialize the free chain Q.
3684 */
3685
3686 INIT_LIST_HEAD(&ioc->FreeChainQ);
3687
3688 /* Post the chain buffers to the FreeChainQ.
3689 */
3690 mem = (u8 *)ioc->ChainBuffer;
3691 for (i=0; i < num_chain; i++) {
3692 mf = (MPT_FRAME_HDR *) mem;
3693 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3694 mem += ioc->req_sz;
3695 }
3696
3697 /* Initialize Request frames linked list
3698 */
3699 alloc_dma = ioc->req_frames_dma;
3700 mem = (u8 *) ioc->req_frames;
3701
3702 spin_lock_irqsave(&ioc->FreeQlock, flags);
3703 INIT_LIST_HEAD(&ioc->FreeQ);
3704 for (i = 0; i < ioc->req_depth; i++) {
3705 mf = (MPT_FRAME_HDR *) mem;
3706
3707 /* Queue REQUESTs *internally*! */
3708 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3709
3710 mem += ioc->req_sz;
3711 }
3712 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3713
3714 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3715 ioc->sense_buf_pool =
3716 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3717 if (ioc->sense_buf_pool == NULL) {
3718 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3719 ioc->name);
3720 goto out_fail;
3721 }
3722
3723 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3724 ioc->alloc_total += sz;
3725 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3726 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3727
3728 }
3729
3730 /* Post Reply frames to FIFO
3731 */
3732 alloc_dma = ioc->alloc_dma;
3733 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3734 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3735
3736 for (i = 0; i < ioc->reply_depth; i++) {
3737 /* Write each address to the IOC! */
3738 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3739 alloc_dma += ioc->reply_sz;
3740 }
3741
3742 return 0;
3743
3744out_fail:
3745 if (ioc->alloc != NULL) {
3746 sz = ioc->alloc_sz;
3747 pci_free_consistent(ioc->pcidev,
3748 sz,
3749 ioc->alloc, ioc->alloc_dma);
3750 ioc->reply_frames = NULL;
3751 ioc->req_frames = NULL;
3752 ioc->alloc_total -= sz;
3753 }
3754 if (ioc->sense_buf_pool != NULL) {
3755 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3756 pci_free_consistent(ioc->pcidev,
3757 sz,
3758 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3759 ioc->sense_buf_pool = NULL;
3760 }
3761 return -1;
3762}
3763
3764/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3765/**
3766 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3767 * from IOC via doorbell handshake method.
3768 * @ioc: Pointer to MPT_ADAPTER structure
3769 * @reqBytes: Size of the request in bytes
3770 * @req: Pointer to MPT request frame
3771 * @replyBytes: Expected size of the reply in bytes
3772 * @u16reply: Pointer to area where reply should be written
3773 * @maxwait: Max wait time for a reply (in seconds)
3774 * @sleepFlag: Specifies whether the process can sleep
3775 *
3776 * NOTES: It is the callers responsibility to byte-swap fields in the
3777 * request which are greater than 1 byte in size. It is also the
3778 * callers responsibility to byte-swap response fields which are
3779 * greater than 1 byte in size.
3780 *
3781 * Returns 0 for success, non-zero for failure.
3782 */
3783static int
3784mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003785 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786{
3787 MPIDefaultReply_t *mptReply;
3788 int failcnt = 0;
3789 int t;
3790
3791 /*
3792 * Get ready to cache a handshake reply
3793 */
3794 ioc->hs_reply_idx = 0;
3795 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3796 mptReply->MsgLength = 0;
3797
3798 /*
3799 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3800 * then tell IOC that we want to handshake a request of N words.
3801 * (WRITE u32val to Doorbell reg).
3802 */
3803 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3804 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3805 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3806 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3807
3808 /*
3809 * Wait for IOC's doorbell handshake int
3810 */
3811 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3812 failcnt++;
3813
3814 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3815 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3816
3817 /* Read doorbell and check for active bit */
3818 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3819 return -1;
3820
3821 /*
3822 * Clear doorbell int (WRITE 0 to IntStatus reg),
3823 * then wait for IOC to ACKnowledge that it's ready for
3824 * our handshake request.
3825 */
3826 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3827 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3828 failcnt++;
3829
3830 if (!failcnt) {
3831 int ii;
3832 u8 *req_as_bytes = (u8 *) req;
3833
3834 /*
3835 * Stuff request words via doorbell handshake,
3836 * with ACK from IOC for each.
3837 */
3838 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3839 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3840 (req_as_bytes[(ii*4) + 1] << 8) |
3841 (req_as_bytes[(ii*4) + 2] << 16) |
3842 (req_as_bytes[(ii*4) + 3] << 24));
3843
3844 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3845 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3846 failcnt++;
3847 }
3848
3849 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3850 DBG_DUMP_REQUEST_FRAME_HDR(req)
3851
3852 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3853 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3854
3855 /*
3856 * Wait for completion of doorbell handshake reply from the IOC
3857 */
3858 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3859 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003860
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3862 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3863
3864 /*
3865 * Copy out the cached reply...
3866 */
3867 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3868 u16reply[ii] = ioc->hs_reply[ii];
3869 } else {
3870 return -99;
3871 }
3872
3873 return -failcnt;
3874}
3875
3876/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3877/*
3878 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3879 * in it's IntStatus register.
3880 * @ioc: Pointer to MPT_ADAPTER structure
3881 * @howlong: How long to wait (in seconds)
3882 * @sleepFlag: Specifies whether the process can sleep
3883 *
3884 * This routine waits (up to ~2 seconds max) for IOC doorbell
3885 * handshake ACKnowledge.
3886 *
3887 * Returns a negative value on failure, else wait loop count.
3888 */
3889static int
3890WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3891{
3892 int cntdn;
3893 int count = 0;
3894 u32 intstat=0;
3895
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003896 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897
3898 if (sleepFlag == CAN_SLEEP) {
3899 while (--cntdn) {
3900 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3901 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3902 break;
3903 msleep_interruptible (1);
3904 count++;
3905 }
3906 } else {
3907 while (--cntdn) {
3908 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3909 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3910 break;
3911 mdelay (1);
3912 count++;
3913 }
3914 }
3915
3916 if (cntdn) {
3917 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3918 ioc->name, count));
3919 return count;
3920 }
3921
3922 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3923 ioc->name, count, intstat);
3924 return -1;
3925}
3926
3927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3928/*
3929 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3930 * in it's IntStatus register.
3931 * @ioc: Pointer to MPT_ADAPTER structure
3932 * @howlong: How long to wait (in seconds)
3933 * @sleepFlag: Specifies whether the process can sleep
3934 *
3935 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3936 *
3937 * Returns a negative value on failure, else wait loop count.
3938 */
3939static int
3940WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3941{
3942 int cntdn;
3943 int count = 0;
3944 u32 intstat=0;
3945
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003946 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 if (sleepFlag == CAN_SLEEP) {
3948 while (--cntdn) {
3949 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3950 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3951 break;
3952 msleep_interruptible(1);
3953 count++;
3954 }
3955 } else {
3956 while (--cntdn) {
3957 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3958 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3959 break;
3960 mdelay(1);
3961 count++;
3962 }
3963 }
3964
3965 if (cntdn) {
3966 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3967 ioc->name, count, howlong));
3968 return count;
3969 }
3970
3971 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3972 ioc->name, count, intstat);
3973 return -1;
3974}
3975
3976/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3977/*
3978 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3979 * @ioc: Pointer to MPT_ADAPTER structure
3980 * @howlong: How long to wait (in seconds)
3981 * @sleepFlag: Specifies whether the process can sleep
3982 *
3983 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3984 * Reply is cached to IOC private area large enough to hold a maximum
3985 * of 128 bytes of reply data.
3986 *
3987 * Returns a negative value on failure, else size of reply in WORDS.
3988 */
3989static int
3990WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3991{
3992 int u16cnt = 0;
3993 int failcnt = 0;
3994 int t;
3995 u16 *hs_reply = ioc->hs_reply;
3996 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3997 u16 hword;
3998
3999 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4000
4001 /*
4002 * Get first two u16's so we can look at IOC's intended reply MsgLength
4003 */
4004 u16cnt=0;
4005 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4006 failcnt++;
4007 } else {
4008 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4009 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4010 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4011 failcnt++;
4012 else {
4013 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4014 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4015 }
4016 }
4017
4018 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004019 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4021
4022 /*
4023 * If no error (and IOC said MsgLength is > 0), piece together
4024 * reply 16 bits at a time.
4025 */
4026 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4027 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4028 failcnt++;
4029 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4030 /* don't overflow our IOC hs_reply[] buffer! */
4031 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4032 hs_reply[u16cnt] = hword;
4033 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4034 }
4035
4036 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4037 failcnt++;
4038 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4039
4040 if (failcnt) {
4041 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4042 ioc->name);
4043 return -failcnt;
4044 }
4045#if 0
4046 else if (u16cnt != (2 * mptReply->MsgLength)) {
4047 return -101;
4048 }
4049 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4050 return -102;
4051 }
4052#endif
4053
4054 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4055 DBG_DUMP_REPLY_FRAME(mptReply)
4056
4057 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4058 ioc->name, t, u16cnt/2));
4059 return u16cnt/2;
4060}
4061
4062/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4063/*
4064 * GetLanConfigPages - Fetch LANConfig pages.
4065 * @ioc: Pointer to MPT_ADAPTER structure
4066 *
4067 * Return: 0 for success
4068 * -ENOMEM if no memory available
4069 * -EPERM if not allowed due to ISR context
4070 * -EAGAIN if no msg frames currently available
4071 * -EFAULT for non-successful reply or no reply (timeout)
4072 */
4073static int
4074GetLanConfigPages(MPT_ADAPTER *ioc)
4075{
4076 ConfigPageHeader_t hdr;
4077 CONFIGPARMS cfg;
4078 LANPage0_t *ppage0_alloc;
4079 dma_addr_t page0_dma;
4080 LANPage1_t *ppage1_alloc;
4081 dma_addr_t page1_dma;
4082 int rc = 0;
4083 int data_sz;
4084 int copy_sz;
4085
4086 /* Get LAN Page 0 header */
4087 hdr.PageVersion = 0;
4088 hdr.PageLength = 0;
4089 hdr.PageNumber = 0;
4090 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004091 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 cfg.physAddr = -1;
4093 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4094 cfg.dir = 0;
4095 cfg.pageAddr = 0;
4096 cfg.timeout = 0;
4097
4098 if ((rc = mpt_config(ioc, &cfg)) != 0)
4099 return rc;
4100
4101 if (hdr.PageLength > 0) {
4102 data_sz = hdr.PageLength * 4;
4103 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4104 rc = -ENOMEM;
4105 if (ppage0_alloc) {
4106 memset((u8 *)ppage0_alloc, 0, data_sz);
4107 cfg.physAddr = page0_dma;
4108 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4109
4110 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4111 /* save the data */
4112 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4113 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4114
4115 }
4116
4117 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4118
4119 /* FIXME!
4120 * Normalize endianness of structure data,
4121 * by byte-swapping all > 1 byte fields!
4122 */
4123
4124 }
4125
4126 if (rc)
4127 return rc;
4128 }
4129
4130 /* Get LAN Page 1 header */
4131 hdr.PageVersion = 0;
4132 hdr.PageLength = 0;
4133 hdr.PageNumber = 1;
4134 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004135 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 cfg.physAddr = -1;
4137 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4138 cfg.dir = 0;
4139 cfg.pageAddr = 0;
4140
4141 if ((rc = mpt_config(ioc, &cfg)) != 0)
4142 return rc;
4143
4144 if (hdr.PageLength == 0)
4145 return 0;
4146
4147 data_sz = hdr.PageLength * 4;
4148 rc = -ENOMEM;
4149 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4150 if (ppage1_alloc) {
4151 memset((u8 *)ppage1_alloc, 0, data_sz);
4152 cfg.physAddr = page1_dma;
4153 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4154
4155 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4156 /* save the data */
4157 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4158 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4159 }
4160
4161 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4162
4163 /* FIXME!
4164 * Normalize endianness of structure data,
4165 * by byte-swapping all > 1 byte fields!
4166 */
4167
4168 }
4169
4170 return rc;
4171}
4172
4173/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4174/*
Michael Reed05e8ec12006-01-13 14:31:54 -06004175 * mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 * @ioc: Pointer to MPT_ADAPTER structure
4177 * @portnum: IOC Port number
4178 *
4179 * Return: 0 for success
4180 * -ENOMEM if no memory available
4181 * -EPERM if not allowed due to ISR context
4182 * -EAGAIN if no msg frames currently available
4183 * -EFAULT for non-successful reply or no reply (timeout)
4184 */
Michael Reed05e8ec12006-01-13 14:31:54 -06004185int
4186mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187{
4188 ConfigPageHeader_t hdr;
4189 CONFIGPARMS cfg;
4190 FCPortPage0_t *ppage0_alloc;
4191 FCPortPage0_t *pp0dest;
4192 dma_addr_t page0_dma;
4193 int data_sz;
4194 int copy_sz;
4195 int rc;
Michael Reed05e8ec12006-01-13 14:31:54 -06004196 int count = 400;
4197
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198
4199 /* Get FCPort Page 0 header */
4200 hdr.PageVersion = 0;
4201 hdr.PageLength = 0;
4202 hdr.PageNumber = 0;
4203 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004204 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 cfg.physAddr = -1;
4206 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4207 cfg.dir = 0;
4208 cfg.pageAddr = portnum;
4209 cfg.timeout = 0;
4210
4211 if ((rc = mpt_config(ioc, &cfg)) != 0)
4212 return rc;
4213
4214 if (hdr.PageLength == 0)
4215 return 0;
4216
4217 data_sz = hdr.PageLength * 4;
4218 rc = -ENOMEM;
4219 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4220 if (ppage0_alloc) {
Michael Reed05e8ec12006-01-13 14:31:54 -06004221
4222 try_again:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 memset((u8 *)ppage0_alloc, 0, data_sz);
4224 cfg.physAddr = page0_dma;
4225 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4226
4227 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4228 /* save the data */
4229 pp0dest = &ioc->fc_port_page0[portnum];
4230 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
4231 memcpy(pp0dest, ppage0_alloc, copy_sz);
4232
4233 /*
4234 * Normalize endianness of structure data,
4235 * by byte-swapping all > 1 byte fields!
4236 */
4237 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
4238 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
4239 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
4240 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
4241 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
4242 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
4243 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
4244 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
4245 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
4246 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
4247 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
4248 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
4249 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
4250 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
4251 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
4252 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
4253
Michael Reed05e8ec12006-01-13 14:31:54 -06004254 /*
4255 * if still doing discovery,
4256 * hang loose a while until finished
4257 */
4258 if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
4259 if (count-- > 0) {
4260 msleep_interruptible(100);
4261 goto try_again;
4262 }
4263 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
4264 " complete.\n",
4265 ioc->name);
4266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 }
4268
4269 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4270 }
4271
4272 return rc;
4273}
4274
4275/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4276/*
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004277 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4278 * @ioc: Pointer to MPT_ADAPTER structure
4279 * @sas_address: 64bit SAS Address for operation.
4280 * @target_id: specified target for operation
4281 * @bus: specified bus for operation
4282 * @persist_opcode: see below
4283 *
4284 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4285 * devices not currently present.
4286 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4287 *
4288 * NOTE: Don't use not this function during interrupt time.
4289 *
4290 * Returns: 0 for success, non-zero error
4291 */
4292
4293/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4294int
4295mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4296{
4297 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4298 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4299 MPT_FRAME_HDR *mf = NULL;
4300 MPIHeader_t *mpi_hdr;
4301
4302
4303 /* insure garbage is not sent to fw */
4304 switch(persist_opcode) {
4305
4306 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4307 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4308 break;
4309
4310 default:
4311 return -1;
4312 break;
4313 }
4314
4315 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4316
4317 /* Get a MF for this command.
4318 */
4319 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4320 printk("%s: no msg frames!\n",__FUNCTION__);
4321 return -1;
4322 }
4323
4324 mpi_hdr = (MPIHeader_t *) mf;
4325 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4326 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4327 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4328 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4329 sasIoUnitCntrReq->Operation = persist_opcode;
4330
4331 init_timer(&ioc->persist_timer);
4332 ioc->persist_timer.data = (unsigned long) ioc;
4333 ioc->persist_timer.function = mpt_timer_expired;
4334 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4335 ioc->persist_wait_done=0;
4336 add_timer(&ioc->persist_timer);
4337 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4338 wait_event(mpt_waitq, ioc->persist_wait_done);
4339
4340 sasIoUnitCntrReply =
4341 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4342 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4343 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4344 __FUNCTION__,
4345 sasIoUnitCntrReply->IOCStatus,
4346 sasIoUnitCntrReply->IOCLogInfo);
4347 return -1;
4348 }
4349
4350 printk("%s: success\n",__FUNCTION__);
4351 return 0;
4352}
4353
4354/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004355
4356static void
4357mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4358 MpiEventDataRaid_t * pRaidEventData)
4359{
4360 int volume;
4361 int reason;
4362 int disk;
4363 int status;
4364 int flags;
4365 int state;
4366
4367 volume = pRaidEventData->VolumeID;
4368 reason = pRaidEventData->ReasonCode;
4369 disk = pRaidEventData->PhysDiskNum;
4370 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4371 flags = (status >> 0) & 0xff;
4372 state = (status >> 8) & 0xff;
4373
4374 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4375 return;
4376 }
4377
4378 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4379 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4380 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4381 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4382 ioc->name, disk);
4383 } else {
4384 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4385 ioc->name, volume);
4386 }
4387
4388 switch(reason) {
4389 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4390 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4391 ioc->name);
4392 break;
4393
4394 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4395
4396 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4397 ioc->name);
4398 break;
4399
4400 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4401 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4402 ioc->name);
4403 break;
4404
4405 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4406 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4407 ioc->name,
4408 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4409 ? "optimal"
4410 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4411 ? "degraded"
4412 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4413 ? "failed"
4414 : "state unknown",
4415 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4416 ? ", enabled" : "",
4417 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4418 ? ", quiesced" : "",
4419 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4420 ? ", resync in progress" : "" );
4421 break;
4422
4423 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4424 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4425 ioc->name, disk);
4426 break;
4427
4428 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4429 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4430 ioc->name);
4431 break;
4432
4433 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4434 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4435 ioc->name);
4436 break;
4437
4438 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4439 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4440 ioc->name);
4441 break;
4442
4443 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4444 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4445 ioc->name,
4446 state == MPI_PHYSDISK0_STATUS_ONLINE
4447 ? "online"
4448 : state == MPI_PHYSDISK0_STATUS_MISSING
4449 ? "missing"
4450 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4451 ? "not compatible"
4452 : state == MPI_PHYSDISK0_STATUS_FAILED
4453 ? "failed"
4454 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4455 ? "initializing"
4456 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4457 ? "offline requested"
4458 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4459 ? "failed requested"
4460 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4461 ? "offline"
4462 : "state unknown",
4463 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4464 ? ", out of sync" : "",
4465 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4466 ? ", quiesced" : "" );
4467 break;
4468
4469 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4470 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4471 ioc->name, disk);
4472 break;
4473
4474 case MPI_EVENT_RAID_RC_SMART_DATA:
4475 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4476 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4477 break;
4478
4479 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4480 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4481 ioc->name, disk);
4482 break;
4483 }
4484}
4485
4486/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004487/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4489 * @ioc: Pointer to MPT_ADAPTER structure
4490 *
4491 * Returns: 0 for success
4492 * -ENOMEM if no memory available
4493 * -EPERM if not allowed due to ISR context
4494 * -EAGAIN if no msg frames currently available
4495 * -EFAULT for non-successful reply or no reply (timeout)
4496 */
4497static int
4498GetIoUnitPage2(MPT_ADAPTER *ioc)
4499{
4500 ConfigPageHeader_t hdr;
4501 CONFIGPARMS cfg;
4502 IOUnitPage2_t *ppage_alloc;
4503 dma_addr_t page_dma;
4504 int data_sz;
4505 int rc;
4506
4507 /* Get the page header */
4508 hdr.PageVersion = 0;
4509 hdr.PageLength = 0;
4510 hdr.PageNumber = 2;
4511 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004512 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 cfg.physAddr = -1;
4514 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4515 cfg.dir = 0;
4516 cfg.pageAddr = 0;
4517 cfg.timeout = 0;
4518
4519 if ((rc = mpt_config(ioc, &cfg)) != 0)
4520 return rc;
4521
4522 if (hdr.PageLength == 0)
4523 return 0;
4524
4525 /* Read the config page */
4526 data_sz = hdr.PageLength * 4;
4527 rc = -ENOMEM;
4528 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4529 if (ppage_alloc) {
4530 memset((u8 *)ppage_alloc, 0, data_sz);
4531 cfg.physAddr = page_dma;
4532 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4533
4534 /* If Good, save data */
4535 if ((rc = mpt_config(ioc, &cfg)) == 0)
4536 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4537
4538 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4539 }
4540
4541 return rc;
4542}
4543
4544/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4545/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4546 * @ioc: Pointer to a Adapter Strucutre
4547 * @portnum: IOC port number
4548 *
4549 * Return: -EFAULT if read of config page header fails
4550 * or if no nvram
4551 * If read of SCSI Port Page 0 fails,
4552 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4553 * Adapter settings: async, narrow
4554 * Return 1
4555 * If read of SCSI Port Page 2 fails,
4556 * Adapter settings valid
4557 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4558 * Return 1
4559 * Else
4560 * Both valid
4561 * Return 0
4562 * CHECK - what type of locking mechanisms should be used????
4563 */
4564static int
4565mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4566{
4567 u8 *pbuf;
4568 dma_addr_t buf_dma;
4569 CONFIGPARMS cfg;
4570 ConfigPageHeader_t header;
4571 int ii;
4572 int data, rc = 0;
4573
4574 /* Allocate memory
4575 */
4576 if (!ioc->spi_data.nvram) {
4577 int sz;
4578 u8 *mem;
4579 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4580 mem = kmalloc(sz, GFP_ATOMIC);
4581 if (mem == NULL)
4582 return -EFAULT;
4583
4584 ioc->spi_data.nvram = (int *) mem;
4585
4586 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4587 ioc->name, ioc->spi_data.nvram, sz));
4588 }
4589
4590 /* Invalidate NVRAM information
4591 */
4592 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4593 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4594 }
4595
4596 /* Read SPP0 header, allocate memory, then read page.
4597 */
4598 header.PageVersion = 0;
4599 header.PageLength = 0;
4600 header.PageNumber = 0;
4601 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004602 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 cfg.physAddr = -1;
4604 cfg.pageAddr = portnum;
4605 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4606 cfg.dir = 0;
4607 cfg.timeout = 0; /* use default */
4608 if (mpt_config(ioc, &cfg) != 0)
4609 return -EFAULT;
4610
4611 if (header.PageLength > 0) {
4612 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4613 if (pbuf) {
4614 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4615 cfg.physAddr = buf_dma;
4616 if (mpt_config(ioc, &cfg) != 0) {
4617 ioc->spi_data.maxBusWidth = MPT_NARROW;
4618 ioc->spi_data.maxSyncOffset = 0;
4619 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4620 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4621 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004622 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4623 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 } else {
4625 /* Save the Port Page 0 data
4626 */
4627 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4628 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4629 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4630
4631 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4632 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004633 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 ioc->name, pPP0->Capabilities));
4635 }
4636 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4637 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4638 if (data) {
4639 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4640 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4641 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004642 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4643 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 } else {
4645 ioc->spi_data.maxSyncOffset = 0;
4646 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4647 }
4648
4649 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4650
4651 /* Update the minSyncFactor based on bus type.
4652 */
4653 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4654 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4655
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004656 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004658 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4659 ioc->name, ioc->spi_data.minSyncFactor));
4660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 }
4662 }
4663 if (pbuf) {
4664 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4665 }
4666 }
4667 }
4668
4669 /* SCSI Port Page 2 - Read the header then the page.
4670 */
4671 header.PageVersion = 0;
4672 header.PageLength = 0;
4673 header.PageNumber = 2;
4674 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004675 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 cfg.physAddr = -1;
4677 cfg.pageAddr = portnum;
4678 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4679 cfg.dir = 0;
4680 if (mpt_config(ioc, &cfg) != 0)
4681 return -EFAULT;
4682
4683 if (header.PageLength > 0) {
4684 /* Allocate memory and read SCSI Port Page 2
4685 */
4686 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4687 if (pbuf) {
4688 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4689 cfg.physAddr = buf_dma;
4690 if (mpt_config(ioc, &cfg) != 0) {
4691 /* Nvram data is left with INVALID mark
4692 */
4693 rc = 1;
4694 } else {
4695 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4696 MpiDeviceInfo_t *pdevice = NULL;
4697
Moore, Ericd8e925d2006-01-16 18:53:06 -07004698 /*
4699 * Save "Set to Avoid SCSI Bus Resets" flag
4700 */
4701 ioc->spi_data.bus_reset =
4702 (le32_to_cpu(pPP2->PortFlags) &
4703 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4704 0 : 1 ;
4705
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 /* Save the Port Page 2 data
4707 * (reformat into a 32bit quantity)
4708 */
4709 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4710 ioc->spi_data.PortFlags = data;
4711 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4712 pdevice = &pPP2->DeviceSettings[ii];
4713 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4714 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4715 ioc->spi_data.nvram[ii] = data;
4716 }
4717 }
4718
4719 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4720 }
4721 }
4722
4723 /* Update Adapter limits with those from NVRAM
4724 * Comment: Don't need to do this. Target performance
4725 * parameters will never exceed the adapters limits.
4726 */
4727
4728 return rc;
4729}
4730
4731/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4732/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4733 * @ioc: Pointer to a Adapter Strucutre
4734 * @portnum: IOC port number
4735 *
4736 * Return: -EFAULT if read of config page header fails
4737 * or 0 if success.
4738 */
4739static int
4740mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4741{
4742 CONFIGPARMS cfg;
4743 ConfigPageHeader_t header;
4744
4745 /* Read the SCSI Device Page 1 header
4746 */
4747 header.PageVersion = 0;
4748 header.PageLength = 0;
4749 header.PageNumber = 1;
4750 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004751 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 cfg.physAddr = -1;
4753 cfg.pageAddr = portnum;
4754 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4755 cfg.dir = 0;
4756 cfg.timeout = 0;
4757 if (mpt_config(ioc, &cfg) != 0)
4758 return -EFAULT;
4759
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004760 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4761 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
4763 header.PageVersion = 0;
4764 header.PageLength = 0;
4765 header.PageNumber = 0;
4766 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4767 if (mpt_config(ioc, &cfg) != 0)
4768 return -EFAULT;
4769
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004770 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4771 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772
4773 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4774 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4775
4776 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4777 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4778 return 0;
4779}
4780
4781/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4782/**
4783 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4784 * @ioc: Pointer to a Adapter Strucutre
4785 * @portnum: IOC port number
4786 *
4787 * Return:
4788 * 0 on success
4789 * -EFAULT if read of config page header fails or data pointer not NULL
4790 * -ENOMEM if pci_alloc failed
4791 */
4792int
4793mpt_findImVolumes(MPT_ADAPTER *ioc)
4794{
4795 IOCPage2_t *pIoc2;
4796 u8 *mem;
4797 ConfigPageIoc2RaidVol_t *pIocRv;
4798 dma_addr_t ioc2_dma;
4799 CONFIGPARMS cfg;
4800 ConfigPageHeader_t header;
4801 int jj;
4802 int rc = 0;
4803 int iocpage2sz;
4804 u8 nVols, nPhys;
4805 u8 vid, vbus, vioc;
4806
4807 /* Read IOCP2 header then the page.
4808 */
4809 header.PageVersion = 0;
4810 header.PageLength = 0;
4811 header.PageNumber = 2;
4812 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004813 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 cfg.physAddr = -1;
4815 cfg.pageAddr = 0;
4816 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4817 cfg.dir = 0;
4818 cfg.timeout = 0;
4819 if (mpt_config(ioc, &cfg) != 0)
4820 return -EFAULT;
4821
4822 if (header.PageLength == 0)
4823 return -EFAULT;
4824
4825 iocpage2sz = header.PageLength * 4;
4826 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4827 if (!pIoc2)
4828 return -ENOMEM;
4829
4830 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4831 cfg.physAddr = ioc2_dma;
4832 if (mpt_config(ioc, &cfg) != 0)
4833 goto done_and_free;
4834
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004835 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4837 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004838 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 } else {
4840 goto done_and_free;
4841 }
4842 }
4843 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4844
4845 /* Identify RAID Volume Id's */
4846 nVols = pIoc2->NumActiveVolumes;
4847 if ( nVols == 0) {
4848 /* No RAID Volume.
4849 */
4850 goto done_and_free;
4851 } else {
4852 /* At least 1 RAID Volume
4853 */
4854 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004855 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4857 vid = pIocRv->VolumeID;
4858 vbus = pIocRv->VolumeBus;
4859 vioc = pIocRv->VolumeIOC;
4860
4861 /* find the match
4862 */
4863 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004864 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 } else {
4866 /* Error! Always bus 0
4867 */
4868 }
4869 }
4870 }
4871
4872 /* Identify Hidden Physical Disk Id's */
4873 nPhys = pIoc2->NumActivePhysDisks;
4874 if (nPhys == 0) {
4875 /* No physical disks.
4876 */
4877 } else {
4878 mpt_read_ioc_pg_3(ioc);
4879 }
4880
4881done_and_free:
4882 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4883
4884 return rc;
4885}
4886
Moore, Ericc972c702006-03-14 09:14:06 -07004887static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4889{
4890 IOCPage3_t *pIoc3;
4891 u8 *mem;
4892 CONFIGPARMS cfg;
4893 ConfigPageHeader_t header;
4894 dma_addr_t ioc3_dma;
4895 int iocpage3sz = 0;
4896
4897 /* Free the old page
4898 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004899 kfree(ioc->raid_data.pIocPg3);
4900 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901
4902 /* There is at least one physical disk.
4903 * Read and save IOC Page 3
4904 */
4905 header.PageVersion = 0;
4906 header.PageLength = 0;
4907 header.PageNumber = 3;
4908 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004909 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 cfg.physAddr = -1;
4911 cfg.pageAddr = 0;
4912 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4913 cfg.dir = 0;
4914 cfg.timeout = 0;
4915 if (mpt_config(ioc, &cfg) != 0)
4916 return 0;
4917
4918 if (header.PageLength == 0)
4919 return 0;
4920
4921 /* Read Header good, alloc memory
4922 */
4923 iocpage3sz = header.PageLength * 4;
4924 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4925 if (!pIoc3)
4926 return 0;
4927
4928 /* Read the Page and save the data
4929 * into malloc'd memory.
4930 */
4931 cfg.physAddr = ioc3_dma;
4932 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4933 if (mpt_config(ioc, &cfg) == 0) {
4934 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4935 if (mem) {
4936 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004937 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 }
4939 }
4940
4941 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4942
4943 return 0;
4944}
4945
4946static void
4947mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4948{
4949 IOCPage4_t *pIoc4;
4950 CONFIGPARMS cfg;
4951 ConfigPageHeader_t header;
4952 dma_addr_t ioc4_dma;
4953 int iocpage4sz;
4954
4955 /* Read and save IOC Page 4
4956 */
4957 header.PageVersion = 0;
4958 header.PageLength = 0;
4959 header.PageNumber = 4;
4960 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004961 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962 cfg.physAddr = -1;
4963 cfg.pageAddr = 0;
4964 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4965 cfg.dir = 0;
4966 cfg.timeout = 0;
4967 if (mpt_config(ioc, &cfg) != 0)
4968 return;
4969
4970 if (header.PageLength == 0)
4971 return;
4972
4973 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4974 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4975 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4976 if (!pIoc4)
4977 return;
4978 } else {
4979 ioc4_dma = ioc->spi_data.IocPg4_dma;
4980 iocpage4sz = ioc->spi_data.IocPg4Sz;
4981 }
4982
4983 /* Read the Page into dma memory.
4984 */
4985 cfg.physAddr = ioc4_dma;
4986 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4987 if (mpt_config(ioc, &cfg) == 0) {
4988 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4989 ioc->spi_data.IocPg4_dma = ioc4_dma;
4990 ioc->spi_data.IocPg4Sz = iocpage4sz;
4991 } else {
4992 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4993 ioc->spi_data.pIocPg4 = NULL;
4994 }
4995}
4996
4997static void
4998mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4999{
5000 IOCPage1_t *pIoc1;
5001 CONFIGPARMS cfg;
5002 ConfigPageHeader_t header;
5003 dma_addr_t ioc1_dma;
5004 int iocpage1sz = 0;
5005 u32 tmp;
5006
5007 /* Check the Coalescing Timeout in IOC Page 1
5008 */
5009 header.PageVersion = 0;
5010 header.PageLength = 0;
5011 header.PageNumber = 1;
5012 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005013 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 cfg.physAddr = -1;
5015 cfg.pageAddr = 0;
5016 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5017 cfg.dir = 0;
5018 cfg.timeout = 0;
5019 if (mpt_config(ioc, &cfg) != 0)
5020 return;
5021
5022 if (header.PageLength == 0)
5023 return;
5024
5025 /* Read Header good, alloc memory
5026 */
5027 iocpage1sz = header.PageLength * 4;
5028 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5029 if (!pIoc1)
5030 return;
5031
5032 /* Read the Page and check coalescing timeout
5033 */
5034 cfg.physAddr = ioc1_dma;
5035 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5036 if (mpt_config(ioc, &cfg) == 0) {
5037
5038 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5039 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5040 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5041
5042 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5043 ioc->name, tmp));
5044
5045 if (tmp > MPT_COALESCING_TIMEOUT) {
5046 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5047
5048 /* Write NVRAM and current
5049 */
5050 cfg.dir = 1;
5051 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5052 if (mpt_config(ioc, &cfg) == 0) {
5053 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5054 ioc->name, MPT_COALESCING_TIMEOUT));
5055
5056 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5057 if (mpt_config(ioc, &cfg) == 0) {
5058 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5059 ioc->name, MPT_COALESCING_TIMEOUT));
5060 } else {
5061 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5062 ioc->name));
5063 }
5064
5065 } else {
5066 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5067 ioc->name));
5068 }
5069 }
5070
5071 } else {
5072 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5073 }
5074 }
5075
5076 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5077
5078 return;
5079}
5080
5081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5082/*
5083 * SendEventNotification - Send EventNotification (on or off) request
5084 * to MPT adapter.
5085 * @ioc: Pointer to MPT_ADAPTER structure
5086 * @EvSwitch: Event switch flags
5087 */
5088static int
5089SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5090{
5091 EventNotification_t *evnp;
5092
5093 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5094 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005095 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 ioc->name));
5097 return 0;
5098 }
5099 memset(evnp, 0, sizeof(*evnp));
5100
Moore, Eric3a892be2006-03-14 09:14:03 -07005101 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102
5103 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5104 evnp->ChainOffset = 0;
5105 evnp->MsgFlags = 0;
5106 evnp->Switch = EvSwitch;
5107
5108 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5109
5110 return 0;
5111}
5112
5113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5114/**
5115 * SendEventAck - Send EventAck request to MPT adapter.
5116 * @ioc: Pointer to MPT_ADAPTER structure
5117 * @evnp: Pointer to original EventNotification request
5118 */
5119static int
5120SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5121{
5122 EventAck_t *pAck;
5123
5124 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005125 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5126 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5127 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5128 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 return -1;
5130 }
5131 memset(pAck, 0, sizeof(*pAck));
5132
5133 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5134
5135 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5136 pAck->ChainOffset = 0;
5137 pAck->MsgFlags = 0;
5138 pAck->Event = evnp->Event;
5139 pAck->EventContext = evnp->EventContext;
5140
5141 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5142
5143 return 0;
5144}
5145
5146/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5147/**
5148 * mpt_config - Generic function to issue config message
5149 * @ioc - Pointer to an adapter structure
5150 * @cfg - Pointer to a configuration structure. Struct contains
5151 * action, page address, direction, physical address
5152 * and pointer to a configuration page header
5153 * Page header is updated.
5154 *
5155 * Returns 0 for success
5156 * -EPERM if not allowed due to ISR context
5157 * -EAGAIN if no msg frames currently available
5158 * -EFAULT for non-successful reply or no reply (timeout)
5159 */
5160int
5161mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5162{
5163 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005164 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 MPT_FRAME_HDR *mf;
5166 unsigned long flags;
5167 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005168 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 int in_isr;
5170
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005171 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 * to be in ISR context, because that is fatal!
5173 */
5174 in_isr = in_interrupt();
5175 if (in_isr) {
5176 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5177 ioc->name));
5178 return -EPERM;
5179 }
5180
5181 /* Get and Populate a free Frame
5182 */
5183 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5184 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5185 ioc->name));
5186 return -EAGAIN;
5187 }
5188 pReq = (Config_t *)mf;
5189 pReq->Action = pCfg->action;
5190 pReq->Reserved = 0;
5191 pReq->ChainOffset = 0;
5192 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005193
5194 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 pReq->ExtPageLength = 0;
5196 pReq->ExtPageType = 0;
5197 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005198
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 for (ii=0; ii < 8; ii++)
5200 pReq->Reserved2[ii] = 0;
5201
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005202 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5203 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5204 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5205 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5206
5207 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5208 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5209 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5210 pReq->ExtPageType = pExtHdr->ExtPageType;
5211 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5212
5213 /* Page Length must be treated as a reserved field for the extended header. */
5214 pReq->Header.PageLength = 0;
5215 }
5216
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5218
5219 /* Add a SGE to the config request.
5220 */
5221 if (pCfg->dir)
5222 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5223 else
5224 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5225
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005226 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5227 flagsLength |= pExtHdr->ExtPageLength * 4;
5228
5229 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5230 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5231 }
5232 else {
5233 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5234
5235 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5236 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238
5239 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5240
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 /* Append pCfg pointer to end of mf
5242 */
5243 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5244
5245 /* Initalize the timer
5246 */
5247 init_timer(&pCfg->timer);
5248 pCfg->timer.data = (unsigned long) ioc;
5249 pCfg->timer.function = mpt_timer_expired;
5250 pCfg->wait_done = 0;
5251
5252 /* Set the timer; ensure 10 second minimum */
5253 if (pCfg->timeout < 10)
5254 pCfg->timer.expires = jiffies + HZ*10;
5255 else
5256 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5257
5258 /* Add to end of Q, set timer and then issue this command */
5259 spin_lock_irqsave(&ioc->FreeQlock, flags);
5260 list_add_tail(&pCfg->linkage, &ioc->configQ);
5261 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5262
5263 add_timer(&pCfg->timer);
5264 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5265 wait_event(mpt_waitq, pCfg->wait_done);
5266
5267 /* mf has been freed - do not access */
5268
5269 rc = pCfg->status;
5270
5271 return rc;
5272}
5273
5274/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275/*
5276 * mpt_timer_expired - Call back for timer process.
5277 * Used only internal config functionality.
5278 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5279 */
5280static void
5281mpt_timer_expired(unsigned long data)
5282{
5283 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5284
5285 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5286
5287 /* Perform a FW reload */
5288 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5289 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5290
5291 /* No more processing.
5292 * Hard reset clean-up will wake up
5293 * process and free all resources.
5294 */
5295 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5296
5297 return;
5298}
5299
5300/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5301/*
5302 * mpt_ioc_reset - Base cleanup for hard reset
5303 * @ioc: Pointer to the adapter structure
5304 * @reset_phase: Indicates pre- or post-reset functionality
5305 *
5306 * Remark: Free's resources with internally generated commands.
5307 */
5308static int
5309mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5310{
5311 CONFIGPARMS *pCfg;
5312 unsigned long flags;
5313
5314 dprintk((KERN_WARNING MYNAM
5315 ": IOC %s_reset routed to MPT base driver!\n",
5316 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5317 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5318
5319 if (reset_phase == MPT_IOC_SETUP_RESET) {
5320 ;
5321 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5322 /* If the internal config Q is not empty -
5323 * delete timer. MF resources will be freed when
5324 * the FIFO's are primed.
5325 */
5326 spin_lock_irqsave(&ioc->FreeQlock, flags);
5327 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5328 del_timer(&pCfg->timer);
5329 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5330
5331 } else {
5332 CONFIGPARMS *pNext;
5333
5334 /* Search the configQ for internal commands.
5335 * Flush the Q, and wake up all suspended threads.
5336 */
5337 spin_lock_irqsave(&ioc->FreeQlock, flags);
5338 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5339 list_del(&pCfg->linkage);
5340
5341 pCfg->status = MPT_CONFIG_ERROR;
5342 pCfg->wait_done = 1;
5343 wake_up(&mpt_waitq);
5344 }
5345 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5346 }
5347
5348 return 1; /* currently means nothing really */
5349}
5350
5351
5352#ifdef CONFIG_PROC_FS /* { */
5353/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5354/*
5355 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5356 */
5357/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5358/*
5359 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5360 *
5361 * Returns 0 for success, non-zero for failure.
5362 */
5363static int
5364procmpt_create(void)
5365{
5366 struct proc_dir_entry *ent;
5367
5368 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5369 if (mpt_proc_root_dir == NULL)
5370 return -ENOTDIR;
5371
5372 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5373 if (ent)
5374 ent->read_proc = procmpt_summary_read;
5375
5376 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5377 if (ent)
5378 ent->read_proc = procmpt_version_read;
5379
5380 return 0;
5381}
5382
5383/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5384/*
5385 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5386 *
5387 * Returns 0 for success, non-zero for failure.
5388 */
5389static void
5390procmpt_destroy(void)
5391{
5392 remove_proc_entry("version", mpt_proc_root_dir);
5393 remove_proc_entry("summary", mpt_proc_root_dir);
5394 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5395}
5396
5397/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5398/*
5399 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5400 * or from /proc/mpt/iocN/summary.
5401 * @buf: Pointer to area to write information
5402 * @start: Pointer to start pointer
5403 * @offset: Offset to start writing
5404 * @request:
5405 * @eof: Pointer to EOF integer
5406 * @data: Pointer
5407 *
5408 * Returns number of characters written to process performing the read.
5409 */
5410static int
5411procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5412{
5413 MPT_ADAPTER *ioc;
5414 char *out = buf;
5415 int len;
5416
5417 if (data) {
5418 int more = 0;
5419
5420 ioc = data;
5421 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5422
5423 out += more;
5424 } else {
5425 list_for_each_entry(ioc, &ioc_list, list) {
5426 int more = 0;
5427
5428 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5429
5430 out += more;
5431 if ((out-buf) >= request)
5432 break;
5433 }
5434 }
5435
5436 len = out - buf;
5437
5438 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5439}
5440
5441/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5442/*
5443 * procmpt_version_read - Handle read request from /proc/mpt/version.
5444 * @buf: Pointer to area to write information
5445 * @start: Pointer to start pointer
5446 * @offset: Offset to start writing
5447 * @request:
5448 * @eof: Pointer to EOF integer
5449 * @data: Pointer
5450 *
5451 * Returns number of characters written to process performing the read.
5452 */
5453static int
5454procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5455{
5456 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005457 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 char *drvname;
5459 int len;
5460
5461 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5462 len += sprintf(buf+len, " Fusion MPT base driver\n");
5463
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005464 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5466 drvname = NULL;
5467 if (MptCallbacks[ii]) {
5468 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005469 case MPTSPI_DRIVER:
5470 if (!scsi++) drvname = "SPI host";
5471 break;
5472 case MPTFC_DRIVER:
5473 if (!fc++) drvname = "FC host";
5474 break;
5475 case MPTSAS_DRIVER:
5476 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 break;
5478 case MPTLAN_DRIVER:
5479 if (!lan++) drvname = "LAN";
5480 break;
5481 case MPTSTM_DRIVER:
5482 if (!targ++) drvname = "SCSI target";
5483 break;
5484 case MPTCTL_DRIVER:
5485 if (!ctl++) drvname = "ioctl";
5486 break;
5487 }
5488
5489 if (drvname)
5490 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5491 }
5492 }
5493
5494 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5495}
5496
5497/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5498/*
5499 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5500 * @buf: Pointer to area to write information
5501 * @start: Pointer to start pointer
5502 * @offset: Offset to start writing
5503 * @request:
5504 * @eof: Pointer to EOF integer
5505 * @data: Pointer
5506 *
5507 * Returns number of characters written to process performing the read.
5508 */
5509static int
5510procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5511{
5512 MPT_ADAPTER *ioc = data;
5513 int len;
5514 char expVer[32];
5515 int sz;
5516 int p;
5517
5518 mpt_get_fw_exp_ver(expVer, ioc);
5519
5520 len = sprintf(buf, "%s:", ioc->name);
5521 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5522 len += sprintf(buf+len, " (f/w download boot flag set)");
5523// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5524// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5525
5526 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5527 ioc->facts.ProductID,
5528 ioc->prod_name);
5529 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5530 if (ioc->facts.FWImageSize)
5531 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5532 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5533 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5534 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5535
5536 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5537 ioc->facts.CurrentHostMfaHighAddr);
5538 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5539 ioc->facts.CurrentSenseBufferHighAddr);
5540
5541 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5542 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5543
5544 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5545 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5546 /*
5547 * Rounding UP to nearest 4-kB boundary here...
5548 */
5549 sz = (ioc->req_sz * ioc->req_depth) + 128;
5550 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5551 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5552 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5553 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5554 4*ioc->facts.RequestFrameSize,
5555 ioc->facts.GlobalCredits);
5556
5557 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5558 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5559 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5560 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5561 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5562 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5563 ioc->facts.CurReplyFrameSize,
5564 ioc->facts.ReplyQueueDepth);
5565
5566 len += sprintf(buf+len, " MaxDevices = %d\n",
5567 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5568 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5569
5570 /* per-port info */
5571 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5572 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5573 p+1,
5574 ioc->facts.NumberOfPorts);
5575 if (ioc->bus_type == FC) {
5576 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5577 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5578 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5579 a[5], a[4], a[3], a[2], a[1], a[0]);
5580 }
5581 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5582 ioc->fc_port_page0[p].WWNN.High,
5583 ioc->fc_port_page0[p].WWNN.Low,
5584 ioc->fc_port_page0[p].WWPN.High,
5585 ioc->fc_port_page0[p].WWPN.Low);
5586 }
5587 }
5588
5589 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5590}
5591
5592#endif /* CONFIG_PROC_FS } */
5593
5594/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5595static void
5596mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5597{
5598 buf[0] ='\0';
5599 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5600 sprintf(buf, " (Exp %02d%02d)",
5601 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5602 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5603
5604 /* insider hack! */
5605 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5606 strcat(buf, " [MDBG]");
5607 }
5608}
5609
5610/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5611/**
5612 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5613 * @ioc: Pointer to MPT_ADAPTER structure
5614 * @buffer: Pointer to buffer where IOC summary info should be written
5615 * @size: Pointer to number of bytes we wrote (set by this routine)
5616 * @len: Offset at which to start writing in buffer
5617 * @showlan: Display LAN stuff?
5618 *
5619 * This routine writes (english readable) ASCII text, which represents
5620 * a summary of IOC information, to a buffer.
5621 */
5622void
5623mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5624{
5625 char expVer[32];
5626 int y;
5627
5628 mpt_get_fw_exp_ver(expVer, ioc);
5629
5630 /*
5631 * Shorter summary of attached ioc's...
5632 */
5633 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5634 ioc->name,
5635 ioc->prod_name,
5636 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5637 ioc->facts.FWVersion.Word,
5638 expVer,
5639 ioc->facts.NumberOfPorts,
5640 ioc->req_depth);
5641
5642 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5643 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5644 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5645 a[5], a[4], a[3], a[2], a[1], a[0]);
5646 }
5647
5648#ifndef __sparc__
5649 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
5650#else
5651 y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
5652#endif
5653
5654 if (!ioc->active)
5655 y += sprintf(buffer+len+y, " (disabled)");
5656
5657 y += sprintf(buffer+len+y, "\n");
5658
5659 *size = y;
5660}
5661
5662/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5663/*
5664 * Reset Handling
5665 */
5666/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5667/**
5668 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5669 * Management call based on input arg values. If TaskMgmt fails,
5670 * return associated SCSI request.
5671 * @ioc: Pointer to MPT_ADAPTER structure
5672 * @sleepFlag: Indicates if sleep or schedule must be called.
5673 *
5674 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5675 * or a non-interrupt thread. In the former, must not call schedule().
5676 *
5677 * Remark: A return of -1 is a FATAL error case, as it means a
5678 * FW reload/initialization failed.
5679 *
5680 * Returns 0 for SUCCESS or -1 if FAILED.
5681 */
5682int
5683mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5684{
5685 int rc;
5686 unsigned long flags;
5687
5688 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5689#ifdef MFCNT
5690 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5691 printk("MF count 0x%x !\n", ioc->mfcnt);
5692#endif
5693
5694 /* Reset the adapter. Prevent more than 1 call to
5695 * mpt_do_ioc_recovery at any instant in time.
5696 */
5697 spin_lock_irqsave(&ioc->diagLock, flags);
5698 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5699 spin_unlock_irqrestore(&ioc->diagLock, flags);
5700 return 0;
5701 } else {
5702 ioc->diagPending = 1;
5703 }
5704 spin_unlock_irqrestore(&ioc->diagLock, flags);
5705
5706 /* FIXME: If do_ioc_recovery fails, repeat....
5707 */
5708
5709 /* The SCSI driver needs to adjust timeouts on all current
5710 * commands prior to the diagnostic reset being issued.
5711 * Prevents timeouts occuring during a diagnostic reset...very bad.
5712 * For all other protocol drivers, this is a no-op.
5713 */
5714 {
5715 int ii;
5716 int r = 0;
5717
5718 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5719 if (MptResetHandlers[ii]) {
5720 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5721 ioc->name, ii));
5722 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
5723 if (ioc->alt_ioc) {
5724 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5725 ioc->name, ioc->alt_ioc->name, ii));
5726 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
5727 }
5728 }
5729 }
5730 }
5731
5732 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5733 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5734 rc, ioc->name);
5735 }
5736 ioc->reload_fw = 0;
5737 if (ioc->alt_ioc)
5738 ioc->alt_ioc->reload_fw = 0;
5739
5740 spin_lock_irqsave(&ioc->diagLock, flags);
5741 ioc->diagPending = 0;
5742 if (ioc->alt_ioc)
5743 ioc->alt_ioc->diagPending = 0;
5744 spin_unlock_irqrestore(&ioc->diagLock, flags);
5745
5746 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5747
5748 return rc;
5749}
5750
5751/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005752static void
5753EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754{
5755 char *ds;
5756
5757 switch(event) {
5758 case MPI_EVENT_NONE:
5759 ds = "None";
5760 break;
5761 case MPI_EVENT_LOG_DATA:
5762 ds = "Log Data";
5763 break;
5764 case MPI_EVENT_STATE_CHANGE:
5765 ds = "State Change";
5766 break;
5767 case MPI_EVENT_UNIT_ATTENTION:
5768 ds = "Unit Attention";
5769 break;
5770 case MPI_EVENT_IOC_BUS_RESET:
5771 ds = "IOC Bus Reset";
5772 break;
5773 case MPI_EVENT_EXT_BUS_RESET:
5774 ds = "External Bus Reset";
5775 break;
5776 case MPI_EVENT_RESCAN:
5777 ds = "Bus Rescan Event";
5778 /* Ok, do we need to do anything here? As far as
5779 I can tell, this is when a new device gets added
5780 to the loop. */
5781 break;
5782 case MPI_EVENT_LINK_STATUS_CHANGE:
5783 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5784 ds = "Link Status(FAILURE) Change";
5785 else
5786 ds = "Link Status(ACTIVE) Change";
5787 break;
5788 case MPI_EVENT_LOOP_STATE_CHANGE:
5789 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5790 ds = "Loop State(LIP) Change";
5791 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
5792 ds = "Loop State(LPE) Change"; /* ??? */
5793 else
5794 ds = "Loop State(LPB) Change"; /* ??? */
5795 break;
5796 case MPI_EVENT_LOGOUT:
5797 ds = "Logout";
5798 break;
5799 case MPI_EVENT_EVENT_CHANGE:
5800 if (evData0)
5801 ds = "Events(ON) Change";
5802 else
5803 ds = "Events(OFF) Change";
5804 break;
5805 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005806 {
5807 u8 ReasonCode = (u8)(evData0 >> 16);
5808 switch (ReasonCode) {
5809 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5810 ds = "Integrated Raid: Volume Created";
5811 break;
5812 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5813 ds = "Integrated Raid: Volume Deleted";
5814 break;
5815 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5816 ds = "Integrated Raid: Volume Settings Changed";
5817 break;
5818 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5819 ds = "Integrated Raid: Volume Status Changed";
5820 break;
5821 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5822 ds = "Integrated Raid: Volume Physdisk Changed";
5823 break;
5824 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5825 ds = "Integrated Raid: Physdisk Created";
5826 break;
5827 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5828 ds = "Integrated Raid: Physdisk Deleted";
5829 break;
5830 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5831 ds = "Integrated Raid: Physdisk Settings Changed";
5832 break;
5833 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5834 ds = "Integrated Raid: Physdisk Status Changed";
5835 break;
5836 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5837 ds = "Integrated Raid: Domain Validation Needed";
5838 break;
5839 case MPI_EVENT_RAID_RC_SMART_DATA :
5840 ds = "Integrated Raid; Smart Data";
5841 break;
5842 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5843 ds = "Integrated Raid: Replace Action Started";
5844 break;
5845 default:
5846 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005848 }
5849 break;
5850 }
5851 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5852 ds = "SCSI Device Status Change";
5853 break;
5854 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5855 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005856 char buf[50];
5857 u8 id = (u8)(evData0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005858 u8 ReasonCode = (u8)(evData0 >> 16);
5859 switch (ReasonCode) {
5860 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Moore, Eric3a892be2006-03-14 09:14:03 -07005861 sprintf(buf,"SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005862 break;
5863 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Moore, Eric3a892be2006-03-14 09:14:03 -07005864 sprintf(buf,"SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005865 break;
5866 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Moore, Eric3a892be2006-03-14 09:14:03 -07005867 sprintf(buf,"SAS Device Status Change: SMART Data: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005868 break;
5869 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Moore, Eric3a892be2006-03-14 09:14:03 -07005870 sprintf(buf,"SAS Device Status Change: No Persistancy Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005871 break;
5872 default:
Moore, Eric3a892be2006-03-14 09:14:03 -07005873 sprintf(buf,"SAS Device Status Change: Unknown: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005874 break;
5875 }
Moore, Eric3a892be2006-03-14 09:14:03 -07005876 ds = buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005877 break;
5878 }
5879 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5880 ds = "Bus Timer Expired";
5881 break;
5882 case MPI_EVENT_QUEUE_FULL:
5883 ds = "Queue Full";
5884 break;
5885 case MPI_EVENT_SAS_SES:
5886 ds = "SAS SES Event";
5887 break;
5888 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5889 ds = "Persistent Table Full";
5890 break;
5891 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005892 {
5893 char buf[50];
5894 u8 LinkRates = (u8)(evData0 >> 8);
5895 u8 PhyNumber = (u8)(evData0);
5896 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5897 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5898 switch (LinkRates) {
5899 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
5900 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5901 " Rate Unknown",PhyNumber);
5902 break;
5903 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
5904 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5905 " Phy Disabled",PhyNumber);
5906 break;
5907 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
5908 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5909 " Failed Speed Nego",PhyNumber);
5910 break;
5911 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
5912 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5913 " Sata OOB Completed",PhyNumber);
5914 break;
5915 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
5916 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5917 " Rate 1.5 Gbps",PhyNumber);
5918 break;
5919 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
5920 sprintf(buf,"SAS PHY Link Status: Phy=%d:"
5921 " Rate 3.0 Gpbs",PhyNumber);
5922 break;
5923 default:
5924 sprintf(buf,"SAS PHY Link Status: Phy=%d", PhyNumber);
5925 break;
5926 }
5927 ds = buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005928 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005929 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005930 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5931 ds = "SAS Discovery Error";
5932 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005933 case MPI_EVENT_IR_RESYNC_UPDATE:
5934 {
5935 u8 resync_complete = (u8)(evData0 >> 16);
5936 char buf[40];
5937 sprintf(buf,"IR Resync Update: Complete = %d:",resync_complete);
5938 ds = buf;
5939 break;
5940 }
5941 case MPI_EVENT_IR2:
5942 {
5943 u8 ReasonCode = (u8)(evData0 >> 16);
5944 switch (ReasonCode) {
5945 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5946 ds = "IR2: LD State Changed";
5947 break;
5948 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5949 ds = "IR2: PD State Changed";
5950 break;
5951 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5952 ds = "IR2: Bad Block Table Full";
5953 break;
5954 case MPI_EVENT_IR2_RC_PD_INSERTED:
5955 ds = "IR2: PD Inserted";
5956 break;
5957 case MPI_EVENT_IR2_RC_PD_REMOVED:
5958 ds = "IR2: PD Removed";
5959 break;
5960 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5961 ds = "IR2: Foreign CFG Detected";
5962 break;
5963 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5964 ds = "IR2: Rebuild Medium Error";
5965 break;
5966 default:
5967 ds = "IR2";
5968 break;
5969 }
5970 break;
5971 }
5972 case MPI_EVENT_SAS_DISCOVERY:
5973 {
5974 if (evData0)
5975 ds = "SAS Discovery: Start";
5976 else
5977 ds = "SAS Discovery: Stop";
5978 break;
5979 }
5980 case MPI_EVENT_LOG_ENTRY_ADDED:
5981 ds = "SAS Log Entry Added";
5982 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005983
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 /*
5985 * MPT base "custom" events may be added here...
5986 */
5987 default:
5988 ds = "Unknown";
5989 break;
5990 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005991 strcpy(evStr,ds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992}
5993
5994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5995/*
5996 * ProcessEventNotification - Route a received EventNotificationReply to
5997 * all currently regeistered event handlers.
5998 * @ioc: Pointer to MPT_ADAPTER structure
5999 * @pEventReply: Pointer to EventNotification reply frame
6000 * @evHandlers: Pointer to integer, number of event handlers
6001 *
6002 * Returns sum of event handlers return values.
6003 */
6004static int
6005ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6006{
6007 u16 evDataLen;
6008 u32 evData0 = 0;
6009// u32 evCtx;
6010 int ii;
6011 int r = 0;
6012 int handlers = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006013 char evStr[100];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 u8 event;
6015
6016 /*
6017 * Do platform normalization of values
6018 */
6019 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6020// evCtx = le32_to_cpu(pEventReply->EventContext);
6021 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6022 if (evDataLen) {
6023 evData0 = le32_to_cpu(pEventReply->Data[0]);
6024 }
6025
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006026 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07006027 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006029 event,
6030 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031
Moore, Eric3a892be2006-03-14 09:14:03 -07006032#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6034 for (ii = 0; ii < evDataLen; ii++)
6035 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6036 printk("\n");
6037#endif
6038
6039 /*
6040 * Do general / base driver event processing
6041 */
6042 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6044 if (evDataLen) {
6045 u8 evState = evData0 & 0xFF;
6046
6047 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6048
6049 /* Update EventState field in cached IocFacts */
6050 if (ioc->facts.Function) {
6051 ioc->facts.EventState = evState;
6052 }
6053 }
6054 break;
Moore, Ericece50912006-01-16 18:53:19 -07006055 case MPI_EVENT_INTEGRATED_RAID:
6056 mptbase_raid_process_event_data(ioc,
6057 (MpiEventDataRaid_t *)pEventReply->Data);
6058 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006059 default:
6060 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061 }
6062
6063 /*
6064 * Should this event be logged? Events are written sequentially.
6065 * When buffer is full, start again at the top.
6066 */
6067 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6068 int idx;
6069
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006070 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071
6072 ioc->events[idx].event = event;
6073 ioc->events[idx].eventContext = ioc->eventContext;
6074
6075 for (ii = 0; ii < 2; ii++) {
6076 if (ii < evDataLen)
6077 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6078 else
6079 ioc->events[idx].data[ii] = 0;
6080 }
6081
6082 ioc->eventContext++;
6083 }
6084
6085
6086 /*
6087 * Call each currently registered protocol event handler.
6088 */
6089 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6090 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006091 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092 ioc->name, ii));
6093 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6094 handlers++;
6095 }
6096 }
6097 /* FIXME? Examine results here? */
6098
6099 /*
6100 * If needed, send (a single) EventAck.
6101 */
6102 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006103 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006104 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006106 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107 ioc->name, ii));
6108 }
6109 }
6110
6111 *evHandlers = handlers;
6112 return r;
6113}
6114
6115/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6116/*
6117 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6118 * @ioc: Pointer to MPT_ADAPTER structure
6119 * @log_info: U32 LogInfo reply word from the IOC
6120 *
6121 * Refer to lsi/fc_log.h.
6122 */
6123static void
6124mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6125{
6126 static char *subcl_str[8] = {
6127 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6128 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6129 };
6130 u8 subcl = (log_info >> 24) & 0x7;
6131
6132 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6133 ioc->name, log_info, subcl_str[subcl]);
6134}
6135
6136/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6137/*
Moore, Eric335a9412006-01-17 17:06:23 -07006138 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139 * @ioc: Pointer to MPT_ADAPTER structure
6140 * @mr: Pointer to MPT reply frame
6141 * @log_info: U32 LogInfo word from the IOC
6142 *
6143 * Refer to lsi/sp_log.h.
6144 */
6145static void
Moore, Eric335a9412006-01-17 17:06:23 -07006146mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147{
6148 u32 info = log_info & 0x00FF0000;
6149 char *desc = "unknown";
6150
6151 switch (info) {
6152 case 0x00010000:
6153 desc = "bug! MID not found";
6154 if (ioc->reload_fw == 0)
6155 ioc->reload_fw++;
6156 break;
6157
6158 case 0x00020000:
6159 desc = "Parity Error";
6160 break;
6161
6162 case 0x00030000:
6163 desc = "ASYNC Outbound Overrun";
6164 break;
6165
6166 case 0x00040000:
6167 desc = "SYNC Offset Error";
6168 break;
6169
6170 case 0x00050000:
6171 desc = "BM Change";
6172 break;
6173
6174 case 0x00060000:
6175 desc = "Msg In Overflow";
6176 break;
6177
6178 case 0x00070000:
6179 desc = "DMA Error";
6180 break;
6181
6182 case 0x00080000:
6183 desc = "Outbound DMA Overrun";
6184 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006185
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186 case 0x00090000:
6187 desc = "Task Management";
6188 break;
6189
6190 case 0x000A0000:
6191 desc = "Device Problem";
6192 break;
6193
6194 case 0x000B0000:
6195 desc = "Invalid Phase Change";
6196 break;
6197
6198 case 0x000C0000:
6199 desc = "Untagged Table Size";
6200 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006201
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202 }
6203
6204 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6205}
6206
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006207/* strings for sas loginfo */
6208 static char *originator_str[] = {
6209 "IOP", /* 00h */
6210 "PL", /* 01h */
6211 "IR" /* 02h */
6212 };
6213 static char *iop_code_str[] = {
6214 NULL, /* 00h */
6215 "Invalid SAS Address", /* 01h */
6216 NULL, /* 02h */
6217 "Invalid Page", /* 03h */
6218 NULL, /* 04h */
6219 "Task Terminated" /* 05h */
6220 };
6221 static char *pl_code_str[] = {
6222 NULL, /* 00h */
6223 "Open Failure", /* 01h */
6224 "Invalid Scatter Gather List", /* 02h */
6225 "Wrong Relative Offset or Frame Length", /* 03h */
6226 "Frame Transfer Error", /* 04h */
6227 "Transmit Frame Connected Low", /* 05h */
6228 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6229 "SATA Read Log Receive Data Error", /* 07h */
6230 "SATA NCQ Fail All Commands After Error", /* 08h */
6231 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6232 "Receive Frame Invalid Message", /* 0Ah */
6233 "Receive Context Message Valid Error", /* 0Bh */
6234 "Receive Frame Current Frame Error", /* 0Ch */
6235 "SATA Link Down", /* 0Dh */
6236 "Discovery SATA Init W IOS", /* 0Eh */
6237 "Config Invalid Page", /* 0Fh */
6238 "Discovery SATA Init Timeout", /* 10h */
6239 "Reset", /* 11h */
6240 "Abort", /* 12h */
6241 "IO Not Yet Executed", /* 13h */
6242 "IO Executed", /* 14h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006243 "Persistant Reservation Out Not Affiliation Owner", /* 15h */
6244 "Open Transmit DMA Abort", /* 16h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006245 NULL, /* 17h */
6246 NULL, /* 18h */
6247 NULL, /* 19h */
6248 NULL, /* 1Ah */
6249 NULL, /* 1Bh */
6250 NULL, /* 1Ch */
6251 NULL, /* 1Dh */
6252 NULL, /* 1Eh */
6253 NULL, /* 1Fh */
6254 "Enclosure Management" /* 20h */
6255 };
6256
6257/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6258/*
6259 * mpt_sas_log_info - Log information returned from SAS IOC.
6260 * @ioc: Pointer to MPT_ADAPTER structure
6261 * @log_info: U32 LogInfo reply word from the IOC
6262 *
6263 * Refer to lsi/mpi_log_sas.h.
6264 */
6265static void
6266mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6267{
6268union loginfo_type {
6269 u32 loginfo;
6270 struct {
6271 u32 subcode:16;
6272 u32 code:8;
6273 u32 originator:4;
6274 u32 bus_type:4;
6275 }dw;
6276};
6277 union loginfo_type sas_loginfo;
6278 char *code_desc = NULL;
6279
6280 sas_loginfo.loginfo = log_info;
6281 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6282 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6283 return;
6284 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6285 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6286 code_desc = iop_code_str[sas_loginfo.dw.code];
6287 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6288 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6289 code_desc = pl_code_str[sas_loginfo.dw.code];
6290 }
6291
6292 if (code_desc != NULL)
6293 printk(MYIOC_s_INFO_FMT
6294 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6295 " SubCode(0x%04x)\n",
6296 ioc->name,
6297 log_info,
6298 originator_str[sas_loginfo.dw.originator],
6299 code_desc,
6300 sas_loginfo.dw.subcode);
6301 else
6302 printk(MYIOC_s_INFO_FMT
6303 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6304 " SubCode(0x%04x)\n",
6305 ioc->name,
6306 log_info,
6307 originator_str[sas_loginfo.dw.originator],
6308 sas_loginfo.dw.code,
6309 sas_loginfo.dw.subcode);
6310}
6311
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6313/*
6314 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6315 * @ioc: Pointer to MPT_ADAPTER structure
6316 * @ioc_status: U32 IOCStatus word from IOC
6317 * @mf: Pointer to MPT request frame
6318 *
6319 * Refer to lsi/mpi.h.
6320 */
6321static void
6322mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6323{
6324 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
6325 char *desc = "";
6326
6327 switch (status) {
6328 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6329 desc = "Invalid Function";
6330 break;
6331
6332 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6333 desc = "Busy";
6334 break;
6335
6336 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6337 desc = "Invalid SGL";
6338 break;
6339
6340 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6341 desc = "Internal Error";
6342 break;
6343
6344 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6345 desc = "Reserved";
6346 break;
6347
6348 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6349 desc = "Insufficient Resources";
6350 break;
6351
6352 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6353 desc = "Invalid Field";
6354 break;
6355
6356 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6357 desc = "Invalid State";
6358 break;
6359
6360 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6361 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6362 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6363 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6364 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6365 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6366 /* No message for Config IOCStatus values */
6367 break;
6368
6369 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6370 /* No message for recovered error
6371 desc = "SCSI Recovered Error";
6372 */
6373 break;
6374
6375 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6376 desc = "SCSI Invalid Bus";
6377 break;
6378
6379 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6380 desc = "SCSI Invalid TargetID";
6381 break;
6382
6383 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6384 {
6385 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6386 U8 cdb = pScsiReq->CDB[0];
6387 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6388 desc = "SCSI Device Not There";
6389 }
6390 break;
6391 }
6392
6393 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6394 desc = "SCSI Data Overrun";
6395 break;
6396
6397 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006398 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399 desc = "SCSI Data Underrun";
6400 */
6401 break;
6402
6403 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6404 desc = "SCSI I/O Data Error";
6405 break;
6406
6407 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6408 desc = "SCSI Protocol Error";
6409 break;
6410
6411 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6412 desc = "SCSI Task Terminated";
6413 break;
6414
6415 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6416 desc = "SCSI Residual Mismatch";
6417 break;
6418
6419 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6420 desc = "SCSI Task Management Failed";
6421 break;
6422
6423 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6424 desc = "SCSI IOC Terminated";
6425 break;
6426
6427 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6428 desc = "SCSI Ext Terminated";
6429 break;
6430
6431 default:
6432 desc = "Others";
6433 break;
6434 }
6435 if (desc != "")
6436 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6437}
6438
6439/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006440EXPORT_SYMBOL(mpt_attach);
6441EXPORT_SYMBOL(mpt_detach);
6442#ifdef CONFIG_PM
6443EXPORT_SYMBOL(mpt_resume);
6444EXPORT_SYMBOL(mpt_suspend);
6445#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006447EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448EXPORT_SYMBOL(mpt_register);
6449EXPORT_SYMBOL(mpt_deregister);
6450EXPORT_SYMBOL(mpt_event_register);
6451EXPORT_SYMBOL(mpt_event_deregister);
6452EXPORT_SYMBOL(mpt_reset_register);
6453EXPORT_SYMBOL(mpt_reset_deregister);
6454EXPORT_SYMBOL(mpt_device_driver_register);
6455EXPORT_SYMBOL(mpt_device_driver_deregister);
6456EXPORT_SYMBOL(mpt_get_msg_frame);
6457EXPORT_SYMBOL(mpt_put_msg_frame);
6458EXPORT_SYMBOL(mpt_free_msg_frame);
6459EXPORT_SYMBOL(mpt_add_sge);
6460EXPORT_SYMBOL(mpt_send_handshake_request);
6461EXPORT_SYMBOL(mpt_verify_adapter);
6462EXPORT_SYMBOL(mpt_GetIocState);
6463EXPORT_SYMBOL(mpt_print_ioc_summary);
6464EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006465EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466EXPORT_SYMBOL(mpt_HardResetHandler);
6467EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006469EXPORT_SYMBOL(mpt_alloc_fw_memory);
6470EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006471EXPORT_SYMBOL(mptbase_sas_persist_operation);
Michael Reed05e8ec12006-01-13 14:31:54 -06006472EXPORT_SYMBOL(mptbase_GetFcPortPage0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474
6475/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6476/*
6477 * fusion_init - Fusion MPT base driver initialization routine.
6478 *
6479 * Returns 0 for success, non-zero for failure.
6480 */
6481static int __init
6482fusion_init(void)
6483{
6484 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006485
6486 show_mptmod_ver(my_NAME, my_VERSION);
6487 printk(KERN_INFO COPYRIGHT "\n");
6488
6489 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6490 MptCallbacks[i] = NULL;
6491 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6492 MptEvHandlers[i] = NULL;
6493 MptResetHandlers[i] = NULL;
6494 }
6495
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006496 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006497 * EventNotification handling.
6498 */
6499 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6500
6501 /* Register for hard reset handling callbacks.
6502 */
6503 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6504 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6505 } else {
6506 /* FIXME! */
6507 }
6508
6509#ifdef CONFIG_PROC_FS
6510 (void) procmpt_create();
6511#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006512 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006513}
6514
6515/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6516/*
6517 * fusion_exit - Perform driver unload cleanup.
6518 *
6519 * This routine frees all resources associated with each MPT adapter
6520 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6521 */
6522static void __exit
6523fusion_exit(void)
6524{
6525
6526 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6527
Linus Torvalds1da177e2005-04-16 15:20:36 -07006528 mpt_reset_deregister(mpt_base_index);
6529
6530#ifdef CONFIG_PROC_FS
6531 procmpt_destroy();
6532#endif
6533}
6534
Linus Torvalds1da177e2005-04-16 15:20:36 -07006535module_init(fusion_init);
6536module_exit(fusion_exit);