blob: 164375eea896fd19001ec320f0c3c6e3c6b8e5ae [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
7 *
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * (mailto:mpt_linux_developer@lsil.com)
10 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
49#include <linux/config.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/kernel.h>
51#include <linux/module.h>
52#include <linux/errno.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/types.h>
56#include <linux/pci.h>
57#include <linux/kdev_t.h>
58#include <linux/blkdev.h>
59#include <linux/delay.h>
60#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040061#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/io.h>
63#ifdef CONFIG_MTRR
64#include <asm/mtrr.h>
65#endif
66#ifdef __sparc__
67#include <asm/irq.h> /* needed for __irq_itoa() proto */
68#endif
69
70#include "mptbase.h"
71
72/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73#define my_NAME "Fusion MPT base driver"
74#define my_VERSION MPT_LINUX_VERSION_COMMON
75#define MYNAM "mptbase"
76
77MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
80
81/*
82 * cmd line parameters
83 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000084static int mpt_msi_enable;
85module_param(mpt_msi_enable, int, 0);
86MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#ifdef MFCNT
89static int mfcounter = 0;
90#define PRINT_MF_COUNT 20000
91#endif
92
93/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
94/*
95 * Public data...
96 */
97int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080098int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Linus Torvaldsf7473072005-11-29 14:21:57 -0800100struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102#define WHOINIT_UNKNOWN 0xAA
103
104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
105/*
106 * Private data...
107 */
108 /* Adapter link list */
109LIST_HEAD(ioc_list);
110 /* Callback lookup table */
111static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
112 /* Protocol driver class lookup table */
113static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
114 /* Event handler lookup table */
115static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
116 /* Reset handler lookup table */
117static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
118static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
119
120static int mpt_base_index = -1;
121static int last_drv_idx = -1;
122
123static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
124
125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
126/*
127 * Forward protos...
128 */
129static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
130static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
131static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
132 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
133 int sleepFlag);
134static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
135static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
136static void mpt_adapter_disable(MPT_ADAPTER *ioc);
137static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
138
139static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
140static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
142static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
143static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
144static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
145static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200146static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
148static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
149static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
150static int PrimeIocFifos(MPT_ADAPTER *ioc);
151static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
152static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
153static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
154static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200156int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
158static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
159static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
160static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
161static void mpt_timer_expired(unsigned long data);
162static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
163static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200164static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
165static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167#ifdef CONFIG_PROC_FS
168static int procmpt_summary_read(char *buf, char **start, off_t offset,
169 int request, int *eof, void *data);
170static int procmpt_version_read(char *buf, char **start, off_t offset,
171 int request, int *eof, void *data);
172static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
173 int request, int *eof, void *data);
174#endif
175static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
176
177//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
178static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
179static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
180static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700181static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600182static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
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 Hellwig82ffb672005-09-09 16:25:54 +0200512 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
513 /* we should be always getting a reply frame */
514 memcpy(ioc->persist_reply_frame, reply,
515 min(MPT_DEFAULT_FRAME_SIZE,
516 4*reply->u.reply.MsgLength));
517 del_timer(&ioc->persist_timer);
518 ioc->persist_wait_done = 1;
519 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 } else {
521 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
522 ioc->name, func);
523 }
524
525 /*
526 * Conditionally tell caller to free the original
527 * EventNotification/EventAck/unexpected request frame!
528 */
529 return freereq;
530}
531
532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
533/**
534 * mpt_register - Register protocol-specific main callback handler.
535 * @cbfunc: callback function pointer
536 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
537 *
538 * This routine is called by a protocol-specific driver (SCSI host,
539 * LAN, SCSI target) to register it's reply callback routine. Each
540 * protocol-specific driver must do this before it will be able to
541 * use any IOC resources, such as obtaining request frames.
542 *
543 * NOTES: The SCSI protocol driver currently calls this routine thrice
544 * in order to register separate callbacks; one for "normal" SCSI IO;
545 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
546 *
547 * Returns a positive integer valued "handle" in the
548 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
549 * Any non-positive return value (including zero!) should be considered
550 * an error by the caller.
551 */
552int
553mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
554{
555 int i;
556
557 last_drv_idx = -1;
558
559 /*
560 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
561 * (slot/handle 0 is reserved!)
562 */
563 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
564 if (MptCallbacks[i] == NULL) {
565 MptCallbacks[i] = cbfunc;
566 MptDriverClass[i] = dclass;
567 MptEvHandlers[i] = NULL;
568 last_drv_idx = i;
569 break;
570 }
571 }
572
573 return last_drv_idx;
574}
575
576/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
577/**
578 * mpt_deregister - Deregister a protocol drivers resources.
579 * @cb_idx: previously registered callback handle
580 *
581 * Each protocol-specific driver should call this routine when it's
582 * module is unloaded.
583 */
584void
585mpt_deregister(int cb_idx)
586{
587 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
588 MptCallbacks[cb_idx] = NULL;
589 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
590 MptEvHandlers[cb_idx] = NULL;
591
592 last_drv_idx++;
593 }
594}
595
596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
597/**
598 * mpt_event_register - Register protocol-specific event callback
599 * handler.
600 * @cb_idx: previously registered (via mpt_register) callback handle
601 * @ev_cbfunc: callback function
602 *
603 * This routine can be called by one or more protocol-specific drivers
604 * if/when they choose to be notified of MPT events.
605 *
606 * Returns 0 for success.
607 */
608int
609mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
610{
611 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
612 return -1;
613
614 MptEvHandlers[cb_idx] = ev_cbfunc;
615 return 0;
616}
617
618/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
619/**
620 * mpt_event_deregister - Deregister protocol-specific event callback
621 * handler.
622 * @cb_idx: previously registered callback handle
623 *
624 * Each protocol-specific driver should call this routine
625 * when it does not (or can no longer) handle events,
626 * or when it's module is unloaded.
627 */
628void
629mpt_event_deregister(int cb_idx)
630{
631 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
632 return;
633
634 MptEvHandlers[cb_idx] = NULL;
635}
636
637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
638/**
639 * mpt_reset_register - Register protocol-specific IOC reset handler.
640 * @cb_idx: previously registered (via mpt_register) callback handle
641 * @reset_func: reset function
642 *
643 * This routine can be called by one or more protocol-specific drivers
644 * if/when they choose to be notified of IOC resets.
645 *
646 * Returns 0 for success.
647 */
648int
649mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
650{
651 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
652 return -1;
653
654 MptResetHandlers[cb_idx] = reset_func;
655 return 0;
656}
657
658/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
659/**
660 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
661 * @cb_idx: previously registered callback handle
662 *
663 * Each protocol-specific driver should call this routine
664 * when it does not (or can no longer) handle IOC reset handling,
665 * or when it's module is unloaded.
666 */
667void
668mpt_reset_deregister(int cb_idx)
669{
670 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
671 return;
672
673 MptResetHandlers[cb_idx] = NULL;
674}
675
676/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
677/**
678 * mpt_device_driver_register - Register device driver hooks
679 */
680int
681mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
682{
683 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400686 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688
689 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
690
691 /* call per pci device probe entry point */
692 list_for_each_entry(ioc, &ioc_list, list) {
693 if(dd_cbfunc->probe) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400694 dd_cbfunc->probe(ioc->pcidev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 ioc->pcidev->driver->id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 }
697 }
698
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400699 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
702/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
703/**
704 * mpt_device_driver_deregister - DeRegister device driver hooks
705 */
706void
707mpt_device_driver_deregister(int cb_idx)
708{
709 struct mpt_pci_driver *dd_cbfunc;
710 MPT_ADAPTER *ioc;
711
712 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
713 return;
714
715 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
716
717 list_for_each_entry(ioc, &ioc_list, list) {
718 if (dd_cbfunc->remove)
719 dd_cbfunc->remove(ioc->pcidev);
720 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 MptDeviceDriverHandlers[cb_idx] = NULL;
723}
724
725
726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
727/**
728 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
729 * allocated per MPT adapter.
730 * @handle: Handle of registered MPT protocol driver
731 * @ioc: Pointer to MPT adapter structure
732 *
733 * Returns pointer to a MPT request frame or %NULL if none are available
734 * or IOC is not active.
735 */
736MPT_FRAME_HDR*
737mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
738{
739 MPT_FRAME_HDR *mf;
740 unsigned long flags;
741 u16 req_idx; /* Request index */
742
743 /* validate handle and ioc identifier */
744
745#ifdef MFCNT
746 if (!ioc->active)
747 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
748#endif
749
750 /* If interrupts are not attached, do not return a request frame */
751 if (!ioc->active)
752 return NULL;
753
754 spin_lock_irqsave(&ioc->FreeQlock, flags);
755 if (!list_empty(&ioc->FreeQ)) {
756 int req_offset;
757
758 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
759 u.frame.linkage.list);
760 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200761 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
763 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
764 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500765 req_idx = req_offset / ioc->req_sz;
766 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
768 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
769#ifdef MFCNT
770 ioc->mfcnt++;
771#endif
772 }
773 else
774 mf = NULL;
775 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
776
777#ifdef MFCNT
778 if (mf == NULL)
779 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
780 mfcounter++;
781 if (mfcounter == PRINT_MF_COUNT)
782 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
783#endif
784
785 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
786 ioc->name, handle, ioc->id, mf));
787 return mf;
788}
789
790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
791/**
792 * mpt_put_msg_frame - Send a protocol specific MPT request frame
793 * to a IOC.
794 * @handle: Handle of registered MPT protocol driver
795 * @ioc: Pointer to MPT adapter structure
796 * @mf: Pointer to MPT request frame
797 *
798 * This routine posts a MPT request frame to the request post FIFO of a
799 * specific MPT adapter.
800 */
801void
802mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
803{
804 u32 mf_dma_addr;
805 int req_offset;
806 u16 req_idx; /* Request index */
807
808 /* ensure values are reset properly! */
809 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
810 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
811 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500812 req_idx = req_offset / ioc->req_sz;
813 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
815
816#ifdef MPT_DEBUG_MSG_FRAME
817 {
818 u32 *m = mf->u.frame.hwhdr.__hdr;
819 int ii, n;
820
821 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
822 ioc->name, m);
823 n = ioc->req_sz/4 - 1;
824 while (m[n] == 0)
825 n--;
826 for (ii=0; ii<=n; ii++) {
827 if (ii && ((ii%8)==0))
828 printk("\n" KERN_INFO " ");
829 printk(" %08x", le32_to_cpu(m[ii]));
830 }
831 printk("\n");
832 }
833#endif
834
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200835 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
837 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
838}
839
840/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
841/**
842 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
843 * @handle: Handle of registered MPT protocol driver
844 * @ioc: Pointer to MPT adapter structure
845 * @mf: Pointer to MPT request frame
846 *
847 * This routine places a MPT request frame back on the MPT adapter's
848 * FreeQ.
849 */
850void
851mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
852{
853 unsigned long flags;
854
855 /* Put Request back on FreeQ! */
856 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200857 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
859#ifdef MFCNT
860 ioc->mfcnt--;
861#endif
862 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
863}
864
865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
866/**
867 * mpt_add_sge - Place a simple SGE at address pAddr.
868 * @pAddr: virtual address for SGE
869 * @flagslength: SGE flags and data transfer length
870 * @dma_addr: Physical address
871 *
872 * This routine places a MPT request frame back on the MPT adapter's
873 * FreeQ.
874 */
875void
876mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
877{
878 if (sizeof(dma_addr_t) == sizeof(u64)) {
879 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
880 u32 tmp = dma_addr & 0xFFFFFFFF;
881
882 pSge->FlagsLength = cpu_to_le32(flagslength);
883 pSge->Address.Low = cpu_to_le32(tmp);
884 tmp = (u32) ((u64)dma_addr >> 32);
885 pSge->Address.High = cpu_to_le32(tmp);
886
887 } else {
888 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
889 pSge->FlagsLength = cpu_to_le32(flagslength);
890 pSge->Address = cpu_to_le32(dma_addr);
891 }
892}
893
894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
895/**
896 * mpt_send_handshake_request - Send MPT request via doorbell
897 * handshake method.
898 * @handle: Handle of registered MPT protocol driver
899 * @ioc: Pointer to MPT adapter structure
900 * @reqBytes: Size of the request in bytes
901 * @req: Pointer to MPT request frame
902 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
903 *
904 * This routine is used exclusively to send MptScsiTaskMgmt
905 * requests since they are required to be sent via doorbell handshake.
906 *
907 * NOTE: It is the callers responsibility to byte-swap fields in the
908 * request which are greater than 1 byte in size.
909 *
910 * Returns 0 for success, non-zero for failure.
911 */
912int
913mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
914{
915 int r = 0;
916 u8 *req_as_bytes;
917 int ii;
918
919 /* State is known to be good upon entering
920 * this function so issue the bus reset
921 * request.
922 */
923
924 /*
925 * Emulate what mpt_put_msg_frame() does /wrt to sanity
926 * setting cb_idx/req_idx. But ONLY if this request
927 * is in proper (pre-alloc'd) request buffer range...
928 */
929 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
930 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
931 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
932 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
933 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
934 }
935
936 /* Make sure there are no doorbells */
937 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 CHIPREG_WRITE32(&ioc->chip->Doorbell,
940 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
941 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
942
943 /* Wait for IOC doorbell int */
944 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
945 return ii;
946 }
947
948 /* Read doorbell and check for active bit */
949 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
950 return -5;
951
952 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200953 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
956
957 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
958 return -2;
959 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 /* Send request via doorbell handshake */
962 req_as_bytes = (u8 *) req;
963 for (ii = 0; ii < reqBytes/4; ii++) {
964 u32 word;
965
966 word = ((req_as_bytes[(ii*4) + 0] << 0) |
967 (req_as_bytes[(ii*4) + 1] << 8) |
968 (req_as_bytes[(ii*4) + 2] << 16) |
969 (req_as_bytes[(ii*4) + 3] << 24));
970 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
971 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
972 r = -3;
973 break;
974 }
975 }
976
977 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
978 r = 0;
979 else
980 r = -4;
981
982 /* Make sure there are no doorbells */
983 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return r;
986}
987
988/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
989/**
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200990 * mpt_host_page_access_control - provides mechanism for the host
991 * driver to control the IOC's Host Page Buffer access.
992 * @ioc: Pointer to MPT adapter structure
993 * @access_control_value: define bits below
994 *
995 * Access Control Value - bits[15:12]
996 * 0h Reserved
997 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
998 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
999 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1000 *
1001 * Returns 0 for success, non-zero for failure.
1002 */
1003
1004static int
1005mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1006{
1007 int r = 0;
1008
1009 /* return if in use */
1010 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1011 & MPI_DOORBELL_ACTIVE)
1012 return -1;
1013
1014 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1015
1016 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1017 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1018 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1019 (access_control_value<<12)));
1020
1021 /* Wait for IOC to clear Doorbell Status bit */
1022 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1023 return -2;
1024 }else
1025 return 0;
1026}
1027
1028/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1029/**
1030 * mpt_host_page_alloc - allocate system memory for the fw
1031 * If we already allocated memory in past, then resend the same pointer.
1032 * ioc@: Pointer to pointer to IOC adapter
1033 * ioc_init@: Pointer to ioc init config page
1034 *
1035 * Returns 0 for success, non-zero for failure.
1036 */
1037static int
1038mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1039{
1040 char *psge;
1041 int flags_length;
1042 u32 host_page_buffer_sz=0;
1043
1044 if(!ioc->HostPageBuffer) {
1045
1046 host_page_buffer_sz =
1047 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1048
1049 if(!host_page_buffer_sz)
1050 return 0; /* fw doesn't need any host buffers */
1051
1052 /* spin till we get enough memory */
1053 while(host_page_buffer_sz > 0) {
1054
1055 if((ioc->HostPageBuffer = pci_alloc_consistent(
1056 ioc->pcidev,
1057 host_page_buffer_sz,
1058 &ioc->HostPageBuffer_dma)) != NULL) {
1059
1060 dinitprintk((MYIOC_s_INFO_FMT
1061 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
1062 ioc->name,
1063 ioc->HostPageBuffer,
1064 ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001065 host_page_buffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001066 ioc->alloc_total += host_page_buffer_sz;
1067 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1068 break;
1069 }
1070
1071 host_page_buffer_sz -= (4*1024);
1072 }
1073 }
1074
1075 if(!ioc->HostPageBuffer) {
1076 printk(MYIOC_s_ERR_FMT
1077 "Failed to alloc memory for host_page_buffer!\n",
1078 ioc->name);
1079 return -999;
1080 }
1081
1082 psge = (char *)&ioc_init->HostPageBufferSGE;
1083 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1084 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1085 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1086 MPI_SGE_FLAGS_HOST_TO_IOC |
1087 MPI_SGE_FLAGS_END_OF_BUFFER;
1088 if (sizeof(dma_addr_t) == sizeof(u64)) {
1089 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1090 }
1091 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1092 flags_length |= ioc->HostPageBuffer_sz;
1093 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1094 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1095
1096return 0;
1097}
1098
1099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1100/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
1102 * the associated MPT adapter structure.
1103 * @iocid: IOC unique identifier (integer)
1104 * @iocpp: Pointer to pointer to IOC adapter
1105 *
1106 * Returns iocid and sets iocpp.
1107 */
1108int
1109mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1110{
1111 MPT_ADAPTER *ioc;
1112
1113 list_for_each_entry(ioc,&ioc_list,list) {
1114 if (ioc->id == iocid) {
1115 *iocpp =ioc;
1116 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 *iocpp = NULL;
1121 return -1;
1122}
1123
1124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1125/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001126 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 * @pdev: Pointer to pci_dev structure
1128 *
1129 * This routine performs all the steps necessary to bring the IOC of
1130 * a MPT adapter to a OPERATIONAL state. This includes registering
1131 * memory regions, registering the interrupt, and allocating request
1132 * and reply memory pools.
1133 *
1134 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1135 * MPT adapter.
1136 *
1137 * Returns 0 for success, non-zero for failure.
1138 *
1139 * TODO: Add support for polled controllers
1140 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001141int
1142mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
1144 MPT_ADAPTER *ioc;
1145 u8 __iomem *mem;
1146 unsigned long mem_phys;
1147 unsigned long port;
1148 u32 msize;
1149 u32 psize;
1150 int ii;
1151 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 u8 revision;
1153 u8 pcixcmd;
1154 static int mpt_ids = 0;
1155#ifdef CONFIG_PROC_FS
1156 struct proc_dir_entry *dent, *ent;
1157#endif
1158
1159 if (pci_enable_device(pdev))
1160 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001163
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001164 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 dprintk((KERN_INFO MYNAM
1166 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001167 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1169 return r;
1170 }
1171
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001172 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 dprintk((KERN_INFO MYNAM
1174 ": Using 64 bit consistent mask\n"));
1175 else
1176 dprintk((KERN_INFO MYNAM
1177 ": Not using 64 bit consistent mask\n"));
1178
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001179 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 if (ioc == NULL) {
1181 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1182 return -ENOMEM;
1183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 ioc->alloc_total = sizeof(MPT_ADAPTER);
1185 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1186 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 ioc->pcidev = pdev;
1189 ioc->diagPending = 0;
1190 spin_lock_init(&ioc->diagLock);
Michael Reed05e8ec12006-01-13 14:31:54 -06001191 spin_lock_init(&ioc->fc_rescan_work_lock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001192 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
1194 /* Initialize the event logging.
1195 */
1196 ioc->eventTypes = 0; /* None */
1197 ioc->eventContext = 0;
1198 ioc->eventLogSize = 0;
1199 ioc->events = NULL;
1200
1201#ifdef MFCNT
1202 ioc->mfcnt = 0;
1203#endif
1204
1205 ioc->cached_fw = NULL;
1206
1207 /* Initilize SCSI Config Data structure
1208 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001209 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211 /* Initialize the running configQ head.
1212 */
1213 INIT_LIST_HEAD(&ioc->configQ);
1214
Michael Reed05e8ec12006-01-13 14:31:54 -06001215 /* Initialize the fc rport list head.
1216 */
1217 INIT_LIST_HEAD(&ioc->fc_rports);
1218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 /* Find lookup slot. */
1220 INIT_LIST_HEAD(&ioc->list);
1221 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 mem_phys = msize = 0;
1224 port = psize = 0;
1225 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1226 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1227 /* Get I/O space! */
1228 port = pci_resource_start(pdev, ii);
1229 psize = pci_resource_len(pdev,ii);
1230 } else {
1231 /* Get memmap */
1232 mem_phys = pci_resource_start(pdev, ii);
1233 msize = pci_resource_len(pdev,ii);
1234 break;
1235 }
1236 }
1237 ioc->mem_size = msize;
1238
1239 if (ii == DEVICE_COUNT_RESOURCE) {
1240 printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
1241 kfree(ioc);
1242 return -EINVAL;
1243 }
1244
1245 dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
1246 dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
1247
1248 mem = NULL;
1249 /* Get logical ptr for PciMem0 space */
1250 /*mem = ioremap(mem_phys, msize);*/
1251 mem = ioremap(mem_phys, 0x100);
1252 if (mem == NULL) {
1253 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1254 kfree(ioc);
1255 return -EINVAL;
1256 }
1257 ioc->memmap = mem;
1258 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1259
1260 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1261 &ioc->facts, &ioc->pfacts[0]));
1262
1263 ioc->mem_phys = mem_phys;
1264 ioc->chip = (SYSIF_REGS __iomem *)mem;
1265
1266 /* Save Port IO values in case we need to do downloadboot */
1267 {
1268 u8 *pmem = (u8*)port;
1269 ioc->pio_mem_phys = port;
1270 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1271 }
1272
1273 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1274 ioc->prod_name = "LSIFC909";
1275 ioc->bus_type = FC;
1276 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001277 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 ioc->prod_name = "LSIFC929";
1279 ioc->bus_type = FC;
1280 }
1281 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1282 ioc->prod_name = "LSIFC919";
1283 ioc->bus_type = FC;
1284 }
1285 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1286 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1287 ioc->bus_type = FC;
1288 if (revision < XL_929) {
1289 ioc->prod_name = "LSIFC929X";
1290 /* 929X Chip Fix. Set Split transactions level
1291 * for PCIX. Set MOST bits to zero.
1292 */
1293 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1294 pcixcmd &= 0x8F;
1295 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1296 } else {
1297 ioc->prod_name = "LSIFC929XL";
1298 /* 929XL Chip Fix. Set MMRBC to 0x08.
1299 */
1300 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1301 pcixcmd |= 0x08;
1302 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1303 }
1304 }
1305 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1306 ioc->prod_name = "LSIFC919X";
1307 ioc->bus_type = FC;
1308 /* 919X Chip Fix. Set Split transactions level
1309 * for PCIX. Set MOST bits to zero.
1310 */
1311 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1312 pcixcmd &= 0x8F;
1313 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1314 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001315 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1316 ioc->prod_name = "LSIFC939X";
1317 ioc->bus_type = FC;
1318 ioc->errata_flag_1064 = 1;
1319 }
1320 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1321 ioc->prod_name = "LSIFC949X";
1322 ioc->bus_type = FC;
1323 ioc->errata_flag_1064 = 1;
1324 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001325 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1326 ioc->prod_name = "LSIFC949E";
1327 ioc->bus_type = FC;
1328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1330 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001331 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 /* 1030 Chip Fix. Disable Split transactions
1333 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1334 */
1335 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1336 if (revision < C0_1030) {
1337 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1338 pcixcmd &= 0x8F;
1339 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1340 }
1341 }
1342 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1343 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001344 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001346 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1347 ioc->prod_name = "LSISAS1064";
1348 ioc->bus_type = SAS;
1349 ioc->errata_flag_1064 = 1;
1350 }
1351 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) {
1352 ioc->prod_name = "LSISAS1066";
1353 ioc->bus_type = SAS;
1354 ioc->errata_flag_1064 = 1;
1355 }
1356 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1357 ioc->prod_name = "LSISAS1068";
1358 ioc->bus_type = SAS;
1359 ioc->errata_flag_1064 = 1;
1360 }
1361 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1362 ioc->prod_name = "LSISAS1064E";
1363 ioc->bus_type = SAS;
1364 }
1365 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) {
1366 ioc->prod_name = "LSISAS1066E";
1367 ioc->bus_type = SAS;
1368 }
1369 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1370 ioc->prod_name = "LSISAS1068E";
1371 ioc->bus_type = SAS;
1372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001374 if (ioc->errata_flag_1064)
1375 pci_disable_io_access(pdev);
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 sprintf(ioc->name, "ioc%d", ioc->id);
1378
1379 spin_lock_init(&ioc->FreeQlock);
1380
1381 /* Disable all! */
1382 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1383 ioc->active = 0;
1384 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1385
1386 /* Set lookup ptr. */
1387 list_add_tail(&ioc->list, &ioc_list);
1388
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001389 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 */
1391 mpt_detect_bound_ports(ioc, pdev);
1392
James Bottomleyc92f2222006-03-01 09:02:49 -06001393 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1394 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 printk(KERN_WARNING MYNAM
1396 ": WARNING - %s did not initialize properly! (%d)\n",
1397 ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001399 if (ioc->alt_ioc)
1400 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 iounmap(mem);
1402 kfree(ioc);
1403 pci_set_drvdata(pdev, NULL);
1404 return r;
1405 }
1406
1407 /* call per device driver probe entry point */
1408 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1409 if(MptDeviceDriverHandlers[ii] &&
1410 MptDeviceDriverHandlers[ii]->probe) {
1411 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1412 }
1413 }
1414
1415#ifdef CONFIG_PROC_FS
1416 /*
1417 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1418 */
1419 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1420 if (dent) {
1421 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1422 if (ent) {
1423 ent->read_proc = procmpt_iocinfo_read;
1424 ent->data = ioc;
1425 }
1426 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1427 if (ent) {
1428 ent->read_proc = procmpt_summary_read;
1429 ent->data = ioc;
1430 }
1431 }
1432#endif
1433
1434 return 0;
1435}
1436
1437/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1438/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001439 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 * @pdev: Pointer to pci_dev structure
1441 *
1442 */
1443
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001444void
1445mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446{
1447 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1448 char pname[32];
1449 int ii;
1450
1451 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1452 remove_proc_entry(pname, NULL);
1453 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1454 remove_proc_entry(pname, NULL);
1455 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1456 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001457
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 /* call per device driver remove entry point */
1459 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1460 if(MptDeviceDriverHandlers[ii] &&
1461 MptDeviceDriverHandlers[ii]->remove) {
1462 MptDeviceDriverHandlers[ii]->remove(pdev);
1463 }
1464 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001465
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 /* Disable interrupts! */
1467 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1468
1469 ioc->active = 0;
1470 synchronize_irq(pdev->irq);
1471
1472 /* Clear any lingering interrupt */
1473 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1474
1475 CHIPREG_READ32(&ioc->chip->IntStatus);
1476
1477 mpt_adapter_dispose(ioc);
1478
1479 pci_set_drvdata(pdev, NULL);
1480}
1481
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482/**************************************************************************
1483 * Power Management
1484 */
1485#ifdef CONFIG_PM
1486/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1487/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001488 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 *
1490 *
1491 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001492int
1493mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
1495 u32 device_state;
1496 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
Pavel Machek2a569572005-07-07 17:56:40 -07001498 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
1500 printk(MYIOC_s_INFO_FMT
1501 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1502 ioc->name, pdev, pci_name(pdev), device_state);
1503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 pci_save_state(pdev);
1505
1506 /* put ioc into READY_STATE */
1507 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1508 printk(MYIOC_s_ERR_FMT
1509 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1510 }
1511
1512 /* disable interrupts */
1513 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1514 ioc->active = 0;
1515
1516 /* Clear any lingering interrupt */
1517 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1518
1519 pci_disable_device(pdev);
1520 pci_set_power_state(pdev, device_state);
1521
1522 return 0;
1523}
1524
1525/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1526/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001527 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 *
1529 *
1530 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001531int
1532mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533{
1534 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1535 u32 device_state = pdev->current_state;
1536 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001537
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 printk(MYIOC_s_INFO_FMT
1539 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1540 ioc->name, pdev, pci_name(pdev), device_state);
1541
1542 pci_set_power_state(pdev, 0);
1543 pci_restore_state(pdev);
1544 pci_enable_device(pdev);
1545
1546 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001547 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 ioc->active = 1;
1549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 printk(MYIOC_s_INFO_FMT
1551 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1552 ioc->name,
1553 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1554 CHIPREG_READ32(&ioc->chip->Doorbell));
1555
1556 /* bring ioc to operational state */
1557 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1558 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1559 printk(MYIOC_s_INFO_FMT
1560 "pci-resume: Cannot recover, error:[%x]\n",
1561 ioc->name, recovery_state);
1562 } else {
1563 printk(MYIOC_s_INFO_FMT
1564 "pci-resume: success\n", ioc->name);
1565 }
1566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 return 0;
1568}
1569#endif
1570
James Bottomley4ff42a62006-05-17 18:06:52 -05001571static int
1572mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1573{
1574 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1575 ioc->bus_type != SPI) ||
1576 (MptDriverClass[index] == MPTFC_DRIVER &&
1577 ioc->bus_type != FC) ||
1578 (MptDriverClass[index] == MPTSAS_DRIVER &&
1579 ioc->bus_type != SAS))
1580 /* make sure we only call the relevant reset handler
1581 * for the bus */
1582 return 0;
1583 return (MptResetHandlers[index])(ioc, reset_phase);
1584}
1585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1587/*
1588 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1589 * @ioc: Pointer to MPT adapter structure
1590 * @reason: Event word / reason
1591 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1592 *
1593 * This routine performs all the steps necessary to bring the IOC
1594 * to a OPERATIONAL state.
1595 *
1596 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1597 * MPT adapter.
1598 *
1599 * Returns:
1600 * 0 for success
1601 * -1 if failed to get board READY
1602 * -2 if READY but IOCFacts Failed
1603 * -3 if READY but PrimeIOCFifos Failed
1604 * -4 if READY but IOCInit Failed
1605 */
1606static int
1607mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1608{
1609 int hard_reset_done = 0;
1610 int alt_ioc_ready = 0;
1611 int hard;
1612 int rc=0;
1613 int ii;
1614 int handlers;
1615 int ret = 0;
1616 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001617 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
1619 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1620 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1621
1622 /* Disable reply interrupts (also blocks FreeQ) */
1623 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1624 ioc->active = 0;
1625
1626 if (ioc->alt_ioc) {
1627 if (ioc->alt_ioc->active)
1628 reset_alt_ioc_active = 1;
1629
1630 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1631 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1632 ioc->alt_ioc->active = 0;
1633 }
1634
1635 hard = 1;
1636 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1637 hard = 0;
1638
1639 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1640 if (hard_reset_done == -4) {
1641 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1642 ioc->name);
1643
1644 if (reset_alt_ioc_active && ioc->alt_ioc) {
1645 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1646 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1647 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001648 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 ioc->alt_ioc->active = 1;
1650 }
1651
1652 } else {
1653 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1654 ioc->name);
1655 }
1656 return -1;
1657 }
1658
1659 /* hard_reset_done = 0 if a soft reset was performed
1660 * and 1 if a hard reset was performed.
1661 */
1662 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1663 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1664 alt_ioc_ready = 1;
1665 else
1666 printk(KERN_WARNING MYNAM
1667 ": alt-%s: Not ready WARNING!\n",
1668 ioc->alt_ioc->name);
1669 }
1670
1671 for (ii=0; ii<5; ii++) {
1672 /* Get IOC facts! Allow 5 retries */
1673 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1674 break;
1675 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
1678 if (ii == 5) {
1679 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1680 ret = -2;
1681 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1682 MptDisplayIocCapabilities(ioc);
1683 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 if (alt_ioc_ready) {
1686 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1687 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1688 /* Retry - alt IOC was initialized once
1689 */
1690 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1691 }
1692 if (rc) {
1693 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1694 alt_ioc_ready = 0;
1695 reset_alt_ioc_active = 0;
1696 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1697 MptDisplayIocCapabilities(ioc->alt_ioc);
1698 }
1699 }
1700
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001701 /*
1702 * Device is reset now. It must have de-asserted the interrupt line
1703 * (if it was asserted) and it should be safe to register for the
1704 * interrupt now.
1705 */
1706 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1707 ioc->pci_irq = -1;
1708 if (ioc->pcidev->irq) {
1709 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1710 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1711 ioc->name);
1712 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
1713 SA_SHIRQ, ioc->name, ioc);
1714 if (rc < 0) {
1715#ifndef __sparc__
1716 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1717 "interrupt %d!\n", ioc->name,
1718 ioc->pcidev->irq);
1719#else
1720 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1721 "interrupt %s!\n", ioc->name,
1722 __irq_itoa(ioc->pcidev->irq));
1723#endif
1724 if (mpt_msi_enable)
1725 pci_disable_msi(ioc->pcidev);
1726 return -EBUSY;
1727 }
1728 irq_allocated = 1;
1729 ioc->pci_irq = ioc->pcidev->irq;
1730 pci_set_master(ioc->pcidev); /* ?? */
1731 pci_set_drvdata(ioc->pcidev, ioc);
1732#ifndef __sparc__
1733 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1734 "%d\n", ioc->name, ioc->pcidev->irq));
1735#else
1736 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1737 "%s\n", ioc->name,
1738 __irq_itoa(ioc->pcidev->irq)));
1739#endif
1740 }
1741 }
1742
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 /* Prime reply & request queues!
1744 * (mucho alloc's) Must be done prior to
1745 * init as upper addresses are needed for init.
1746 * If fails, continue with alt-ioc processing
1747 */
1748 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1749 ret = -3;
1750
1751 /* May need to check/upload firmware & data here!
1752 * If fails, continue with alt-ioc processing
1753 */
1754 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1755 ret = -4;
1756// NEW!
1757 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1758 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1759 ioc->alt_ioc->name, rc);
1760 alt_ioc_ready = 0;
1761 reset_alt_ioc_active = 0;
1762 }
1763
1764 if (alt_ioc_ready) {
1765 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1766 alt_ioc_ready = 0;
1767 reset_alt_ioc_active = 0;
1768 printk(KERN_WARNING MYNAM
1769 ": alt-%s: (%d) init failure WARNING!\n",
1770 ioc->alt_ioc->name, rc);
1771 }
1772 }
1773
1774 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1775 if (ioc->upload_fw) {
1776 ddlprintk((MYIOC_s_INFO_FMT
1777 "firmware upload required!\n", ioc->name));
1778
1779 /* Controller is not operational, cannot do upload
1780 */
1781 if (ret == 0) {
1782 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001783 if (rc == 0) {
1784 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1785 /*
1786 * Maintain only one pointer to FW memory
1787 * so there will not be two attempt to
1788 * downloadboot onboard dual function
1789 * chips (mpt_adapter_disable,
1790 * mpt_diag_reset)
1791 */
1792 ioc->cached_fw = NULL;
1793 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1794 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1795 }
1796 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001798 ret = -5;
1799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 }
1801 }
1802 }
1803
1804 if (ret == 0) {
1805 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001806 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 ioc->active = 1;
1808 }
1809
1810 if (reset_alt_ioc_active && ioc->alt_ioc) {
1811 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001812 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001814 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 ioc->alt_ioc->active = 1;
1816 }
1817
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001818 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 * and EventAck handling.
1820 */
1821 if ((ret == 0) && (!ioc->facts.EventState))
1822 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1823
1824 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1825 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1826
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001827 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1829 * recursive scenario; GetLanConfigPages times out, timer expired
1830 * routine calls HardResetHandler, which calls into here again,
1831 * and we try GetLanConfigPages again...
1832 */
1833 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001834 if (ioc->bus_type == SAS) {
1835
1836 /* clear persistency table */
1837 if(ioc->facts.IOCExceptions &
1838 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1839 ret = mptbase_sas_persist_operation(ioc,
1840 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1841 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001842 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001843 }
1844
1845 /* Find IM volumes
1846 */
1847 mpt_findImVolumes(ioc);
1848
1849 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 /*
1851 * Pre-fetch FC port WWN and stuff...
1852 * (FCPortPage0_t stuff)
1853 */
1854 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
Michael Reed05e8ec12006-01-13 14:31:54 -06001855 (void) mptbase_GetFcPortPage0(ioc, ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 }
1857
1858 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1859 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1860 /*
1861 * Pre-fetch the ports LAN MAC address!
1862 * (LANPage1_t stuff)
1863 */
1864 (void) GetLanConfigPages(ioc);
1865#ifdef MPT_DEBUG
1866 {
1867 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1868 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1869 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1870 }
1871#endif
1872 }
1873 } else {
1874 /* Get NVRAM and adapter maximums from SPP 0 and 2
1875 */
1876 mpt_GetScsiPortSettings(ioc, 0);
1877
1878 /* Get version and length of SDP 1
1879 */
1880 mpt_readScsiDevicePageHeaders(ioc, 0);
1881
1882 /* Find IM volumes
1883 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001884 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 mpt_findImVolumes(ioc);
1886
1887 /* Check, and possibly reset, the coalescing value
1888 */
1889 mpt_read_ioc_pg_1(ioc);
1890
1891 mpt_read_ioc_pg_4(ioc);
1892 }
1893
1894 GetIoUnitPage2(ioc);
1895 }
1896
1897 /*
1898 * Call each currently registered protocol IOC reset handler
1899 * with post-reset indication.
1900 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1901 * MptResetHandlers[] registered yet.
1902 */
1903 if (hard_reset_done) {
1904 rc = handlers = 0;
1905 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1906 if ((ret == 0) && MptResetHandlers[ii]) {
1907 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1908 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001909 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 handlers++;
1911 }
1912
1913 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001914 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001916 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 handlers++;
1918 }
1919 }
1920 /* FIXME? Examine results here? */
1921 }
1922
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001923out:
1924 if ((ret != 0) && irq_allocated) {
1925 free_irq(ioc->pci_irq, ioc);
1926 if (mpt_msi_enable)
1927 pci_disable_msi(ioc->pcidev);
1928 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 return ret;
1930}
1931
1932/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1933/*
1934 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1935 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1936 * 929X, 1030 or 1035.
1937 * @ioc: Pointer to MPT adapter structure
1938 * @pdev: Pointer to (struct pci_dev) structure
1939 *
1940 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1941 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1942 */
1943static void
1944mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1945{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001946 struct pci_dev *peer=NULL;
1947 unsigned int slot = PCI_SLOT(pdev->devfn);
1948 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 MPT_ADAPTER *ioc_srch;
1950
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001951 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1952 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001953 ioc->name, pci_name(pdev), pdev->bus->number,
1954 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001955
1956 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1957 if (!peer) {
1958 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1959 if (!peer)
1960 return;
1961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962
1963 list_for_each_entry(ioc_srch, &ioc_list, list) {
1964 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001965 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 /* Paranoia checks */
1967 if (ioc->alt_ioc != NULL) {
1968 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001969 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 break;
1971 } else if (ioc_srch->alt_ioc != NULL) {
1972 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001973 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 break;
1975 }
1976 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001977 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 ioc_srch->alt_ioc = ioc;
1979 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 }
1981 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001982 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983}
1984
1985/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1986/*
1987 * mpt_adapter_disable - Disable misbehaving MPT adapter.
1988 * @this: Pointer to MPT adapter structure
1989 */
1990static void
1991mpt_adapter_disable(MPT_ADAPTER *ioc)
1992{
1993 int sz;
1994 int ret;
1995
1996 if (ioc->cached_fw != NULL) {
1997 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001998 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 printk(KERN_WARNING MYNAM
2000 ": firmware downloadboot failure (%d)!\n", ret);
2001 }
2002 }
2003
2004 /* Disable adapter interrupts! */
2005 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2006 ioc->active = 0;
2007 /* Clear any lingering interrupt */
2008 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2009
2010 if (ioc->alloc != NULL) {
2011 sz = ioc->alloc_sz;
2012 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
2013 ioc->name, ioc->alloc, ioc->alloc_sz));
2014 pci_free_consistent(ioc->pcidev, sz,
2015 ioc->alloc, ioc->alloc_dma);
2016 ioc->reply_frames = NULL;
2017 ioc->req_frames = NULL;
2018 ioc->alloc = NULL;
2019 ioc->alloc_total -= sz;
2020 }
2021
2022 if (ioc->sense_buf_pool != NULL) {
2023 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2024 pci_free_consistent(ioc->pcidev, sz,
2025 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2026 ioc->sense_buf_pool = NULL;
2027 ioc->alloc_total -= sz;
2028 }
2029
2030 if (ioc->events != NULL){
2031 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2032 kfree(ioc->events);
2033 ioc->events = NULL;
2034 ioc->alloc_total -= sz;
2035 }
2036
2037 if (ioc->cached_fw != NULL) {
2038 sz = ioc->facts.FWImageSize;
2039 pci_free_consistent(ioc->pcidev, sz,
2040 ioc->cached_fw, ioc->cached_fw_dma);
2041 ioc->cached_fw = NULL;
2042 ioc->alloc_total -= sz;
2043 }
2044
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002045 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002046 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002047 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002048 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
2050 if (ioc->spi_data.pIocPg4 != NULL) {
2051 sz = ioc->spi_data.IocPg4Sz;
2052 pci_free_consistent(ioc->pcidev, sz,
2053 ioc->spi_data.pIocPg4,
2054 ioc->spi_data.IocPg4_dma);
2055 ioc->spi_data.pIocPg4 = NULL;
2056 ioc->alloc_total -= sz;
2057 }
2058
2059 if (ioc->ReqToChain != NULL) {
2060 kfree(ioc->ReqToChain);
2061 kfree(ioc->RequestNB);
2062 ioc->ReqToChain = NULL;
2063 }
2064
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002065 kfree(ioc->ChainToChain);
2066 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002067
2068 if (ioc->HostPageBuffer != NULL) {
2069 if((ret = mpt_host_page_access_control(ioc,
2070 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2071 printk(KERN_ERR MYNAM
2072 ": %s: host page buffers free failed (%d)!\n",
2073 __FUNCTION__, ret);
2074 }
2075 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2076 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2077 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2078 ioc->HostPageBuffer,
2079 ioc->HostPageBuffer_dma);
2080 ioc->HostPageBuffer = NULL;
2081 ioc->HostPageBuffer_sz = 0;
2082 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084}
2085
2086/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2087/*
2088 * mpt_adapter_dispose - Free all resources associated with a MPT
2089 * adapter.
2090 * @ioc: Pointer to MPT adapter structure
2091 *
2092 * This routine unregisters h/w resources and frees all alloc'd memory
2093 * associated with a MPT adapter structure.
2094 */
2095static void
2096mpt_adapter_dispose(MPT_ADAPTER *ioc)
2097{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002098 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002100 if (ioc == NULL)
2101 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002103 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002105 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002107 if (ioc->pci_irq != -1) {
2108 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002109 if (mpt_msi_enable)
2110 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002111 ioc->pci_irq = -1;
2112 }
2113
2114 if (ioc->memmap != NULL) {
2115 iounmap(ioc->memmap);
2116 ioc->memmap = NULL;
2117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
2119#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002120 if (ioc->mtrr_reg > 0) {
2121 mtrr_del(ioc->mtrr_reg, 0, 0);
2122 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124#endif
2125
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002126 /* Zap the adapter lookup ptr! */
2127 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002129 sz_last = ioc->alloc_total;
2130 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2131 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002132
2133 if (ioc->alt_ioc)
2134 ioc->alt_ioc->alt_ioc = NULL;
2135
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002136 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137}
2138
2139/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2140/*
2141 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2142 * @ioc: Pointer to MPT adapter structure
2143 */
2144static void
2145MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2146{
2147 int i = 0;
2148
2149 printk(KERN_INFO "%s: ", ioc->name);
2150 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2151 printk("%s: ", ioc->prod_name+3);
2152 printk("Capabilities={");
2153
2154 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2155 printk("Initiator");
2156 i++;
2157 }
2158
2159 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2160 printk("%sTarget", i ? "," : "");
2161 i++;
2162 }
2163
2164 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2165 printk("%sLAN", i ? "," : "");
2166 i++;
2167 }
2168
2169#if 0
2170 /*
2171 * This would probably evoke more questions than it's worth
2172 */
2173 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2174 printk("%sLogBusAddr", i ? "," : "");
2175 i++;
2176 }
2177#endif
2178
2179 printk("}\n");
2180}
2181
2182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2183/*
2184 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2185 * @ioc: Pointer to MPT_ADAPTER structure
2186 * @force: Force hard KickStart of IOC
2187 * @sleepFlag: Specifies whether the process can sleep
2188 *
2189 * Returns:
2190 * 1 - DIAG reset and READY
2191 * 0 - READY initially OR soft reset and READY
2192 * -1 - Any failure on KickStart
2193 * -2 - Msg Unit Reset Failed
2194 * -3 - IO Unit Reset Failed
2195 * -4 - IOC owned by a PEER
2196 */
2197static int
2198MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2199{
2200 u32 ioc_state;
2201 int statefault = 0;
2202 int cntdn;
2203 int hard_reset_done = 0;
2204 int r;
2205 int ii;
2206 int whoinit;
2207
2208 /* Get current [raw] IOC state */
2209 ioc_state = mpt_GetIocState(ioc, 0);
2210 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2211
2212 /*
2213 * Check to see if IOC got left/stuck in doorbell handshake
2214 * grip of death. If so, hard reset the IOC.
2215 */
2216 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2217 statefault = 1;
2218 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2219 ioc->name);
2220 }
2221
2222 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002223 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 return 0;
2225
2226 /*
2227 * Check to see if IOC is in FAULT state.
2228 */
2229 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2230 statefault = 2;
2231 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2232 ioc->name);
2233 printk(KERN_WARNING " FAULT code = %04xh\n",
2234 ioc_state & MPI_DOORBELL_DATA_MASK);
2235 }
2236
2237 /*
2238 * Hmmm... Did it get left operational?
2239 */
2240 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002241 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 ioc->name));
2243
2244 /* Check WhoInit.
2245 * If PCI Peer, exit.
2246 * Else, if no fault conditions are present, issue a MessageUnitReset
2247 * Else, fall through to KickStart case
2248 */
2249 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002250 dinitprintk((KERN_INFO MYNAM
2251 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 whoinit, statefault, force));
2253 if (whoinit == MPI_WHOINIT_PCI_PEER)
2254 return -4;
2255 else {
2256 if ((statefault == 0 ) && (force == 0)) {
2257 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2258 return 0;
2259 }
2260 statefault = 3;
2261 }
2262 }
2263
2264 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2265 if (hard_reset_done < 0)
2266 return -1;
2267
2268 /*
2269 * Loop here waiting for IOC to come READY.
2270 */
2271 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002272 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273
2274 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2275 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2276 /*
2277 * BIOS or previous driver load left IOC in OP state.
2278 * Reset messaging FIFOs.
2279 */
2280 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2281 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2282 return -2;
2283 }
2284 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2285 /*
2286 * Something is wrong. Try to get IOC back
2287 * to a known state.
2288 */
2289 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2290 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2291 return -3;
2292 }
2293 }
2294
2295 ii++; cntdn--;
2296 if (!cntdn) {
2297 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2298 ioc->name, (int)((ii+5)/HZ));
2299 return -ETIME;
2300 }
2301
2302 if (sleepFlag == CAN_SLEEP) {
2303 msleep_interruptible(1);
2304 } else {
2305 mdelay (1); /* 1 msec delay */
2306 }
2307
2308 }
2309
2310 if (statefault < 3) {
2311 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2312 ioc->name,
2313 statefault==1 ? "stuck handshake" : "IOC FAULT");
2314 }
2315
2316 return hard_reset_done;
2317}
2318
2319/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2320/*
2321 * mpt_GetIocState - Get the current state of a MPT adapter.
2322 * @ioc: Pointer to MPT_ADAPTER structure
2323 * @cooked: Request raw or cooked IOC state
2324 *
2325 * Returns all IOC Doorbell register bits if cooked==0, else just the
2326 * Doorbell bits in MPI_IOC_STATE_MASK.
2327 */
2328u32
2329mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2330{
2331 u32 s, sc;
2332
2333 /* Get! */
2334 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2335// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2336 sc = s & MPI_IOC_STATE_MASK;
2337
2338 /* Save! */
2339 ioc->last_state = sc;
2340
2341 return cooked ? sc : s;
2342}
2343
2344/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2345/*
2346 * GetIocFacts - Send IOCFacts request to MPT adapter.
2347 * @ioc: Pointer to MPT_ADAPTER structure
2348 * @sleepFlag: Specifies whether the process can sleep
2349 * @reason: If recovery, only update facts.
2350 *
2351 * Returns 0 for success, non-zero for failure.
2352 */
2353static int
2354GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2355{
2356 IOCFacts_t get_facts;
2357 IOCFactsReply_t *facts;
2358 int r;
2359 int req_sz;
2360 int reply_sz;
2361 int sz;
2362 u32 status, vv;
2363 u8 shiftFactor=1;
2364
2365 /* IOC *must* NOT be in RESET state! */
2366 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2367 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2368 ioc->name,
2369 ioc->last_state );
2370 return -44;
2371 }
2372
2373 facts = &ioc->facts;
2374
2375 /* Destination (reply area)... */
2376 reply_sz = sizeof(*facts);
2377 memset(facts, 0, reply_sz);
2378
2379 /* Request area (get_facts on the stack right now!) */
2380 req_sz = sizeof(get_facts);
2381 memset(&get_facts, 0, req_sz);
2382
2383 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2384 /* Assert: All other get_facts fields are zero! */
2385
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002386 dinitprintk((MYIOC_s_INFO_FMT
2387 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 ioc->name, req_sz, reply_sz));
2389
2390 /* No non-zero fields in the get_facts request are greater than
2391 * 1 byte in size, so we can just fire it off as is.
2392 */
2393 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2394 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2395 if (r != 0)
2396 return r;
2397
2398 /*
2399 * Now byte swap (GRRR) the necessary fields before any further
2400 * inspection of reply contents.
2401 *
2402 * But need to do some sanity checks on MsgLength (byte) field
2403 * to make sure we don't zero IOC's req_sz!
2404 */
2405 /* Did we get a valid reply? */
2406 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2407 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2408 /*
2409 * If not been here, done that, save off first WhoInit value
2410 */
2411 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2412 ioc->FirstWhoInit = facts->WhoInit;
2413 }
2414
2415 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2416 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2417 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2418 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2419 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002420 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 /* CHECKME! IOCStatus, IOCLogInfo */
2422
2423 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2424 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2425
2426 /*
2427 * FC f/w version changed between 1.1 and 1.2
2428 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2429 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2430 */
2431 if (facts->MsgVersion < 0x0102) {
2432 /*
2433 * Handle old FC f/w style, convert to new...
2434 */
2435 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2436 facts->FWVersion.Word =
2437 ((oldv<<12) & 0xFF000000) |
2438 ((oldv<<8) & 0x000FFF00);
2439 } else
2440 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2441
2442 facts->ProductID = le16_to_cpu(facts->ProductID);
2443 facts->CurrentHostMfaHighAddr =
2444 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2445 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2446 facts->CurrentSenseBufferHighAddr =
2447 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2448 facts->CurReplyFrameSize =
2449 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002450 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
2452 /*
2453 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2454 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2455 * to 14 in MPI-1.01.0x.
2456 */
2457 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2458 facts->MsgVersion > 0x0100) {
2459 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2460 }
2461
2462 sz = facts->FWImageSize;
2463 if ( sz & 0x01 )
2464 sz += 1;
2465 if ( sz & 0x02 )
2466 sz += 2;
2467 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002468
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 if (!facts->RequestFrameSize) {
2470 /* Something is wrong! */
2471 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2472 ioc->name);
2473 return -55;
2474 }
2475
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002476 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 vv = ((63 / (sz * 4)) + 1) & 0x03;
2478 ioc->NB_for_64_byte_frame = vv;
2479 while ( sz )
2480 {
2481 shiftFactor++;
2482 sz = sz >> 1;
2483 }
2484 ioc->NBShiftFactor = shiftFactor;
2485 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2486 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002487
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2489 /*
2490 * Set values for this IOC's request & reply frame sizes,
2491 * and request & reply queue depths...
2492 */
2493 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2494 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2495 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2496 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2497
2498 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2499 ioc->name, ioc->reply_sz, ioc->reply_depth));
2500 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2501 ioc->name, ioc->req_sz, ioc->req_depth));
2502
2503 /* Get port facts! */
2504 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2505 return r;
2506 }
2507 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002508 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2510 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2511 RequestFrameSize)/sizeof(u32)));
2512 return -66;
2513 }
2514
2515 return 0;
2516}
2517
2518/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2519/*
2520 * GetPortFacts - Send PortFacts request to MPT adapter.
2521 * @ioc: Pointer to MPT_ADAPTER structure
2522 * @portnum: Port number
2523 * @sleepFlag: Specifies whether the process can sleep
2524 *
2525 * Returns 0 for success, non-zero for failure.
2526 */
2527static int
2528GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2529{
2530 PortFacts_t get_pfacts;
2531 PortFactsReply_t *pfacts;
2532 int ii;
2533 int req_sz;
2534 int reply_sz;
2535
2536 /* IOC *must* NOT be in RESET state! */
2537 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2538 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2539 ioc->name,
2540 ioc->last_state );
2541 return -4;
2542 }
2543
2544 pfacts = &ioc->pfacts[portnum];
2545
2546 /* Destination (reply area)... */
2547 reply_sz = sizeof(*pfacts);
2548 memset(pfacts, 0, reply_sz);
2549
2550 /* Request area (get_pfacts on the stack right now!) */
2551 req_sz = sizeof(get_pfacts);
2552 memset(&get_pfacts, 0, req_sz);
2553
2554 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2555 get_pfacts.PortNumber = portnum;
2556 /* Assert: All other get_pfacts fields are zero! */
2557
2558 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2559 ioc->name, portnum));
2560
2561 /* No non-zero fields in the get_pfacts request are greater than
2562 * 1 byte in size, so we can just fire it off as is.
2563 */
2564 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2565 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2566 if (ii != 0)
2567 return ii;
2568
2569 /* Did we get a valid reply? */
2570
2571 /* Now byte swap the necessary fields in the response. */
2572 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2573 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2574 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2575 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2576 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2577 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2578 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2579 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2580 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2581
2582 return 0;
2583}
2584
2585/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2586/*
2587 * SendIocInit - Send IOCInit request to MPT adapter.
2588 * @ioc: Pointer to MPT_ADAPTER structure
2589 * @sleepFlag: Specifies whether the process can sleep
2590 *
2591 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2592 *
2593 * Returns 0 for success, non-zero for failure.
2594 */
2595static int
2596SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2597{
2598 IOCInit_t ioc_init;
2599 MPIDefaultReply_t init_reply;
2600 u32 state;
2601 int r;
2602 int count;
2603 int cntdn;
2604
2605 memset(&ioc_init, 0, sizeof(ioc_init));
2606 memset(&init_reply, 0, sizeof(init_reply));
2607
2608 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2609 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2610
2611 /* If we are in a recovery mode and we uploaded the FW image,
2612 * then this pointer is not NULL. Skip the upload a second time.
2613 * Set this flag if cached_fw set for either IOC.
2614 */
2615 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2616 ioc->upload_fw = 1;
2617 else
2618 ioc->upload_fw = 0;
2619 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2620 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2621
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002622 if(ioc->bus_type == SAS)
2623 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2624 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2626 else
2627 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002629 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2630 ioc->name, ioc->facts.MsgVersion));
2631 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2632 // set MsgVersion and HeaderVersion host driver was built with
2633 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2634 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002636 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2637 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2638 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2639 return -99;
2640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2642
2643 if (sizeof(dma_addr_t) == sizeof(u64)) {
2644 /* Save the upper 32-bits of the request
2645 * (reply) and sense buffers.
2646 */
2647 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2648 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2649 } else {
2650 /* Force 32-bit addressing */
2651 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2652 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2653 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002654
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2656 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002657 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2658 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
2660 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2661 ioc->name, &ioc_init));
2662
2663 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2664 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002665 if (r != 0) {
2666 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
2670 /* No need to byte swap the multibyte fields in the reply
2671 * since we don't even look at it's contents.
2672 */
2673
2674 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2675 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002676
2677 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2678 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
2682 /* YIKES! SUPER IMPORTANT!!!
2683 * Poll IocState until _OPERATIONAL while IOC is doing
2684 * LoopInit and TargetDiscovery!
2685 */
2686 count = 0;
2687 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2688 state = mpt_GetIocState(ioc, 1);
2689 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2690 if (sleepFlag == CAN_SLEEP) {
2691 msleep_interruptible(1);
2692 } else {
2693 mdelay(1);
2694 }
2695
2696 if (!cntdn) {
2697 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2698 ioc->name, (int)((count+5)/HZ));
2699 return -9;
2700 }
2701
2702 state = mpt_GetIocState(ioc, 1);
2703 count++;
2704 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002705 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 ioc->name, count));
2707
2708 return r;
2709}
2710
2711/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2712/*
2713 * SendPortEnable - Send PortEnable request to MPT adapter port.
2714 * @ioc: Pointer to MPT_ADAPTER structure
2715 * @portnum: Port number to enable
2716 * @sleepFlag: Specifies whether the process can sleep
2717 *
2718 * Send PortEnable to bring IOC to OPERATIONAL state.
2719 *
2720 * Returns 0 for success, non-zero for failure.
2721 */
2722static int
2723SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2724{
2725 PortEnable_t port_enable;
2726 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002727 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 int req_sz;
2729 int reply_sz;
2730
2731 /* Destination... */
2732 reply_sz = sizeof(MPIDefaultReply_t);
2733 memset(&reply_buf, 0, reply_sz);
2734
2735 req_sz = sizeof(PortEnable_t);
2736 memset(&port_enable, 0, req_sz);
2737
2738 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2739 port_enable.PortNumber = portnum;
2740/* port_enable.ChainOffset = 0; */
2741/* port_enable.MsgFlags = 0; */
2742/* port_enable.MsgContext = 0; */
2743
2744 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2745 ioc->name, portnum, &port_enable));
2746
2747 /* RAID FW may take a long time to enable
2748 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002749 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2750 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2751 (ioc->bus_type == SAS)) {
2752 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2753 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2754 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002755 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002756 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2757 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2758 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002760 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761}
2762
2763/*
2764 * ioc: Pointer to MPT_ADAPTER structure
2765 * size - total FW bytes
2766 */
2767void
2768mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2769{
2770 if (ioc->cached_fw)
2771 return; /* use already allocated memory */
2772 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2773 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2774 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2775 } else {
2776 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2777 ioc->alloc_total += size;
2778 }
2779}
2780/*
2781 * If alt_img is NULL, delete from ioc structure.
2782 * Else, delete a secondary image in same format.
2783 */
2784void
2785mpt_free_fw_memory(MPT_ADAPTER *ioc)
2786{
2787 int sz;
2788
2789 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002790 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2792 pci_free_consistent(ioc->pcidev, sz,
2793 ioc->cached_fw, ioc->cached_fw_dma);
2794 ioc->cached_fw = NULL;
2795
2796 return;
2797}
2798
2799
2800/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2801/*
2802 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2803 * @ioc: Pointer to MPT_ADAPTER structure
2804 * @sleepFlag: Specifies whether the process can sleep
2805 *
2806 * Returns 0 for success, >0 for handshake failure
2807 * <0 for fw upload failure.
2808 *
2809 * Remark: If bound IOC and a successful FWUpload was performed
2810 * on the bound IOC, the second image is discarded
2811 * and memory is free'd. Both channels must upload to prevent
2812 * IOC from running in degraded mode.
2813 */
2814static int
2815mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2816{
2817 u8 request[ioc->req_sz];
2818 u8 reply[sizeof(FWUploadReply_t)];
2819 FWUpload_t *prequest;
2820 FWUploadReply_t *preply;
2821 FWUploadTCSGE_t *ptcsge;
2822 int sgeoffset;
2823 u32 flagsLength;
2824 int ii, sz, reply_sz;
2825 int cmdStatus;
2826
2827 /* If the image size is 0, we are done.
2828 */
2829 if ((sz = ioc->facts.FWImageSize) == 0)
2830 return 0;
2831
2832 mpt_alloc_fw_memory(ioc, sz);
2833
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002834 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002836
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 if (ioc->cached_fw == NULL) {
2838 /* Major Failure.
2839 */
2840 return -ENOMEM;
2841 }
2842
2843 prequest = (FWUpload_t *)&request;
2844 preply = (FWUploadReply_t *)&reply;
2845
2846 /* Destination... */
2847 memset(prequest, 0, ioc->req_sz);
2848
2849 reply_sz = sizeof(reply);
2850 memset(preply, 0, reply_sz);
2851
2852 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2853 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2854
2855 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2856 ptcsge->DetailsLength = 12;
2857 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2858 ptcsge->ImageSize = cpu_to_le32(sz);
2859
2860 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2861
2862 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2863 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2864
2865 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002866 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 prequest, sgeoffset));
2868 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2869
2870 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2871 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2872
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002873 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
2875 cmdStatus = -EFAULT;
2876 if (ii == 0) {
2877 /* Handshake transfer was complete and successful.
2878 * Check the Reply Frame.
2879 */
2880 int status, transfer_sz;
2881 status = le16_to_cpu(preply->IOCStatus);
2882 if (status == MPI_IOCSTATUS_SUCCESS) {
2883 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2884 if (transfer_sz == sz)
2885 cmdStatus = 0;
2886 }
2887 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002888 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 ioc->name, cmdStatus));
2890
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002891
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 if (cmdStatus) {
2893
2894 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2895 ioc->name));
2896 mpt_free_fw_memory(ioc);
2897 }
2898
2899 return cmdStatus;
2900}
2901
2902/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2903/*
2904 * mpt_downloadboot - DownloadBoot code
2905 * @ioc: Pointer to MPT_ADAPTER structure
2906 * @flag: Specify which part of IOC memory is to be uploaded.
2907 * @sleepFlag: Specifies whether the process can sleep
2908 *
2909 * FwDownloadBoot requires Programmed IO access.
2910 *
2911 * Returns 0 for success
2912 * -1 FW Image size is 0
2913 * -2 No valid cached_fw Pointer
2914 * <0 for fw upload failure.
2915 */
2916static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002917mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 MpiExtImageHeader_t *pExtImage;
2920 u32 fwSize;
2921 u32 diag0val;
2922 int count;
2923 u32 *ptrFw;
2924 u32 diagRwData;
2925 u32 nextImage;
2926 u32 load_addr;
2927 u32 ioc_state=0;
2928
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002929 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2930 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002931
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2933 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2934 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2935 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2936 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2937 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2938
2939 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2940
2941 /* wait 1 msec */
2942 if (sleepFlag == CAN_SLEEP) {
2943 msleep_interruptible(1);
2944 } else {
2945 mdelay (1);
2946 }
2947
2948 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2949 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2950
2951 for (count = 0; count < 30; count ++) {
2952 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2953 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2954 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2955 ioc->name, count));
2956 break;
2957 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002958 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002960 msleep_interruptible (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002962 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 }
2964 }
2965
2966 if ( count == 30 ) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002967 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2968 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 ioc->name, diag0val));
2970 return -3;
2971 }
2972
2973 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2974 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2975 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2976 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2977 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2978 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2979
2980 /* Set the DiagRwEn and Disable ARM bits */
2981 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2982
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 fwSize = (pFwHeader->ImageSize + 3)/4;
2984 ptrFw = (u32 *) pFwHeader;
2985
2986 /* Write the LoadStartAddress to the DiagRw Address Register
2987 * using Programmed IO
2988 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002989 if (ioc->errata_flag_1064)
2990 pci_enable_io_access(ioc->pcidev);
2991
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2993 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2994 ioc->name, pFwHeader->LoadStartAddress));
2995
2996 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2997 ioc->name, fwSize*4, ptrFw));
2998 while (fwSize--) {
2999 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3000 }
3001
3002 nextImage = pFwHeader->NextImageHeaderOffset;
3003 while (nextImage) {
3004 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3005
3006 load_addr = pExtImage->LoadStartAddress;
3007
3008 fwSize = (pExtImage->ImageSize + 3) >> 2;
3009 ptrFw = (u32 *)pExtImage;
3010
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003011 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
3012 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3014
3015 while (fwSize--) {
3016 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3017 }
3018 nextImage = pExtImage->NextImageHeaderOffset;
3019 }
3020
3021 /* Write the IopResetVectorRegAddr */
3022 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3023 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3024
3025 /* Write the IopResetVectorValue */
3026 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3027 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3028
3029 /* Clear the internal flash bad bit - autoincrementing register,
3030 * so must do two writes.
3031 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003032 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003033 /*
3034 * 1030 and 1035 H/W errata, workaround to access
3035 * the ClearFlashBadSignatureBit
3036 */
3037 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3038 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3039 diagRwData |= 0x40000000;
3040 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3041 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3042
3043 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3044 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3045 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3046 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3047
3048 /* wait 1 msec */
3049 if (sleepFlag == CAN_SLEEP) {
3050 msleep_interruptible (1);
3051 } else {
3052 mdelay (1);
3053 }
3054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003056 if (ioc->errata_flag_1064)
3057 pci_disable_io_access(ioc->pcidev);
3058
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003060 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3061 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003063 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3065 ioc->name, diag0val));
3066 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3067
3068 /* Write 0xFF to reset the sequencer */
3069 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3070
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003071 if (ioc->bus_type == SAS) {
3072 ioc_state = mpt_GetIocState(ioc, 0);
3073 if ( (GetIocFacts(ioc, sleepFlag,
3074 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3075 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3076 ioc->name, ioc_state));
3077 return -EFAULT;
3078 }
3079 }
3080
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 for (count=0; count<HZ*20; count++) {
3082 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3083 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3084 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003085 if (ioc->bus_type == SAS) {
3086 return 0;
3087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3089 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3090 ioc->name));
3091 return -EFAULT;
3092 }
3093 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3094 ioc->name));
3095 return 0;
3096 }
3097 if (sleepFlag == CAN_SLEEP) {
3098 msleep_interruptible (10);
3099 } else {
3100 mdelay (10);
3101 }
3102 }
3103 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3104 ioc->name, ioc_state));
3105 return -EFAULT;
3106}
3107
3108/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3109/*
3110 * KickStart - Perform hard reset of MPT adapter.
3111 * @ioc: Pointer to MPT_ADAPTER structure
3112 * @force: Force hard reset
3113 * @sleepFlag: Specifies whether the process can sleep
3114 *
3115 * This routine places MPT adapter in diagnostic mode via the
3116 * WriteSequence register, and then performs a hard reset of adapter
3117 * via the Diagnostic register.
3118 *
3119 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3120 * or NO_SLEEP (interrupt thread, use mdelay)
3121 * force - 1 if doorbell active, board fault state
3122 * board operational, IOC_RECOVERY or
3123 * IOC_BRINGUP and there is an alt_ioc.
3124 * 0 else
3125 *
3126 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003127 * 1 - hard reset, READY
3128 * 0 - no reset due to History bit, READY
3129 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 * OR reset but failed to come READY
3131 * -2 - no reset, could not enter DIAG mode
3132 * -3 - reset but bad FW bit
3133 */
3134static int
3135KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3136{
3137 int hard_reset_done = 0;
3138 u32 ioc_state=0;
3139 int cnt,cntdn;
3140
3141 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003142 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 /* Always issue a Msg Unit Reset first. This will clear some
3144 * SCSI bus hang conditions.
3145 */
3146 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3147
3148 if (sleepFlag == CAN_SLEEP) {
3149 msleep_interruptible (1000);
3150 } else {
3151 mdelay (1000);
3152 }
3153 }
3154
3155 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3156 if (hard_reset_done < 0)
3157 return hard_reset_done;
3158
3159 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3160 ioc->name));
3161
3162 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3163 for (cnt=0; cnt<cntdn; cnt++) {
3164 ioc_state = mpt_GetIocState(ioc, 1);
3165 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3166 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3167 ioc->name, cnt));
3168 return hard_reset_done;
3169 }
3170 if (sleepFlag == CAN_SLEEP) {
3171 msleep_interruptible (10);
3172 } else {
3173 mdelay (10);
3174 }
3175 }
3176
3177 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3178 ioc->name, ioc_state);
3179 return -1;
3180}
3181
3182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3183/*
3184 * mpt_diag_reset - Perform hard reset of the adapter.
3185 * @ioc: Pointer to MPT_ADAPTER structure
3186 * @ignore: Set if to honor and clear to ignore
3187 * the reset history bit
3188 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3189 * else set to NO_SLEEP (use mdelay instead)
3190 *
3191 * This routine places the adapter in diagnostic mode via the
3192 * WriteSequence register and then performs a hard reset of adapter
3193 * via the Diagnostic register. Adapter should be in ready state
3194 * upon successful completion.
3195 *
3196 * Returns: 1 hard reset successful
3197 * 0 no reset performed because reset history bit set
3198 * -2 enabling diagnostic mode failed
3199 * -3 diagnostic reset failed
3200 */
3201static int
3202mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3203{
3204 u32 diag0val;
3205 u32 doorbell;
3206 int hard_reset_done = 0;
3207 int count = 0;
3208#ifdef MPT_DEBUG
3209 u32 diag1val = 0;
3210#endif
3211
3212 /* Clear any existing interrupts */
3213 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3214
3215 /* Use "Diagnostic reset" method! (only thing available!) */
3216 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3217
3218#ifdef MPT_DEBUG
3219 if (ioc->alt_ioc)
3220 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3221 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3222 ioc->name, diag0val, diag1val));
3223#endif
3224
3225 /* Do the reset if we are told to ignore the reset history
3226 * or if the reset history is 0
3227 */
3228 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3229 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3230 /* Write magic sequence to WriteSequence register
3231 * Loop until in diagnostic mode
3232 */
3233 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3234 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3235 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3236 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3237 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3238 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3239
3240 /* wait 100 msec */
3241 if (sleepFlag == CAN_SLEEP) {
3242 msleep_interruptible (100);
3243 } else {
3244 mdelay (100);
3245 }
3246
3247 count++;
3248 if (count > 20) {
3249 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3250 ioc->name, diag0val);
3251 return -2;
3252
3253 }
3254
3255 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3256
3257 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3258 ioc->name, diag0val));
3259 }
3260
3261#ifdef MPT_DEBUG
3262 if (ioc->alt_ioc)
3263 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3264 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3265 ioc->name, diag0val, diag1val));
3266#endif
3267 /*
3268 * Disable the ARM (Bug fix)
3269 *
3270 */
3271 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003272 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273
3274 /*
3275 * Now hit the reset bit in the Diagnostic register
3276 * (THE BIG HAMMER!) (Clears DRWE bit).
3277 */
3278 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3279 hard_reset_done = 1;
3280 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3281 ioc->name));
3282
3283 /*
3284 * Call each currently registered protocol IOC reset handler
3285 * with pre-reset indication.
3286 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3287 * MptResetHandlers[] registered yet.
3288 */
3289 {
3290 int ii;
3291 int r = 0;
3292
3293 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3294 if (MptResetHandlers[ii]) {
3295 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3296 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003297 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 if (ioc->alt_ioc) {
3299 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3300 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003301 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 }
3303 }
3304 }
3305 /* FIXME? Examine results here? */
3306 }
3307
3308 if (ioc->cached_fw) {
3309 /* If the DownloadBoot operation fails, the
3310 * IOC will be left unusable. This is a fatal error
3311 * case. _diag_reset will return < 0
3312 */
3313 for (count = 0; count < 30; count ++) {
3314 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3315 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3316 break;
3317 }
3318
3319 /* wait 1 sec */
3320 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003321 msleep_interruptible (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 } else {
3323 mdelay (1000);
3324 }
3325 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003326 if ((count = mpt_downloadboot(ioc,
3327 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 printk(KERN_WARNING MYNAM
3329 ": firmware downloadboot failure (%d)!\n", count);
3330 }
3331
3332 } else {
3333 /* Wait for FW to reload and for board
3334 * to go to the READY state.
3335 * Maximum wait is 60 seconds.
3336 * If fail, no error will check again
3337 * with calling program.
3338 */
3339 for (count = 0; count < 60; count ++) {
3340 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3341 doorbell &= MPI_IOC_STATE_MASK;
3342
3343 if (doorbell == MPI_IOC_STATE_READY) {
3344 break;
3345 }
3346
3347 /* wait 1 sec */
3348 if (sleepFlag == CAN_SLEEP) {
3349 msleep_interruptible (1000);
3350 } else {
3351 mdelay (1000);
3352 }
3353 }
3354 }
3355 }
3356
3357 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3358#ifdef MPT_DEBUG
3359 if (ioc->alt_ioc)
3360 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3361 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3362 ioc->name, diag0val, diag1val));
3363#endif
3364
3365 /* Clear RESET_HISTORY bit! Place board in the
3366 * diagnostic mode to update the diag register.
3367 */
3368 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3369 count = 0;
3370 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3371 /* Write magic sequence to WriteSequence register
3372 * Loop until in diagnostic mode
3373 */
3374 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3375 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3376 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3377 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3378 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3379 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3380
3381 /* wait 100 msec */
3382 if (sleepFlag == CAN_SLEEP) {
3383 msleep_interruptible (100);
3384 } else {
3385 mdelay (100);
3386 }
3387
3388 count++;
3389 if (count > 20) {
3390 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3391 ioc->name, diag0val);
3392 break;
3393 }
3394 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3395 }
3396 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3397 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3398 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3399 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3400 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3401 ioc->name);
3402 }
3403
3404 /* Disable Diagnostic Mode
3405 */
3406 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3407
3408 /* Check FW reload status flags.
3409 */
3410 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3411 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3412 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3413 ioc->name, diag0val);
3414 return -3;
3415 }
3416
3417#ifdef MPT_DEBUG
3418 if (ioc->alt_ioc)
3419 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3420 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3421 ioc->name, diag0val, diag1val));
3422#endif
3423
3424 /*
3425 * Reset flag that says we've enabled event notification
3426 */
3427 ioc->facts.EventState = 0;
3428
3429 if (ioc->alt_ioc)
3430 ioc->alt_ioc->facts.EventState = 0;
3431
3432 return hard_reset_done;
3433}
3434
3435/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3436/*
3437 * SendIocReset - Send IOCReset request to MPT adapter.
3438 * @ioc: Pointer to MPT_ADAPTER structure
3439 * @reset_type: reset type, expected values are
3440 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3441 *
3442 * Send IOCReset request to the MPT adapter.
3443 *
3444 * Returns 0 for success, non-zero for failure.
3445 */
3446static int
3447SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3448{
3449 int r;
3450 u32 state;
3451 int cntdn, count;
3452
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003453 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 ioc->name, reset_type));
3455 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3456 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3457 return r;
3458
3459 /* FW ACK'd request, wait for READY state
3460 */
3461 count = 0;
3462 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3463
3464 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3465 cntdn--;
3466 count++;
3467 if (!cntdn) {
3468 if (sleepFlag != CAN_SLEEP)
3469 count *= 10;
3470
3471 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3472 ioc->name, (int)((count+5)/HZ));
3473 return -ETIME;
3474 }
3475
3476 if (sleepFlag == CAN_SLEEP) {
3477 msleep_interruptible(1);
3478 } else {
3479 mdelay (1); /* 1 msec delay */
3480 }
3481 }
3482
3483 /* TODO!
3484 * Cleanup all event stuff for this IOC; re-issue EventNotification
3485 * request if needed.
3486 */
3487 if (ioc->facts.Function)
3488 ioc->facts.EventState = 0;
3489
3490 return 0;
3491}
3492
3493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3494/*
3495 * initChainBuffers - Allocate memory for and initialize
3496 * chain buffers, chain buffer control arrays and spinlock.
3497 * @hd: Pointer to MPT_SCSI_HOST structure
3498 * @init: If set, initialize the spin lock.
3499 */
3500static int
3501initChainBuffers(MPT_ADAPTER *ioc)
3502{
3503 u8 *mem;
3504 int sz, ii, num_chain;
3505 int scale, num_sge, numSGE;
3506
3507 /* ReqToChain size must equal the req_depth
3508 * index = req_idx
3509 */
3510 if (ioc->ReqToChain == NULL) {
3511 sz = ioc->req_depth * sizeof(int);
3512 mem = kmalloc(sz, GFP_ATOMIC);
3513 if (mem == NULL)
3514 return -1;
3515
3516 ioc->ReqToChain = (int *) mem;
3517 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3518 ioc->name, mem, sz));
3519 mem = kmalloc(sz, GFP_ATOMIC);
3520 if (mem == NULL)
3521 return -1;
3522
3523 ioc->RequestNB = (int *) mem;
3524 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3525 ioc->name, mem, sz));
3526 }
3527 for (ii = 0; ii < ioc->req_depth; ii++) {
3528 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3529 }
3530
3531 /* ChainToChain size must equal the total number
3532 * of chain buffers to be allocated.
3533 * index = chain_idx
3534 *
3535 * Calculate the number of chain buffers needed(plus 1) per I/O
3536 * then multiply the the maximum number of simultaneous cmds
3537 *
3538 * num_sge = num sge in request frame + last chain buffer
3539 * scale = num sge per chain buffer if no chain element
3540 */
3541 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3542 if (sizeof(dma_addr_t) == sizeof(u64))
3543 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3544 else
3545 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3546
3547 if (sizeof(dma_addr_t) == sizeof(u64)) {
3548 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3549 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3550 } else {
3551 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3552 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3553 }
3554 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3555 ioc->name, num_sge, numSGE));
3556
3557 if ( numSGE > MPT_SCSI_SG_DEPTH )
3558 numSGE = MPT_SCSI_SG_DEPTH;
3559
3560 num_chain = 1;
3561 while (numSGE - num_sge > 0) {
3562 num_chain++;
3563 num_sge += (scale - 1);
3564 }
3565 num_chain++;
3566
3567 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3568 ioc->name, numSGE, num_sge, num_chain));
3569
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003570 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 num_chain *= MPT_SCSI_CAN_QUEUE;
3572 else
3573 num_chain *= MPT_FC_CAN_QUEUE;
3574
3575 ioc->num_chain = num_chain;
3576
3577 sz = num_chain * sizeof(int);
3578 if (ioc->ChainToChain == NULL) {
3579 mem = kmalloc(sz, GFP_ATOMIC);
3580 if (mem == NULL)
3581 return -1;
3582
3583 ioc->ChainToChain = (int *) mem;
3584 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3585 ioc->name, mem, sz));
3586 } else {
3587 mem = (u8 *) ioc->ChainToChain;
3588 }
3589 memset(mem, 0xFF, sz);
3590 return num_chain;
3591}
3592
3593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3594/*
3595 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3596 * @ioc: Pointer to MPT_ADAPTER structure
3597 *
3598 * This routine allocates memory for the MPT reply and request frame
3599 * pools (if necessary), and primes the IOC reply FIFO with
3600 * reply frames.
3601 *
3602 * Returns 0 for success, non-zero for failure.
3603 */
3604static int
3605PrimeIocFifos(MPT_ADAPTER *ioc)
3606{
3607 MPT_FRAME_HDR *mf;
3608 unsigned long flags;
3609 dma_addr_t alloc_dma;
3610 u8 *mem;
3611 int i, reply_sz, sz, total_size, num_chain;
3612
3613 /* Prime reply FIFO... */
3614
3615 if (ioc->reply_frames == NULL) {
3616 if ( (num_chain = initChainBuffers(ioc)) < 0)
3617 return -1;
3618
3619 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3620 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3621 ioc->name, ioc->reply_sz, ioc->reply_depth));
3622 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3623 ioc->name, reply_sz, reply_sz));
3624
3625 sz = (ioc->req_sz * ioc->req_depth);
3626 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3627 ioc->name, ioc->req_sz, ioc->req_depth));
3628 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3629 ioc->name, sz, sz));
3630 total_size += sz;
3631
3632 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3633 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3634 ioc->name, ioc->req_sz, num_chain));
3635 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3636 ioc->name, sz, sz, num_chain));
3637
3638 total_size += sz;
3639 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3640 if (mem == NULL) {
3641 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3642 ioc->name);
3643 goto out_fail;
3644 }
3645
3646 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3647 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3648
3649 memset(mem, 0, total_size);
3650 ioc->alloc_total += total_size;
3651 ioc->alloc = mem;
3652 ioc->alloc_dma = alloc_dma;
3653 ioc->alloc_sz = total_size;
3654 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3655 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3656
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003657 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3658 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3659
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 alloc_dma += reply_sz;
3661 mem += reply_sz;
3662
3663 /* Request FIFO - WE manage this! */
3664
3665 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3666 ioc->req_frames_dma = alloc_dma;
3667
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003668 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 ioc->name, mem, (void *)(ulong)alloc_dma));
3670
3671 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3672
3673#if defined(CONFIG_MTRR) && 0
3674 /*
3675 * Enable Write Combining MTRR for IOC's memory region.
3676 * (at least as much as we can; "size and base must be
3677 * multiples of 4 kiB"
3678 */
3679 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3680 sz,
3681 MTRR_TYPE_WRCOMB, 1);
3682 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3683 ioc->name, ioc->req_frames_dma, sz));
3684#endif
3685
3686 for (i = 0; i < ioc->req_depth; i++) {
3687 alloc_dma += ioc->req_sz;
3688 mem += ioc->req_sz;
3689 }
3690
3691 ioc->ChainBuffer = mem;
3692 ioc->ChainBufferDMA = alloc_dma;
3693
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003694 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3696
3697 /* Initialize the free chain Q.
3698 */
3699
3700 INIT_LIST_HEAD(&ioc->FreeChainQ);
3701
3702 /* Post the chain buffers to the FreeChainQ.
3703 */
3704 mem = (u8 *)ioc->ChainBuffer;
3705 for (i=0; i < num_chain; i++) {
3706 mf = (MPT_FRAME_HDR *) mem;
3707 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3708 mem += ioc->req_sz;
3709 }
3710
3711 /* Initialize Request frames linked list
3712 */
3713 alloc_dma = ioc->req_frames_dma;
3714 mem = (u8 *) ioc->req_frames;
3715
3716 spin_lock_irqsave(&ioc->FreeQlock, flags);
3717 INIT_LIST_HEAD(&ioc->FreeQ);
3718 for (i = 0; i < ioc->req_depth; i++) {
3719 mf = (MPT_FRAME_HDR *) mem;
3720
3721 /* Queue REQUESTs *internally*! */
3722 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3723
3724 mem += ioc->req_sz;
3725 }
3726 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3727
3728 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3729 ioc->sense_buf_pool =
3730 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3731 if (ioc->sense_buf_pool == NULL) {
3732 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3733 ioc->name);
3734 goto out_fail;
3735 }
3736
3737 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3738 ioc->alloc_total += sz;
3739 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3740 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3741
3742 }
3743
3744 /* Post Reply frames to FIFO
3745 */
3746 alloc_dma = ioc->alloc_dma;
3747 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3748 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3749
3750 for (i = 0; i < ioc->reply_depth; i++) {
3751 /* Write each address to the IOC! */
3752 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3753 alloc_dma += ioc->reply_sz;
3754 }
3755
3756 return 0;
3757
3758out_fail:
3759 if (ioc->alloc != NULL) {
3760 sz = ioc->alloc_sz;
3761 pci_free_consistent(ioc->pcidev,
3762 sz,
3763 ioc->alloc, ioc->alloc_dma);
3764 ioc->reply_frames = NULL;
3765 ioc->req_frames = NULL;
3766 ioc->alloc_total -= sz;
3767 }
3768 if (ioc->sense_buf_pool != NULL) {
3769 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3770 pci_free_consistent(ioc->pcidev,
3771 sz,
3772 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3773 ioc->sense_buf_pool = NULL;
3774 }
3775 return -1;
3776}
3777
3778/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3779/**
3780 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3781 * from IOC via doorbell handshake method.
3782 * @ioc: Pointer to MPT_ADAPTER structure
3783 * @reqBytes: Size of the request in bytes
3784 * @req: Pointer to MPT request frame
3785 * @replyBytes: Expected size of the reply in bytes
3786 * @u16reply: Pointer to area where reply should be written
3787 * @maxwait: Max wait time for a reply (in seconds)
3788 * @sleepFlag: Specifies whether the process can sleep
3789 *
3790 * NOTES: It is the callers responsibility to byte-swap fields in the
3791 * request which are greater than 1 byte in size. It is also the
3792 * callers responsibility to byte-swap response fields which are
3793 * greater than 1 byte in size.
3794 *
3795 * Returns 0 for success, non-zero for failure.
3796 */
3797static int
3798mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003799 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800{
3801 MPIDefaultReply_t *mptReply;
3802 int failcnt = 0;
3803 int t;
3804
3805 /*
3806 * Get ready to cache a handshake reply
3807 */
3808 ioc->hs_reply_idx = 0;
3809 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3810 mptReply->MsgLength = 0;
3811
3812 /*
3813 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3814 * then tell IOC that we want to handshake a request of N words.
3815 * (WRITE u32val to Doorbell reg).
3816 */
3817 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3818 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3819 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3820 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3821
3822 /*
3823 * Wait for IOC's doorbell handshake int
3824 */
3825 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3826 failcnt++;
3827
3828 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3829 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3830
3831 /* Read doorbell and check for active bit */
3832 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3833 return -1;
3834
3835 /*
3836 * Clear doorbell int (WRITE 0 to IntStatus reg),
3837 * then wait for IOC to ACKnowledge that it's ready for
3838 * our handshake request.
3839 */
3840 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3841 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3842 failcnt++;
3843
3844 if (!failcnt) {
3845 int ii;
3846 u8 *req_as_bytes = (u8 *) req;
3847
3848 /*
3849 * Stuff request words via doorbell handshake,
3850 * with ACK from IOC for each.
3851 */
3852 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3853 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3854 (req_as_bytes[(ii*4) + 1] << 8) |
3855 (req_as_bytes[(ii*4) + 2] << 16) |
3856 (req_as_bytes[(ii*4) + 3] << 24));
3857
3858 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3859 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3860 failcnt++;
3861 }
3862
3863 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3864 DBG_DUMP_REQUEST_FRAME_HDR(req)
3865
3866 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3867 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3868
3869 /*
3870 * Wait for completion of doorbell handshake reply from the IOC
3871 */
3872 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3873 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003874
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3876 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3877
3878 /*
3879 * Copy out the cached reply...
3880 */
3881 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3882 u16reply[ii] = ioc->hs_reply[ii];
3883 } else {
3884 return -99;
3885 }
3886
3887 return -failcnt;
3888}
3889
3890/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3891/*
3892 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3893 * in it's IntStatus register.
3894 * @ioc: Pointer to MPT_ADAPTER structure
3895 * @howlong: How long to wait (in seconds)
3896 * @sleepFlag: Specifies whether the process can sleep
3897 *
3898 * This routine waits (up to ~2 seconds max) for IOC doorbell
3899 * handshake ACKnowledge.
3900 *
3901 * Returns a negative value on failure, else wait loop count.
3902 */
3903static int
3904WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3905{
3906 int cntdn;
3907 int count = 0;
3908 u32 intstat=0;
3909
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003910 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911
3912 if (sleepFlag == CAN_SLEEP) {
3913 while (--cntdn) {
3914 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3915 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3916 break;
3917 msleep_interruptible (1);
3918 count++;
3919 }
3920 } else {
3921 while (--cntdn) {
3922 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3923 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3924 break;
3925 mdelay (1);
3926 count++;
3927 }
3928 }
3929
3930 if (cntdn) {
3931 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3932 ioc->name, count));
3933 return count;
3934 }
3935
3936 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3937 ioc->name, count, intstat);
3938 return -1;
3939}
3940
3941/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3942/*
3943 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3944 * in it's IntStatus register.
3945 * @ioc: Pointer to MPT_ADAPTER structure
3946 * @howlong: How long to wait (in seconds)
3947 * @sleepFlag: Specifies whether the process can sleep
3948 *
3949 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3950 *
3951 * Returns a negative value on failure, else wait loop count.
3952 */
3953static int
3954WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3955{
3956 int cntdn;
3957 int count = 0;
3958 u32 intstat=0;
3959
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003960 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 if (sleepFlag == CAN_SLEEP) {
3962 while (--cntdn) {
3963 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3964 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3965 break;
3966 msleep_interruptible(1);
3967 count++;
3968 }
3969 } else {
3970 while (--cntdn) {
3971 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3972 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3973 break;
3974 mdelay(1);
3975 count++;
3976 }
3977 }
3978
3979 if (cntdn) {
3980 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3981 ioc->name, count, howlong));
3982 return count;
3983 }
3984
3985 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3986 ioc->name, count, intstat);
3987 return -1;
3988}
3989
3990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3991/*
3992 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3993 * @ioc: Pointer to MPT_ADAPTER structure
3994 * @howlong: How long to wait (in seconds)
3995 * @sleepFlag: Specifies whether the process can sleep
3996 *
3997 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3998 * Reply is cached to IOC private area large enough to hold a maximum
3999 * of 128 bytes of reply data.
4000 *
4001 * Returns a negative value on failure, else size of reply in WORDS.
4002 */
4003static int
4004WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4005{
4006 int u16cnt = 0;
4007 int failcnt = 0;
4008 int t;
4009 u16 *hs_reply = ioc->hs_reply;
4010 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4011 u16 hword;
4012
4013 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4014
4015 /*
4016 * Get first two u16's so we can look at IOC's intended reply MsgLength
4017 */
4018 u16cnt=0;
4019 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4020 failcnt++;
4021 } else {
4022 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4023 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4024 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4025 failcnt++;
4026 else {
4027 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4028 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4029 }
4030 }
4031
4032 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004033 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4035
4036 /*
4037 * If no error (and IOC said MsgLength is > 0), piece together
4038 * reply 16 bits at a time.
4039 */
4040 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4041 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4042 failcnt++;
4043 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4044 /* don't overflow our IOC hs_reply[] buffer! */
4045 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4046 hs_reply[u16cnt] = hword;
4047 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4048 }
4049
4050 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4051 failcnt++;
4052 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4053
4054 if (failcnt) {
4055 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4056 ioc->name);
4057 return -failcnt;
4058 }
4059#if 0
4060 else if (u16cnt != (2 * mptReply->MsgLength)) {
4061 return -101;
4062 }
4063 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4064 return -102;
4065 }
4066#endif
4067
4068 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4069 DBG_DUMP_REPLY_FRAME(mptReply)
4070
4071 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4072 ioc->name, t, u16cnt/2));
4073 return u16cnt/2;
4074}
4075
4076/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4077/*
4078 * GetLanConfigPages - Fetch LANConfig pages.
4079 * @ioc: Pointer to MPT_ADAPTER structure
4080 *
4081 * Return: 0 for success
4082 * -ENOMEM if no memory available
4083 * -EPERM if not allowed due to ISR context
4084 * -EAGAIN if no msg frames currently available
4085 * -EFAULT for non-successful reply or no reply (timeout)
4086 */
4087static int
4088GetLanConfigPages(MPT_ADAPTER *ioc)
4089{
4090 ConfigPageHeader_t hdr;
4091 CONFIGPARMS cfg;
4092 LANPage0_t *ppage0_alloc;
4093 dma_addr_t page0_dma;
4094 LANPage1_t *ppage1_alloc;
4095 dma_addr_t page1_dma;
4096 int rc = 0;
4097 int data_sz;
4098 int copy_sz;
4099
4100 /* Get LAN Page 0 header */
4101 hdr.PageVersion = 0;
4102 hdr.PageLength = 0;
4103 hdr.PageNumber = 0;
4104 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004105 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 cfg.physAddr = -1;
4107 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4108 cfg.dir = 0;
4109 cfg.pageAddr = 0;
4110 cfg.timeout = 0;
4111
4112 if ((rc = mpt_config(ioc, &cfg)) != 0)
4113 return rc;
4114
4115 if (hdr.PageLength > 0) {
4116 data_sz = hdr.PageLength * 4;
4117 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4118 rc = -ENOMEM;
4119 if (ppage0_alloc) {
4120 memset((u8 *)ppage0_alloc, 0, data_sz);
4121 cfg.physAddr = page0_dma;
4122 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4123
4124 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4125 /* save the data */
4126 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4127 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4128
4129 }
4130
4131 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4132
4133 /* FIXME!
4134 * Normalize endianness of structure data,
4135 * by byte-swapping all > 1 byte fields!
4136 */
4137
4138 }
4139
4140 if (rc)
4141 return rc;
4142 }
4143
4144 /* Get LAN Page 1 header */
4145 hdr.PageVersion = 0;
4146 hdr.PageLength = 0;
4147 hdr.PageNumber = 1;
4148 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004149 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 cfg.physAddr = -1;
4151 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4152 cfg.dir = 0;
4153 cfg.pageAddr = 0;
4154
4155 if ((rc = mpt_config(ioc, &cfg)) != 0)
4156 return rc;
4157
4158 if (hdr.PageLength == 0)
4159 return 0;
4160
4161 data_sz = hdr.PageLength * 4;
4162 rc = -ENOMEM;
4163 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4164 if (ppage1_alloc) {
4165 memset((u8 *)ppage1_alloc, 0, data_sz);
4166 cfg.physAddr = page1_dma;
4167 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4168
4169 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4170 /* save the data */
4171 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4172 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4173 }
4174
4175 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4176
4177 /* FIXME!
4178 * Normalize endianness of structure data,
4179 * by byte-swapping all > 1 byte fields!
4180 */
4181
4182 }
4183
4184 return rc;
4185}
4186
4187/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4188/*
Michael Reed05e8ec12006-01-13 14:31:54 -06004189 * mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 * @ioc: Pointer to MPT_ADAPTER structure
4191 * @portnum: IOC Port number
4192 *
4193 * Return: 0 for success
4194 * -ENOMEM if no memory available
4195 * -EPERM if not allowed due to ISR context
4196 * -EAGAIN if no msg frames currently available
4197 * -EFAULT for non-successful reply or no reply (timeout)
4198 */
Michael Reed05e8ec12006-01-13 14:31:54 -06004199int
4200mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201{
4202 ConfigPageHeader_t hdr;
4203 CONFIGPARMS cfg;
4204 FCPortPage0_t *ppage0_alloc;
4205 FCPortPage0_t *pp0dest;
4206 dma_addr_t page0_dma;
4207 int data_sz;
4208 int copy_sz;
4209 int rc;
Michael Reed05e8ec12006-01-13 14:31:54 -06004210 int count = 400;
4211
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212
4213 /* Get FCPort Page 0 header */
4214 hdr.PageVersion = 0;
4215 hdr.PageLength = 0;
4216 hdr.PageNumber = 0;
4217 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004218 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 cfg.physAddr = -1;
4220 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4221 cfg.dir = 0;
4222 cfg.pageAddr = portnum;
4223 cfg.timeout = 0;
4224
4225 if ((rc = mpt_config(ioc, &cfg)) != 0)
4226 return rc;
4227
4228 if (hdr.PageLength == 0)
4229 return 0;
4230
4231 data_sz = hdr.PageLength * 4;
4232 rc = -ENOMEM;
4233 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4234 if (ppage0_alloc) {
Michael Reed05e8ec12006-01-13 14:31:54 -06004235
4236 try_again:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 memset((u8 *)ppage0_alloc, 0, data_sz);
4238 cfg.physAddr = page0_dma;
4239 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4240
4241 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4242 /* save the data */
4243 pp0dest = &ioc->fc_port_page0[portnum];
4244 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
4245 memcpy(pp0dest, ppage0_alloc, copy_sz);
4246
4247 /*
4248 * Normalize endianness of structure data,
4249 * by byte-swapping all > 1 byte fields!
4250 */
4251 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
4252 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
4253 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
4254 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
4255 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
4256 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
4257 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
4258 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
4259 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
4260 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
4261 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
4262 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
4263 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
4264 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
4265 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
4266 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
4267
Michael Reed05e8ec12006-01-13 14:31:54 -06004268 /*
4269 * if still doing discovery,
4270 * hang loose a while until finished
4271 */
4272 if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
4273 if (count-- > 0) {
4274 msleep_interruptible(100);
4275 goto try_again;
4276 }
4277 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
4278 " complete.\n",
4279 ioc->name);
4280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 }
4282
4283 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4284 }
4285
4286 return rc;
4287}
4288
4289/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4290/*
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004291 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4292 * @ioc: Pointer to MPT_ADAPTER structure
4293 * @sas_address: 64bit SAS Address for operation.
4294 * @target_id: specified target for operation
4295 * @bus: specified bus for operation
4296 * @persist_opcode: see below
4297 *
4298 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4299 * devices not currently present.
4300 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4301 *
4302 * NOTE: Don't use not this function during interrupt time.
4303 *
4304 * Returns: 0 for success, non-zero error
4305 */
4306
4307/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4308int
4309mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4310{
4311 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4312 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4313 MPT_FRAME_HDR *mf = NULL;
4314 MPIHeader_t *mpi_hdr;
4315
4316
4317 /* insure garbage is not sent to fw */
4318 switch(persist_opcode) {
4319
4320 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4321 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4322 break;
4323
4324 default:
4325 return -1;
4326 break;
4327 }
4328
4329 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4330
4331 /* Get a MF for this command.
4332 */
4333 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4334 printk("%s: no msg frames!\n",__FUNCTION__);
4335 return -1;
4336 }
4337
4338 mpi_hdr = (MPIHeader_t *) mf;
4339 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4340 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4341 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4342 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4343 sasIoUnitCntrReq->Operation = persist_opcode;
4344
4345 init_timer(&ioc->persist_timer);
4346 ioc->persist_timer.data = (unsigned long) ioc;
4347 ioc->persist_timer.function = mpt_timer_expired;
4348 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4349 ioc->persist_wait_done=0;
4350 add_timer(&ioc->persist_timer);
4351 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4352 wait_event(mpt_waitq, ioc->persist_wait_done);
4353
4354 sasIoUnitCntrReply =
4355 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4356 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4357 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4358 __FUNCTION__,
4359 sasIoUnitCntrReply->IOCStatus,
4360 sasIoUnitCntrReply->IOCLogInfo);
4361 return -1;
4362 }
4363
4364 printk("%s: success\n",__FUNCTION__);
4365 return 0;
4366}
4367
4368/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004369
4370static void
4371mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4372 MpiEventDataRaid_t * pRaidEventData)
4373{
4374 int volume;
4375 int reason;
4376 int disk;
4377 int status;
4378 int flags;
4379 int state;
4380
4381 volume = pRaidEventData->VolumeID;
4382 reason = pRaidEventData->ReasonCode;
4383 disk = pRaidEventData->PhysDiskNum;
4384 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4385 flags = (status >> 0) & 0xff;
4386 state = (status >> 8) & 0xff;
4387
4388 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4389 return;
4390 }
4391
4392 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4393 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4394 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4395 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4396 ioc->name, disk);
4397 } else {
4398 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4399 ioc->name, volume);
4400 }
4401
4402 switch(reason) {
4403 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4404 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4405 ioc->name);
4406 break;
4407
4408 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4409
4410 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4411 ioc->name);
4412 break;
4413
4414 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4415 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4416 ioc->name);
4417 break;
4418
4419 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4420 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4421 ioc->name,
4422 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4423 ? "optimal"
4424 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4425 ? "degraded"
4426 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4427 ? "failed"
4428 : "state unknown",
4429 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4430 ? ", enabled" : "",
4431 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4432 ? ", quiesced" : "",
4433 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4434 ? ", resync in progress" : "" );
4435 break;
4436
4437 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4438 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4439 ioc->name, disk);
4440 break;
4441
4442 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4443 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4444 ioc->name);
4445 break;
4446
4447 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4448 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4449 ioc->name);
4450 break;
4451
4452 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4453 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4454 ioc->name);
4455 break;
4456
4457 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4458 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4459 ioc->name,
4460 state == MPI_PHYSDISK0_STATUS_ONLINE
4461 ? "online"
4462 : state == MPI_PHYSDISK0_STATUS_MISSING
4463 ? "missing"
4464 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4465 ? "not compatible"
4466 : state == MPI_PHYSDISK0_STATUS_FAILED
4467 ? "failed"
4468 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4469 ? "initializing"
4470 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4471 ? "offline requested"
4472 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4473 ? "failed requested"
4474 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4475 ? "offline"
4476 : "state unknown",
4477 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4478 ? ", out of sync" : "",
4479 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4480 ? ", quiesced" : "" );
4481 break;
4482
4483 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4484 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4485 ioc->name, disk);
4486 break;
4487
4488 case MPI_EVENT_RAID_RC_SMART_DATA:
4489 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4490 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4491 break;
4492
4493 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4494 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4495 ioc->name, disk);
4496 break;
4497 }
4498}
4499
4500/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004501/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4503 * @ioc: Pointer to MPT_ADAPTER structure
4504 *
4505 * Returns: 0 for success
4506 * -ENOMEM if no memory available
4507 * -EPERM if not allowed due to ISR context
4508 * -EAGAIN if no msg frames currently available
4509 * -EFAULT for non-successful reply or no reply (timeout)
4510 */
4511static int
4512GetIoUnitPage2(MPT_ADAPTER *ioc)
4513{
4514 ConfigPageHeader_t hdr;
4515 CONFIGPARMS cfg;
4516 IOUnitPage2_t *ppage_alloc;
4517 dma_addr_t page_dma;
4518 int data_sz;
4519 int rc;
4520
4521 /* Get the page header */
4522 hdr.PageVersion = 0;
4523 hdr.PageLength = 0;
4524 hdr.PageNumber = 2;
4525 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004526 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 cfg.physAddr = -1;
4528 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4529 cfg.dir = 0;
4530 cfg.pageAddr = 0;
4531 cfg.timeout = 0;
4532
4533 if ((rc = mpt_config(ioc, &cfg)) != 0)
4534 return rc;
4535
4536 if (hdr.PageLength == 0)
4537 return 0;
4538
4539 /* Read the config page */
4540 data_sz = hdr.PageLength * 4;
4541 rc = -ENOMEM;
4542 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4543 if (ppage_alloc) {
4544 memset((u8 *)ppage_alloc, 0, data_sz);
4545 cfg.physAddr = page_dma;
4546 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4547
4548 /* If Good, save data */
4549 if ((rc = mpt_config(ioc, &cfg)) == 0)
4550 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4551
4552 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4553 }
4554
4555 return rc;
4556}
4557
4558/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4559/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4560 * @ioc: Pointer to a Adapter Strucutre
4561 * @portnum: IOC port number
4562 *
4563 * Return: -EFAULT if read of config page header fails
4564 * or if no nvram
4565 * If read of SCSI Port Page 0 fails,
4566 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4567 * Adapter settings: async, narrow
4568 * Return 1
4569 * If read of SCSI Port Page 2 fails,
4570 * Adapter settings valid
4571 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4572 * Return 1
4573 * Else
4574 * Both valid
4575 * Return 0
4576 * CHECK - what type of locking mechanisms should be used????
4577 */
4578static int
4579mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4580{
4581 u8 *pbuf;
4582 dma_addr_t buf_dma;
4583 CONFIGPARMS cfg;
4584 ConfigPageHeader_t header;
4585 int ii;
4586 int data, rc = 0;
4587
4588 /* Allocate memory
4589 */
4590 if (!ioc->spi_data.nvram) {
4591 int sz;
4592 u8 *mem;
4593 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4594 mem = kmalloc(sz, GFP_ATOMIC);
4595 if (mem == NULL)
4596 return -EFAULT;
4597
4598 ioc->spi_data.nvram = (int *) mem;
4599
4600 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4601 ioc->name, ioc->spi_data.nvram, sz));
4602 }
4603
4604 /* Invalidate NVRAM information
4605 */
4606 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4607 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4608 }
4609
4610 /* Read SPP0 header, allocate memory, then read page.
4611 */
4612 header.PageVersion = 0;
4613 header.PageLength = 0;
4614 header.PageNumber = 0;
4615 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004616 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 cfg.physAddr = -1;
4618 cfg.pageAddr = portnum;
4619 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4620 cfg.dir = 0;
4621 cfg.timeout = 0; /* use default */
4622 if (mpt_config(ioc, &cfg) != 0)
4623 return -EFAULT;
4624
4625 if (header.PageLength > 0) {
4626 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4627 if (pbuf) {
4628 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4629 cfg.physAddr = buf_dma;
4630 if (mpt_config(ioc, &cfg) != 0) {
4631 ioc->spi_data.maxBusWidth = MPT_NARROW;
4632 ioc->spi_data.maxSyncOffset = 0;
4633 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4634 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4635 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004636 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4637 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 } else {
4639 /* Save the Port Page 0 data
4640 */
4641 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4642 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4643 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4644
4645 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4646 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004647 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 ioc->name, pPP0->Capabilities));
4649 }
4650 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4651 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4652 if (data) {
4653 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4654 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4655 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004656 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4657 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 } else {
4659 ioc->spi_data.maxSyncOffset = 0;
4660 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4661 }
4662
4663 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4664
4665 /* Update the minSyncFactor based on bus type.
4666 */
4667 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4668 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4669
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004670 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004672 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4673 ioc->name, ioc->spi_data.minSyncFactor));
4674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 }
4676 }
4677 if (pbuf) {
4678 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4679 }
4680 }
4681 }
4682
4683 /* SCSI Port Page 2 - Read the header then the page.
4684 */
4685 header.PageVersion = 0;
4686 header.PageLength = 0;
4687 header.PageNumber = 2;
4688 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004689 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 cfg.physAddr = -1;
4691 cfg.pageAddr = portnum;
4692 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4693 cfg.dir = 0;
4694 if (mpt_config(ioc, &cfg) != 0)
4695 return -EFAULT;
4696
4697 if (header.PageLength > 0) {
4698 /* Allocate memory and read SCSI Port Page 2
4699 */
4700 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4701 if (pbuf) {
4702 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4703 cfg.physAddr = buf_dma;
4704 if (mpt_config(ioc, &cfg) != 0) {
4705 /* Nvram data is left with INVALID mark
4706 */
4707 rc = 1;
4708 } else {
4709 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4710 MpiDeviceInfo_t *pdevice = NULL;
4711
Moore, Ericd8e925d2006-01-16 18:53:06 -07004712 /*
4713 * Save "Set to Avoid SCSI Bus Resets" flag
4714 */
4715 ioc->spi_data.bus_reset =
4716 (le32_to_cpu(pPP2->PortFlags) &
4717 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4718 0 : 1 ;
4719
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 /* Save the Port Page 2 data
4721 * (reformat into a 32bit quantity)
4722 */
4723 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4724 ioc->spi_data.PortFlags = data;
4725 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4726 pdevice = &pPP2->DeviceSettings[ii];
4727 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4728 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4729 ioc->spi_data.nvram[ii] = data;
4730 }
4731 }
4732
4733 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4734 }
4735 }
4736
4737 /* Update Adapter limits with those from NVRAM
4738 * Comment: Don't need to do this. Target performance
4739 * parameters will never exceed the adapters limits.
4740 */
4741
4742 return rc;
4743}
4744
4745/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4746/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4747 * @ioc: Pointer to a Adapter Strucutre
4748 * @portnum: IOC port number
4749 *
4750 * Return: -EFAULT if read of config page header fails
4751 * or 0 if success.
4752 */
4753static int
4754mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4755{
4756 CONFIGPARMS cfg;
4757 ConfigPageHeader_t header;
4758
4759 /* Read the SCSI Device Page 1 header
4760 */
4761 header.PageVersion = 0;
4762 header.PageLength = 0;
4763 header.PageNumber = 1;
4764 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004765 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 cfg.physAddr = -1;
4767 cfg.pageAddr = portnum;
4768 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4769 cfg.dir = 0;
4770 cfg.timeout = 0;
4771 if (mpt_config(ioc, &cfg) != 0)
4772 return -EFAULT;
4773
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004774 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4775 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776
4777 header.PageVersion = 0;
4778 header.PageLength = 0;
4779 header.PageNumber = 0;
4780 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4781 if (mpt_config(ioc, &cfg) != 0)
4782 return -EFAULT;
4783
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004784 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4785 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786
4787 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4788 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4789
4790 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4791 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4792 return 0;
4793}
4794
4795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4796/**
4797 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4798 * @ioc: Pointer to a Adapter Strucutre
4799 * @portnum: IOC port number
4800 *
4801 * Return:
4802 * 0 on success
4803 * -EFAULT if read of config page header fails or data pointer not NULL
4804 * -ENOMEM if pci_alloc failed
4805 */
4806int
4807mpt_findImVolumes(MPT_ADAPTER *ioc)
4808{
4809 IOCPage2_t *pIoc2;
4810 u8 *mem;
4811 ConfigPageIoc2RaidVol_t *pIocRv;
4812 dma_addr_t ioc2_dma;
4813 CONFIGPARMS cfg;
4814 ConfigPageHeader_t header;
4815 int jj;
4816 int rc = 0;
4817 int iocpage2sz;
4818 u8 nVols, nPhys;
4819 u8 vid, vbus, vioc;
4820
4821 /* Read IOCP2 header then the page.
4822 */
4823 header.PageVersion = 0;
4824 header.PageLength = 0;
4825 header.PageNumber = 2;
4826 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004827 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 cfg.physAddr = -1;
4829 cfg.pageAddr = 0;
4830 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4831 cfg.dir = 0;
4832 cfg.timeout = 0;
4833 if (mpt_config(ioc, &cfg) != 0)
4834 return -EFAULT;
4835
4836 if (header.PageLength == 0)
4837 return -EFAULT;
4838
4839 iocpage2sz = header.PageLength * 4;
4840 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4841 if (!pIoc2)
4842 return -ENOMEM;
4843
4844 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4845 cfg.physAddr = ioc2_dma;
4846 if (mpt_config(ioc, &cfg) != 0)
4847 goto done_and_free;
4848
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004849 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4851 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004852 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 } else {
4854 goto done_and_free;
4855 }
4856 }
4857 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4858
4859 /* Identify RAID Volume Id's */
4860 nVols = pIoc2->NumActiveVolumes;
4861 if ( nVols == 0) {
4862 /* No RAID Volume.
4863 */
4864 goto done_and_free;
4865 } else {
4866 /* At least 1 RAID Volume
4867 */
4868 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004869 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4871 vid = pIocRv->VolumeID;
4872 vbus = pIocRv->VolumeBus;
4873 vioc = pIocRv->VolumeIOC;
4874
4875 /* find the match
4876 */
4877 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004878 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 } else {
4880 /* Error! Always bus 0
4881 */
4882 }
4883 }
4884 }
4885
4886 /* Identify Hidden Physical Disk Id's */
4887 nPhys = pIoc2->NumActivePhysDisks;
4888 if (nPhys == 0) {
4889 /* No physical disks.
4890 */
4891 } else {
4892 mpt_read_ioc_pg_3(ioc);
4893 }
4894
4895done_and_free:
4896 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4897
4898 return rc;
4899}
4900
Moore, Ericc972c702006-03-14 09:14:06 -07004901static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4903{
4904 IOCPage3_t *pIoc3;
4905 u8 *mem;
4906 CONFIGPARMS cfg;
4907 ConfigPageHeader_t header;
4908 dma_addr_t ioc3_dma;
4909 int iocpage3sz = 0;
4910
4911 /* Free the old page
4912 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004913 kfree(ioc->raid_data.pIocPg3);
4914 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915
4916 /* There is at least one physical disk.
4917 * Read and save IOC Page 3
4918 */
4919 header.PageVersion = 0;
4920 header.PageLength = 0;
4921 header.PageNumber = 3;
4922 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004923 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 cfg.physAddr = -1;
4925 cfg.pageAddr = 0;
4926 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4927 cfg.dir = 0;
4928 cfg.timeout = 0;
4929 if (mpt_config(ioc, &cfg) != 0)
4930 return 0;
4931
4932 if (header.PageLength == 0)
4933 return 0;
4934
4935 /* Read Header good, alloc memory
4936 */
4937 iocpage3sz = header.PageLength * 4;
4938 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4939 if (!pIoc3)
4940 return 0;
4941
4942 /* Read the Page and save the data
4943 * into malloc'd memory.
4944 */
4945 cfg.physAddr = ioc3_dma;
4946 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4947 if (mpt_config(ioc, &cfg) == 0) {
4948 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4949 if (mem) {
4950 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004951 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 }
4953 }
4954
4955 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4956
4957 return 0;
4958}
4959
4960static void
4961mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4962{
4963 IOCPage4_t *pIoc4;
4964 CONFIGPARMS cfg;
4965 ConfigPageHeader_t header;
4966 dma_addr_t ioc4_dma;
4967 int iocpage4sz;
4968
4969 /* Read and save IOC Page 4
4970 */
4971 header.PageVersion = 0;
4972 header.PageLength = 0;
4973 header.PageNumber = 4;
4974 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004975 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 cfg.physAddr = -1;
4977 cfg.pageAddr = 0;
4978 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4979 cfg.dir = 0;
4980 cfg.timeout = 0;
4981 if (mpt_config(ioc, &cfg) != 0)
4982 return;
4983
4984 if (header.PageLength == 0)
4985 return;
4986
4987 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4988 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4989 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4990 if (!pIoc4)
4991 return;
4992 } else {
4993 ioc4_dma = ioc->spi_data.IocPg4_dma;
4994 iocpage4sz = ioc->spi_data.IocPg4Sz;
4995 }
4996
4997 /* Read the Page into dma memory.
4998 */
4999 cfg.physAddr = ioc4_dma;
5000 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5001 if (mpt_config(ioc, &cfg) == 0) {
5002 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5003 ioc->spi_data.IocPg4_dma = ioc4_dma;
5004 ioc->spi_data.IocPg4Sz = iocpage4sz;
5005 } else {
5006 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5007 ioc->spi_data.pIocPg4 = NULL;
5008 }
5009}
5010
5011static void
5012mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5013{
5014 IOCPage1_t *pIoc1;
5015 CONFIGPARMS cfg;
5016 ConfigPageHeader_t header;
5017 dma_addr_t ioc1_dma;
5018 int iocpage1sz = 0;
5019 u32 tmp;
5020
5021 /* Check the Coalescing Timeout in IOC Page 1
5022 */
5023 header.PageVersion = 0;
5024 header.PageLength = 0;
5025 header.PageNumber = 1;
5026 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005027 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 cfg.physAddr = -1;
5029 cfg.pageAddr = 0;
5030 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5031 cfg.dir = 0;
5032 cfg.timeout = 0;
5033 if (mpt_config(ioc, &cfg) != 0)
5034 return;
5035
5036 if (header.PageLength == 0)
5037 return;
5038
5039 /* Read Header good, alloc memory
5040 */
5041 iocpage1sz = header.PageLength * 4;
5042 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5043 if (!pIoc1)
5044 return;
5045
5046 /* Read the Page and check coalescing timeout
5047 */
5048 cfg.physAddr = ioc1_dma;
5049 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5050 if (mpt_config(ioc, &cfg) == 0) {
5051
5052 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5053 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5054 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5055
5056 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5057 ioc->name, tmp));
5058
5059 if (tmp > MPT_COALESCING_TIMEOUT) {
5060 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5061
5062 /* Write NVRAM and current
5063 */
5064 cfg.dir = 1;
5065 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5066 if (mpt_config(ioc, &cfg) == 0) {
5067 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5068 ioc->name, MPT_COALESCING_TIMEOUT));
5069
5070 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5071 if (mpt_config(ioc, &cfg) == 0) {
5072 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5073 ioc->name, MPT_COALESCING_TIMEOUT));
5074 } else {
5075 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5076 ioc->name));
5077 }
5078
5079 } else {
5080 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5081 ioc->name));
5082 }
5083 }
5084
5085 } else {
5086 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5087 }
5088 }
5089
5090 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5091
5092 return;
5093}
5094
5095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5096/*
5097 * SendEventNotification - Send EventNotification (on or off) request
5098 * to MPT adapter.
5099 * @ioc: Pointer to MPT_ADAPTER structure
5100 * @EvSwitch: Event switch flags
5101 */
5102static int
5103SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5104{
5105 EventNotification_t *evnp;
5106
5107 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5108 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005109 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 ioc->name));
5111 return 0;
5112 }
5113 memset(evnp, 0, sizeof(*evnp));
5114
Moore, Eric3a892be2006-03-14 09:14:03 -07005115 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116
5117 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5118 evnp->ChainOffset = 0;
5119 evnp->MsgFlags = 0;
5120 evnp->Switch = EvSwitch;
5121
5122 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5123
5124 return 0;
5125}
5126
5127/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5128/**
5129 * SendEventAck - Send EventAck request to MPT adapter.
5130 * @ioc: Pointer to MPT_ADAPTER structure
5131 * @evnp: Pointer to original EventNotification request
5132 */
5133static int
5134SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5135{
5136 EventAck_t *pAck;
5137
5138 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005139 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5140 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5141 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5142 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 return -1;
5144 }
5145 memset(pAck, 0, sizeof(*pAck));
5146
5147 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5148
5149 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5150 pAck->ChainOffset = 0;
5151 pAck->MsgFlags = 0;
5152 pAck->Event = evnp->Event;
5153 pAck->EventContext = evnp->EventContext;
5154
5155 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5156
5157 return 0;
5158}
5159
5160/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5161/**
5162 * mpt_config - Generic function to issue config message
5163 * @ioc - Pointer to an adapter structure
5164 * @cfg - Pointer to a configuration structure. Struct contains
5165 * action, page address, direction, physical address
5166 * and pointer to a configuration page header
5167 * Page header is updated.
5168 *
5169 * Returns 0 for success
5170 * -EPERM if not allowed due to ISR context
5171 * -EAGAIN if no msg frames currently available
5172 * -EFAULT for non-successful reply or no reply (timeout)
5173 */
5174int
5175mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5176{
5177 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005178 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179 MPT_FRAME_HDR *mf;
5180 unsigned long flags;
5181 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005182 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 int in_isr;
5184
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005185 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 * to be in ISR context, because that is fatal!
5187 */
5188 in_isr = in_interrupt();
5189 if (in_isr) {
5190 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5191 ioc->name));
5192 return -EPERM;
5193 }
5194
5195 /* Get and Populate a free Frame
5196 */
5197 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5198 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5199 ioc->name));
5200 return -EAGAIN;
5201 }
5202 pReq = (Config_t *)mf;
5203 pReq->Action = pCfg->action;
5204 pReq->Reserved = 0;
5205 pReq->ChainOffset = 0;
5206 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005207
5208 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 pReq->ExtPageLength = 0;
5210 pReq->ExtPageType = 0;
5211 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005212
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 for (ii=0; ii < 8; ii++)
5214 pReq->Reserved2[ii] = 0;
5215
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005216 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5217 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5218 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5219 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5220
5221 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5222 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5223 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5224 pReq->ExtPageType = pExtHdr->ExtPageType;
5225 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5226
5227 /* Page Length must be treated as a reserved field for the extended header. */
5228 pReq->Header.PageLength = 0;
5229 }
5230
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5232
5233 /* Add a SGE to the config request.
5234 */
5235 if (pCfg->dir)
5236 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5237 else
5238 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5239
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005240 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5241 flagsLength |= pExtHdr->ExtPageLength * 4;
5242
5243 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5244 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5245 }
5246 else {
5247 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5248
5249 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5250 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252
5253 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5254
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 /* Append pCfg pointer to end of mf
5256 */
5257 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5258
5259 /* Initalize the timer
5260 */
5261 init_timer(&pCfg->timer);
5262 pCfg->timer.data = (unsigned long) ioc;
5263 pCfg->timer.function = mpt_timer_expired;
5264 pCfg->wait_done = 0;
5265
5266 /* Set the timer; ensure 10 second minimum */
5267 if (pCfg->timeout < 10)
5268 pCfg->timer.expires = jiffies + HZ*10;
5269 else
5270 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5271
5272 /* Add to end of Q, set timer and then issue this command */
5273 spin_lock_irqsave(&ioc->FreeQlock, flags);
5274 list_add_tail(&pCfg->linkage, &ioc->configQ);
5275 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5276
5277 add_timer(&pCfg->timer);
5278 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5279 wait_event(mpt_waitq, pCfg->wait_done);
5280
5281 /* mf has been freed - do not access */
5282
5283 rc = pCfg->status;
5284
5285 return rc;
5286}
5287
5288/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289/*
5290 * mpt_timer_expired - Call back for timer process.
5291 * Used only internal config functionality.
5292 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5293 */
5294static void
5295mpt_timer_expired(unsigned long data)
5296{
5297 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5298
5299 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5300
5301 /* Perform a FW reload */
5302 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5303 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5304
5305 /* No more processing.
5306 * Hard reset clean-up will wake up
5307 * process and free all resources.
5308 */
5309 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5310
5311 return;
5312}
5313
5314/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5315/*
5316 * mpt_ioc_reset - Base cleanup for hard reset
5317 * @ioc: Pointer to the adapter structure
5318 * @reset_phase: Indicates pre- or post-reset functionality
5319 *
5320 * Remark: Free's resources with internally generated commands.
5321 */
5322static int
5323mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5324{
5325 CONFIGPARMS *pCfg;
5326 unsigned long flags;
5327
5328 dprintk((KERN_WARNING MYNAM
5329 ": IOC %s_reset routed to MPT base driver!\n",
5330 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5331 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5332
5333 if (reset_phase == MPT_IOC_SETUP_RESET) {
5334 ;
5335 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5336 /* If the internal config Q is not empty -
5337 * delete timer. MF resources will be freed when
5338 * the FIFO's are primed.
5339 */
5340 spin_lock_irqsave(&ioc->FreeQlock, flags);
5341 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5342 del_timer(&pCfg->timer);
5343 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5344
5345 } else {
5346 CONFIGPARMS *pNext;
5347
5348 /* Search the configQ for internal commands.
5349 * Flush the Q, and wake up all suspended threads.
5350 */
5351 spin_lock_irqsave(&ioc->FreeQlock, flags);
5352 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5353 list_del(&pCfg->linkage);
5354
5355 pCfg->status = MPT_CONFIG_ERROR;
5356 pCfg->wait_done = 1;
5357 wake_up(&mpt_waitq);
5358 }
5359 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5360 }
5361
5362 return 1; /* currently means nothing really */
5363}
5364
5365
5366#ifdef CONFIG_PROC_FS /* { */
5367/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5368/*
5369 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5370 */
5371/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5372/*
5373 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5374 *
5375 * Returns 0 for success, non-zero for failure.
5376 */
5377static int
5378procmpt_create(void)
5379{
5380 struct proc_dir_entry *ent;
5381
5382 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5383 if (mpt_proc_root_dir == NULL)
5384 return -ENOTDIR;
5385
5386 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5387 if (ent)
5388 ent->read_proc = procmpt_summary_read;
5389
5390 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5391 if (ent)
5392 ent->read_proc = procmpt_version_read;
5393
5394 return 0;
5395}
5396
5397/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5398/*
5399 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5400 *
5401 * Returns 0 for success, non-zero for failure.
5402 */
5403static void
5404procmpt_destroy(void)
5405{
5406 remove_proc_entry("version", mpt_proc_root_dir);
5407 remove_proc_entry("summary", mpt_proc_root_dir);
5408 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5409}
5410
5411/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5412/*
5413 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5414 * or from /proc/mpt/iocN/summary.
5415 * @buf: Pointer to area to write information
5416 * @start: Pointer to start pointer
5417 * @offset: Offset to start writing
5418 * @request:
5419 * @eof: Pointer to EOF integer
5420 * @data: Pointer
5421 *
5422 * Returns number of characters written to process performing the read.
5423 */
5424static int
5425procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5426{
5427 MPT_ADAPTER *ioc;
5428 char *out = buf;
5429 int len;
5430
5431 if (data) {
5432 int more = 0;
5433
5434 ioc = data;
5435 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5436
5437 out += more;
5438 } else {
5439 list_for_each_entry(ioc, &ioc_list, list) {
5440 int more = 0;
5441
5442 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5443
5444 out += more;
5445 if ((out-buf) >= request)
5446 break;
5447 }
5448 }
5449
5450 len = out - buf;
5451
5452 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5453}
5454
5455/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5456/*
5457 * procmpt_version_read - Handle read request from /proc/mpt/version.
5458 * @buf: Pointer to area to write information
5459 * @start: Pointer to start pointer
5460 * @offset: Offset to start writing
5461 * @request:
5462 * @eof: Pointer to EOF integer
5463 * @data: Pointer
5464 *
5465 * Returns number of characters written to process performing the read.
5466 */
5467static int
5468procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5469{
5470 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005471 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 char *drvname;
5473 int len;
5474
5475 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5476 len += sprintf(buf+len, " Fusion MPT base driver\n");
5477
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005478 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5480 drvname = NULL;
5481 if (MptCallbacks[ii]) {
5482 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005483 case MPTSPI_DRIVER:
5484 if (!scsi++) drvname = "SPI host";
5485 break;
5486 case MPTFC_DRIVER:
5487 if (!fc++) drvname = "FC host";
5488 break;
5489 case MPTSAS_DRIVER:
5490 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 break;
5492 case MPTLAN_DRIVER:
5493 if (!lan++) drvname = "LAN";
5494 break;
5495 case MPTSTM_DRIVER:
5496 if (!targ++) drvname = "SCSI target";
5497 break;
5498 case MPTCTL_DRIVER:
5499 if (!ctl++) drvname = "ioctl";
5500 break;
5501 }
5502
5503 if (drvname)
5504 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5505 }
5506 }
5507
5508 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5509}
5510
5511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5512/*
5513 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5514 * @buf: Pointer to area to write information
5515 * @start: Pointer to start pointer
5516 * @offset: Offset to start writing
5517 * @request:
5518 * @eof: Pointer to EOF integer
5519 * @data: Pointer
5520 *
5521 * Returns number of characters written to process performing the read.
5522 */
5523static int
5524procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5525{
5526 MPT_ADAPTER *ioc = data;
5527 int len;
5528 char expVer[32];
5529 int sz;
5530 int p;
5531
5532 mpt_get_fw_exp_ver(expVer, ioc);
5533
5534 len = sprintf(buf, "%s:", ioc->name);
5535 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5536 len += sprintf(buf+len, " (f/w download boot flag set)");
5537// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5538// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5539
5540 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5541 ioc->facts.ProductID,
5542 ioc->prod_name);
5543 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5544 if (ioc->facts.FWImageSize)
5545 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5546 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5547 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5548 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5549
5550 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5551 ioc->facts.CurrentHostMfaHighAddr);
5552 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5553 ioc->facts.CurrentSenseBufferHighAddr);
5554
5555 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5556 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5557
5558 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5559 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5560 /*
5561 * Rounding UP to nearest 4-kB boundary here...
5562 */
5563 sz = (ioc->req_sz * ioc->req_depth) + 128;
5564 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5565 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5566 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5567 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5568 4*ioc->facts.RequestFrameSize,
5569 ioc->facts.GlobalCredits);
5570
5571 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5572 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5573 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5574 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5575 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5576 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5577 ioc->facts.CurReplyFrameSize,
5578 ioc->facts.ReplyQueueDepth);
5579
5580 len += sprintf(buf+len, " MaxDevices = %d\n",
5581 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5582 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5583
5584 /* per-port info */
5585 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5586 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5587 p+1,
5588 ioc->facts.NumberOfPorts);
5589 if (ioc->bus_type == FC) {
5590 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5591 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5592 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5593 a[5], a[4], a[3], a[2], a[1], a[0]);
5594 }
5595 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5596 ioc->fc_port_page0[p].WWNN.High,
5597 ioc->fc_port_page0[p].WWNN.Low,
5598 ioc->fc_port_page0[p].WWPN.High,
5599 ioc->fc_port_page0[p].WWPN.Low);
5600 }
5601 }
5602
5603 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5604}
5605
5606#endif /* CONFIG_PROC_FS } */
5607
5608/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5609static void
5610mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5611{
5612 buf[0] ='\0';
5613 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5614 sprintf(buf, " (Exp %02d%02d)",
5615 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5616 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5617
5618 /* insider hack! */
5619 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5620 strcat(buf, " [MDBG]");
5621 }
5622}
5623
5624/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5625/**
5626 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5627 * @ioc: Pointer to MPT_ADAPTER structure
5628 * @buffer: Pointer to buffer where IOC summary info should be written
5629 * @size: Pointer to number of bytes we wrote (set by this routine)
5630 * @len: Offset at which to start writing in buffer
5631 * @showlan: Display LAN stuff?
5632 *
5633 * This routine writes (english readable) ASCII text, which represents
5634 * a summary of IOC information, to a buffer.
5635 */
5636void
5637mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5638{
5639 char expVer[32];
5640 int y;
5641
5642 mpt_get_fw_exp_ver(expVer, ioc);
5643
5644 /*
5645 * Shorter summary of attached ioc's...
5646 */
5647 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5648 ioc->name,
5649 ioc->prod_name,
5650 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5651 ioc->facts.FWVersion.Word,
5652 expVer,
5653 ioc->facts.NumberOfPorts,
5654 ioc->req_depth);
5655
5656 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5657 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5658 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5659 a[5], a[4], a[3], a[2], a[1], a[0]);
5660 }
5661
5662#ifndef __sparc__
5663 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
5664#else
5665 y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
5666#endif
5667
5668 if (!ioc->active)
5669 y += sprintf(buffer+len+y, " (disabled)");
5670
5671 y += sprintf(buffer+len+y, "\n");
5672
5673 *size = y;
5674}
5675
5676/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5677/*
5678 * Reset Handling
5679 */
5680/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5681/**
5682 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5683 * Management call based on input arg values. If TaskMgmt fails,
5684 * return associated SCSI request.
5685 * @ioc: Pointer to MPT_ADAPTER structure
5686 * @sleepFlag: Indicates if sleep or schedule must be called.
5687 *
5688 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5689 * or a non-interrupt thread. In the former, must not call schedule().
5690 *
5691 * Remark: A return of -1 is a FATAL error case, as it means a
5692 * FW reload/initialization failed.
5693 *
5694 * Returns 0 for SUCCESS or -1 if FAILED.
5695 */
5696int
5697mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5698{
5699 int rc;
5700 unsigned long flags;
5701
5702 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5703#ifdef MFCNT
5704 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5705 printk("MF count 0x%x !\n", ioc->mfcnt);
5706#endif
5707
5708 /* Reset the adapter. Prevent more than 1 call to
5709 * mpt_do_ioc_recovery at any instant in time.
5710 */
5711 spin_lock_irqsave(&ioc->diagLock, flags);
5712 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5713 spin_unlock_irqrestore(&ioc->diagLock, flags);
5714 return 0;
5715 } else {
5716 ioc->diagPending = 1;
5717 }
5718 spin_unlock_irqrestore(&ioc->diagLock, flags);
5719
5720 /* FIXME: If do_ioc_recovery fails, repeat....
5721 */
5722
5723 /* The SCSI driver needs to adjust timeouts on all current
5724 * commands prior to the diagnostic reset being issued.
5725 * Prevents timeouts occuring during a diagnostic reset...very bad.
5726 * For all other protocol drivers, this is a no-op.
5727 */
5728 {
5729 int ii;
5730 int r = 0;
5731
5732 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5733 if (MptResetHandlers[ii]) {
5734 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5735 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005736 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 if (ioc->alt_ioc) {
5738 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5739 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005740 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 }
5742 }
5743 }
5744 }
5745
5746 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5747 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5748 rc, ioc->name);
5749 }
5750 ioc->reload_fw = 0;
5751 if (ioc->alt_ioc)
5752 ioc->alt_ioc->reload_fw = 0;
5753
5754 spin_lock_irqsave(&ioc->diagLock, flags);
5755 ioc->diagPending = 0;
5756 if (ioc->alt_ioc)
5757 ioc->alt_ioc->diagPending = 0;
5758 spin_unlock_irqrestore(&ioc->diagLock, flags);
5759
5760 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5761
5762 return rc;
5763}
5764
Eric Moore509e5e52006-04-26 13:22:37 -06005765# define EVENT_DESCR_STR_SZ 100
5766
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005768static void
5769EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770{
Eric Moore509e5e52006-04-26 13:22:37 -06005771 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
5773 switch(event) {
5774 case MPI_EVENT_NONE:
5775 ds = "None";
5776 break;
5777 case MPI_EVENT_LOG_DATA:
5778 ds = "Log Data";
5779 break;
5780 case MPI_EVENT_STATE_CHANGE:
5781 ds = "State Change";
5782 break;
5783 case MPI_EVENT_UNIT_ATTENTION:
5784 ds = "Unit Attention";
5785 break;
5786 case MPI_EVENT_IOC_BUS_RESET:
5787 ds = "IOC Bus Reset";
5788 break;
5789 case MPI_EVENT_EXT_BUS_RESET:
5790 ds = "External Bus Reset";
5791 break;
5792 case MPI_EVENT_RESCAN:
5793 ds = "Bus Rescan Event";
5794 /* Ok, do we need to do anything here? As far as
5795 I can tell, this is when a new device gets added
5796 to the loop. */
5797 break;
5798 case MPI_EVENT_LINK_STATUS_CHANGE:
5799 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5800 ds = "Link Status(FAILURE) Change";
5801 else
5802 ds = "Link Status(ACTIVE) Change";
5803 break;
5804 case MPI_EVENT_LOOP_STATE_CHANGE:
5805 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5806 ds = "Loop State(LIP) Change";
5807 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005808 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 else
Eric Moore509e5e52006-04-26 13:22:37 -06005810 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 break;
5812 case MPI_EVENT_LOGOUT:
5813 ds = "Logout";
5814 break;
5815 case MPI_EVENT_EVENT_CHANGE:
5816 if (evData0)
5817 ds = "Events(ON) Change";
5818 else
5819 ds = "Events(OFF) Change";
5820 break;
5821 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005822 {
5823 u8 ReasonCode = (u8)(evData0 >> 16);
5824 switch (ReasonCode) {
5825 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5826 ds = "Integrated Raid: Volume Created";
5827 break;
5828 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5829 ds = "Integrated Raid: Volume Deleted";
5830 break;
5831 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5832 ds = "Integrated Raid: Volume Settings Changed";
5833 break;
5834 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5835 ds = "Integrated Raid: Volume Status Changed";
5836 break;
5837 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5838 ds = "Integrated Raid: Volume Physdisk Changed";
5839 break;
5840 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5841 ds = "Integrated Raid: Physdisk Created";
5842 break;
5843 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5844 ds = "Integrated Raid: Physdisk Deleted";
5845 break;
5846 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5847 ds = "Integrated Raid: Physdisk Settings Changed";
5848 break;
5849 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5850 ds = "Integrated Raid: Physdisk Status Changed";
5851 break;
5852 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5853 ds = "Integrated Raid: Domain Validation Needed";
5854 break;
5855 case MPI_EVENT_RAID_RC_SMART_DATA :
5856 ds = "Integrated Raid; Smart Data";
5857 break;
5858 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5859 ds = "Integrated Raid: Replace Action Started";
5860 break;
5861 default:
5862 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005864 }
5865 break;
5866 }
5867 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5868 ds = "SCSI Device Status Change";
5869 break;
5870 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5871 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005872 u8 id = (u8)(evData0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005873 u8 ReasonCode = (u8)(evData0 >> 16);
5874 switch (ReasonCode) {
5875 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005876 snprintf(evStr, EVENT_DESCR_STR_SZ,
5877 "SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005878 break;
5879 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005880 snprintf(evStr, EVENT_DESCR_STR_SZ,
5881 "SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005882 break;
5883 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005884 snprintf(evStr, EVENT_DESCR_STR_SZ,
5885 "SAS Device Status Change: SMART Data: id=%d",
5886 id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005887 break;
5888 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005889 snprintf(evStr, EVENT_DESCR_STR_SZ,
5890 "SAS Device Status Change: No Persistancy "
5891 "Added: id=%d", id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005892 break;
5893 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005894 snprintf(evStr, EVENT_DESCR_STR_SZ,
5895 "SAS Device Status Change: Unknown: id=%d", id);
5896 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005897 }
5898 break;
5899 }
5900 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5901 ds = "Bus Timer Expired";
5902 break;
5903 case MPI_EVENT_QUEUE_FULL:
5904 ds = "Queue Full";
5905 break;
5906 case MPI_EVENT_SAS_SES:
5907 ds = "SAS SES Event";
5908 break;
5909 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5910 ds = "Persistent Table Full";
5911 break;
5912 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005913 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005914 u8 LinkRates = (u8)(evData0 >> 8);
5915 u8 PhyNumber = (u8)(evData0);
5916 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5917 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5918 switch (LinkRates) {
5919 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06005920 snprintf(evStr, EVENT_DESCR_STR_SZ,
5921 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005922 " Rate Unknown",PhyNumber);
5923 break;
5924 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06005925 snprintf(evStr, EVENT_DESCR_STR_SZ,
5926 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005927 " Phy Disabled",PhyNumber);
5928 break;
5929 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06005930 snprintf(evStr, EVENT_DESCR_STR_SZ,
5931 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005932 " Failed Speed Nego",PhyNumber);
5933 break;
5934 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06005935 snprintf(evStr, EVENT_DESCR_STR_SZ,
5936 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005937 " Sata OOB Completed",PhyNumber);
5938 break;
5939 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06005940 snprintf(evStr, EVENT_DESCR_STR_SZ,
5941 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005942 " Rate 1.5 Gbps",PhyNumber);
5943 break;
5944 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06005945 snprintf(evStr, EVENT_DESCR_STR_SZ,
5946 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005947 " Rate 3.0 Gpbs",PhyNumber);
5948 break;
5949 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005950 snprintf(evStr, EVENT_DESCR_STR_SZ,
5951 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07005952 break;
5953 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005954 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005955 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005956 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5957 ds = "SAS Discovery Error";
5958 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005959 case MPI_EVENT_IR_RESYNC_UPDATE:
5960 {
5961 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06005962 snprintf(evStr, EVENT_DESCR_STR_SZ,
5963 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07005964 break;
5965 }
5966 case MPI_EVENT_IR2:
5967 {
5968 u8 ReasonCode = (u8)(evData0 >> 16);
5969 switch (ReasonCode) {
5970 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5971 ds = "IR2: LD State Changed";
5972 break;
5973 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5974 ds = "IR2: PD State Changed";
5975 break;
5976 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5977 ds = "IR2: Bad Block Table Full";
5978 break;
5979 case MPI_EVENT_IR2_RC_PD_INSERTED:
5980 ds = "IR2: PD Inserted";
5981 break;
5982 case MPI_EVENT_IR2_RC_PD_REMOVED:
5983 ds = "IR2: PD Removed";
5984 break;
5985 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5986 ds = "IR2: Foreign CFG Detected";
5987 break;
5988 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5989 ds = "IR2: Rebuild Medium Error";
5990 break;
5991 default:
5992 ds = "IR2";
5993 break;
5994 }
5995 break;
5996 }
5997 case MPI_EVENT_SAS_DISCOVERY:
5998 {
5999 if (evData0)
6000 ds = "SAS Discovery: Start";
6001 else
6002 ds = "SAS Discovery: Stop";
6003 break;
6004 }
6005 case MPI_EVENT_LOG_ENTRY_ADDED:
6006 ds = "SAS Log Entry Added";
6007 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006008
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009 /*
6010 * MPT base "custom" events may be added here...
6011 */
6012 default:
6013 ds = "Unknown";
6014 break;
6015 }
Eric Moore509e5e52006-04-26 13:22:37 -06006016 if (ds)
6017 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018}
6019
6020/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6021/*
6022 * ProcessEventNotification - Route a received EventNotificationReply to
6023 * all currently regeistered event handlers.
6024 * @ioc: Pointer to MPT_ADAPTER structure
6025 * @pEventReply: Pointer to EventNotification reply frame
6026 * @evHandlers: Pointer to integer, number of event handlers
6027 *
6028 * Returns sum of event handlers return values.
6029 */
6030static int
6031ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6032{
6033 u16 evDataLen;
6034 u32 evData0 = 0;
6035// u32 evCtx;
6036 int ii;
6037 int r = 0;
6038 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006039 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040 u8 event;
6041
6042 /*
6043 * Do platform normalization of values
6044 */
6045 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6046// evCtx = le32_to_cpu(pEventReply->EventContext);
6047 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6048 if (evDataLen) {
6049 evData0 = le32_to_cpu(pEventReply->Data[0]);
6050 }
6051
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006052 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07006053 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006055 event,
6056 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057
Moore, Eric3a892be2006-03-14 09:14:03 -07006058#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6060 for (ii = 0; ii < evDataLen; ii++)
6061 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6062 printk("\n");
6063#endif
6064
6065 /*
6066 * Do general / base driver event processing
6067 */
6068 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6070 if (evDataLen) {
6071 u8 evState = evData0 & 0xFF;
6072
6073 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6074
6075 /* Update EventState field in cached IocFacts */
6076 if (ioc->facts.Function) {
6077 ioc->facts.EventState = evState;
6078 }
6079 }
6080 break;
Moore, Ericece50912006-01-16 18:53:19 -07006081 case MPI_EVENT_INTEGRATED_RAID:
6082 mptbase_raid_process_event_data(ioc,
6083 (MpiEventDataRaid_t *)pEventReply->Data);
6084 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006085 default:
6086 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 }
6088
6089 /*
6090 * Should this event be logged? Events are written sequentially.
6091 * When buffer is full, start again at the top.
6092 */
6093 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6094 int idx;
6095
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006096 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097
6098 ioc->events[idx].event = event;
6099 ioc->events[idx].eventContext = ioc->eventContext;
6100
6101 for (ii = 0; ii < 2; ii++) {
6102 if (ii < evDataLen)
6103 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6104 else
6105 ioc->events[idx].data[ii] = 0;
6106 }
6107
6108 ioc->eventContext++;
6109 }
6110
6111
6112 /*
6113 * Call each currently registered protocol event handler.
6114 */
6115 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6116 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006117 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 ioc->name, ii));
6119 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6120 handlers++;
6121 }
6122 }
6123 /* FIXME? Examine results here? */
6124
6125 /*
6126 * If needed, send (a single) EventAck.
6127 */
6128 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006129 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006130 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006132 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133 ioc->name, ii));
6134 }
6135 }
6136
6137 *evHandlers = handlers;
6138 return r;
6139}
6140
6141/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6142/*
6143 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6144 * @ioc: Pointer to MPT_ADAPTER structure
6145 * @log_info: U32 LogInfo reply word from the IOC
6146 *
6147 * Refer to lsi/fc_log.h.
6148 */
6149static void
6150mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6151{
6152 static char *subcl_str[8] = {
6153 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6154 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6155 };
6156 u8 subcl = (log_info >> 24) & 0x7;
6157
6158 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6159 ioc->name, log_info, subcl_str[subcl]);
6160}
6161
6162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6163/*
Moore, Eric335a9412006-01-17 17:06:23 -07006164 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165 * @ioc: Pointer to MPT_ADAPTER structure
6166 * @mr: Pointer to MPT reply frame
6167 * @log_info: U32 LogInfo word from the IOC
6168 *
6169 * Refer to lsi/sp_log.h.
6170 */
6171static void
Moore, Eric335a9412006-01-17 17:06:23 -07006172mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173{
6174 u32 info = log_info & 0x00FF0000;
6175 char *desc = "unknown";
6176
6177 switch (info) {
6178 case 0x00010000:
6179 desc = "bug! MID not found";
6180 if (ioc->reload_fw == 0)
6181 ioc->reload_fw++;
6182 break;
6183
6184 case 0x00020000:
6185 desc = "Parity Error";
6186 break;
6187
6188 case 0x00030000:
6189 desc = "ASYNC Outbound Overrun";
6190 break;
6191
6192 case 0x00040000:
6193 desc = "SYNC Offset Error";
6194 break;
6195
6196 case 0x00050000:
6197 desc = "BM Change";
6198 break;
6199
6200 case 0x00060000:
6201 desc = "Msg In Overflow";
6202 break;
6203
6204 case 0x00070000:
6205 desc = "DMA Error";
6206 break;
6207
6208 case 0x00080000:
6209 desc = "Outbound DMA Overrun";
6210 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006211
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 case 0x00090000:
6213 desc = "Task Management";
6214 break;
6215
6216 case 0x000A0000:
6217 desc = "Device Problem";
6218 break;
6219
6220 case 0x000B0000:
6221 desc = "Invalid Phase Change";
6222 break;
6223
6224 case 0x000C0000:
6225 desc = "Untagged Table Size";
6226 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006227
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228 }
6229
6230 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6231}
6232
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006233/* strings for sas loginfo */
6234 static char *originator_str[] = {
6235 "IOP", /* 00h */
6236 "PL", /* 01h */
6237 "IR" /* 02h */
6238 };
6239 static char *iop_code_str[] = {
6240 NULL, /* 00h */
6241 "Invalid SAS Address", /* 01h */
6242 NULL, /* 02h */
6243 "Invalid Page", /* 03h */
6244 NULL, /* 04h */
6245 "Task Terminated" /* 05h */
6246 };
6247 static char *pl_code_str[] = {
6248 NULL, /* 00h */
6249 "Open Failure", /* 01h */
6250 "Invalid Scatter Gather List", /* 02h */
6251 "Wrong Relative Offset or Frame Length", /* 03h */
6252 "Frame Transfer Error", /* 04h */
6253 "Transmit Frame Connected Low", /* 05h */
6254 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6255 "SATA Read Log Receive Data Error", /* 07h */
6256 "SATA NCQ Fail All Commands After Error", /* 08h */
6257 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6258 "Receive Frame Invalid Message", /* 0Ah */
6259 "Receive Context Message Valid Error", /* 0Bh */
6260 "Receive Frame Current Frame Error", /* 0Ch */
6261 "SATA Link Down", /* 0Dh */
6262 "Discovery SATA Init W IOS", /* 0Eh */
6263 "Config Invalid Page", /* 0Fh */
6264 "Discovery SATA Init Timeout", /* 10h */
6265 "Reset", /* 11h */
6266 "Abort", /* 12h */
6267 "IO Not Yet Executed", /* 13h */
6268 "IO Executed", /* 14h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006269 "Persistant Reservation Out Not Affiliation Owner", /* 15h */
6270 "Open Transmit DMA Abort", /* 16h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006271 NULL, /* 17h */
6272 NULL, /* 18h */
6273 NULL, /* 19h */
6274 NULL, /* 1Ah */
6275 NULL, /* 1Bh */
6276 NULL, /* 1Ch */
6277 NULL, /* 1Dh */
6278 NULL, /* 1Eh */
6279 NULL, /* 1Fh */
6280 "Enclosure Management" /* 20h */
6281 };
6282
6283/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6284/*
6285 * mpt_sas_log_info - Log information returned from SAS IOC.
6286 * @ioc: Pointer to MPT_ADAPTER structure
6287 * @log_info: U32 LogInfo reply word from the IOC
6288 *
6289 * Refer to lsi/mpi_log_sas.h.
6290 */
6291static void
6292mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6293{
6294union loginfo_type {
6295 u32 loginfo;
6296 struct {
6297 u32 subcode:16;
6298 u32 code:8;
6299 u32 originator:4;
6300 u32 bus_type:4;
6301 }dw;
6302};
6303 union loginfo_type sas_loginfo;
6304 char *code_desc = NULL;
6305
6306 sas_loginfo.loginfo = log_info;
6307 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6308 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6309 return;
6310 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6311 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6312 code_desc = iop_code_str[sas_loginfo.dw.code];
6313 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6314 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6315 code_desc = pl_code_str[sas_loginfo.dw.code];
6316 }
6317
6318 if (code_desc != NULL)
6319 printk(MYIOC_s_INFO_FMT
6320 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6321 " SubCode(0x%04x)\n",
6322 ioc->name,
6323 log_info,
6324 originator_str[sas_loginfo.dw.originator],
6325 code_desc,
6326 sas_loginfo.dw.subcode);
6327 else
6328 printk(MYIOC_s_INFO_FMT
6329 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6330 " SubCode(0x%04x)\n",
6331 ioc->name,
6332 log_info,
6333 originator_str[sas_loginfo.dw.originator],
6334 sas_loginfo.dw.code,
6335 sas_loginfo.dw.subcode);
6336}
6337
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6339/*
6340 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6341 * @ioc: Pointer to MPT_ADAPTER structure
6342 * @ioc_status: U32 IOCStatus word from IOC
6343 * @mf: Pointer to MPT request frame
6344 *
6345 * Refer to lsi/mpi.h.
6346 */
6347static void
6348mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6349{
6350 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
6351 char *desc = "";
6352
6353 switch (status) {
6354 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6355 desc = "Invalid Function";
6356 break;
6357
6358 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6359 desc = "Busy";
6360 break;
6361
6362 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6363 desc = "Invalid SGL";
6364 break;
6365
6366 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6367 desc = "Internal Error";
6368 break;
6369
6370 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6371 desc = "Reserved";
6372 break;
6373
6374 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6375 desc = "Insufficient Resources";
6376 break;
6377
6378 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6379 desc = "Invalid Field";
6380 break;
6381
6382 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6383 desc = "Invalid State";
6384 break;
6385
6386 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6387 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6388 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6389 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6390 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6391 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6392 /* No message for Config IOCStatus values */
6393 break;
6394
6395 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6396 /* No message for recovered error
6397 desc = "SCSI Recovered Error";
6398 */
6399 break;
6400
6401 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6402 desc = "SCSI Invalid Bus";
6403 break;
6404
6405 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6406 desc = "SCSI Invalid TargetID";
6407 break;
6408
6409 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6410 {
6411 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6412 U8 cdb = pScsiReq->CDB[0];
6413 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6414 desc = "SCSI Device Not There";
6415 }
6416 break;
6417 }
6418
6419 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6420 desc = "SCSI Data Overrun";
6421 break;
6422
6423 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006424 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425 desc = "SCSI Data Underrun";
6426 */
6427 break;
6428
6429 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6430 desc = "SCSI I/O Data Error";
6431 break;
6432
6433 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6434 desc = "SCSI Protocol Error";
6435 break;
6436
6437 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6438 desc = "SCSI Task Terminated";
6439 break;
6440
6441 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6442 desc = "SCSI Residual Mismatch";
6443 break;
6444
6445 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6446 desc = "SCSI Task Management Failed";
6447 break;
6448
6449 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6450 desc = "SCSI IOC Terminated";
6451 break;
6452
6453 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6454 desc = "SCSI Ext Terminated";
6455 break;
6456
6457 default:
6458 desc = "Others";
6459 break;
6460 }
6461 if (desc != "")
6462 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6463}
6464
6465/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006466EXPORT_SYMBOL(mpt_attach);
6467EXPORT_SYMBOL(mpt_detach);
6468#ifdef CONFIG_PM
6469EXPORT_SYMBOL(mpt_resume);
6470EXPORT_SYMBOL(mpt_suspend);
6471#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006472EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006473EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474EXPORT_SYMBOL(mpt_register);
6475EXPORT_SYMBOL(mpt_deregister);
6476EXPORT_SYMBOL(mpt_event_register);
6477EXPORT_SYMBOL(mpt_event_deregister);
6478EXPORT_SYMBOL(mpt_reset_register);
6479EXPORT_SYMBOL(mpt_reset_deregister);
6480EXPORT_SYMBOL(mpt_device_driver_register);
6481EXPORT_SYMBOL(mpt_device_driver_deregister);
6482EXPORT_SYMBOL(mpt_get_msg_frame);
6483EXPORT_SYMBOL(mpt_put_msg_frame);
6484EXPORT_SYMBOL(mpt_free_msg_frame);
6485EXPORT_SYMBOL(mpt_add_sge);
6486EXPORT_SYMBOL(mpt_send_handshake_request);
6487EXPORT_SYMBOL(mpt_verify_adapter);
6488EXPORT_SYMBOL(mpt_GetIocState);
6489EXPORT_SYMBOL(mpt_print_ioc_summary);
6490EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006491EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006492EXPORT_SYMBOL(mpt_HardResetHandler);
6493EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006494EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495EXPORT_SYMBOL(mpt_alloc_fw_memory);
6496EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006497EXPORT_SYMBOL(mptbase_sas_persist_operation);
Michael Reed05e8ec12006-01-13 14:31:54 -06006498EXPORT_SYMBOL(mptbase_GetFcPortPage0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006499
Linus Torvalds1da177e2005-04-16 15:20:36 -07006500
6501/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6502/*
6503 * fusion_init - Fusion MPT base driver initialization routine.
6504 *
6505 * Returns 0 for success, non-zero for failure.
6506 */
6507static int __init
6508fusion_init(void)
6509{
6510 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006511
6512 show_mptmod_ver(my_NAME, my_VERSION);
6513 printk(KERN_INFO COPYRIGHT "\n");
6514
6515 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6516 MptCallbacks[i] = NULL;
6517 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6518 MptEvHandlers[i] = NULL;
6519 MptResetHandlers[i] = NULL;
6520 }
6521
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006522 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523 * EventNotification handling.
6524 */
6525 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6526
6527 /* Register for hard reset handling callbacks.
6528 */
6529 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6530 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6531 } else {
6532 /* FIXME! */
6533 }
6534
6535#ifdef CONFIG_PROC_FS
6536 (void) procmpt_create();
6537#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006538 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006539}
6540
6541/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6542/*
6543 * fusion_exit - Perform driver unload cleanup.
6544 *
6545 * This routine frees all resources associated with each MPT adapter
6546 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6547 */
6548static void __exit
6549fusion_exit(void)
6550{
6551
6552 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6553
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554 mpt_reset_deregister(mpt_base_index);
6555
6556#ifdef CONFIG_PROC_FS
6557 procmpt_destroy();
6558#endif
6559}
6560
Linus Torvalds1da177e2005-04-16 15:20:36 -07006561module_init(fusion_init);
6562module_exit(fusion_exit);