1 |
1275 |
phoenix |
/*
|
2 |
|
|
* linux/drivers/message/fusion/mptbase.c
|
3 |
|
|
* High performance SCSI + LAN / Fibre Channel device drivers.
|
4 |
|
|
* This is the Fusion MPT base driver which supports multiple
|
5 |
|
|
* (SCSI + LAN) specialized protocol drivers.
|
6 |
|
|
* For use with PCI chip/adapter(s):
|
7 |
|
|
* LSIFC9xx/LSI409xx Fibre Channel
|
8 |
|
|
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
|
9 |
|
|
*
|
10 |
|
|
* Credits:
|
11 |
|
|
* There are lots of people not mentioned below that deserve credit
|
12 |
|
|
* and thanks but won't get it here - sorry in advance that you
|
13 |
|
|
* got overlooked.
|
14 |
|
|
*
|
15 |
|
|
* This driver would not exist if not for Alan Cox's development
|
16 |
|
|
* of the linux i2o driver.
|
17 |
|
|
*
|
18 |
|
|
* A special thanks to Noah Romer (LSI Logic) for tons of work
|
19 |
|
|
* and tough debugging on the LAN driver, especially early on;-)
|
20 |
|
|
* And to Roger Hickerson (LSI Logic) for tirelessly supporting
|
21 |
|
|
* this driver project.
|
22 |
|
|
*
|
23 |
|
|
* A special thanks to Pamela Delaney (LSI Logic) for tons of work
|
24 |
|
|
* and countless enhancements while adding support for the 1030
|
25 |
|
|
* chip family. Pam has been instrumental in the development of
|
26 |
|
|
* of the 2.xx.xx series fusion drivers, and her contributions are
|
27 |
|
|
* far too numerous to hope to list in one place.
|
28 |
|
|
*
|
29 |
|
|
* All manner of help from Stephen Shirron (LSI Logic):
|
30 |
|
|
* low-level FC analysis, debug + various fixes in FCxx firmware,
|
31 |
|
|
* initial port to alpha platform, various driver code optimizations,
|
32 |
|
|
* being a faithful sounding board on all sorts of issues & ideas,
|
33 |
|
|
* etc.
|
34 |
|
|
*
|
35 |
|
|
* A huge debt of gratitude is owed to David S. Miller (DaveM)
|
36 |
|
|
* for fixing much of the stupid and broken stuff in the early
|
37 |
|
|
* driver while porting to sparc64 platform. THANK YOU!
|
38 |
|
|
*
|
39 |
|
|
* Special thanks goes to the I2O LAN driver people at the
|
40 |
|
|
* University of Helsinki, who, unbeknownst to them, provided
|
41 |
|
|
* the inspiration and initial structure for this driver.
|
42 |
|
|
*
|
43 |
|
|
* A really huge debt of gratitude is owed to Eddie C. Dost
|
44 |
|
|
* for gobs of hard work fixing and optimizing LAN code.
|
45 |
|
|
* THANK YOU!
|
46 |
|
|
*
|
47 |
|
|
* Copyright (c) 1999-2002 LSI Logic Corporation
|
48 |
|
|
* Originally By: Steven J. Ralston
|
49 |
|
|
* (mailto:sjralston1@netscape.net)
|
50 |
|
|
* (mailto:mpt_linux_developer@lsil.com)
|
51 |
|
|
*
|
52 |
|
|
* $Id: mptbase.c,v 1.1.1.1 2004-04-15 02:27:30 phoenix Exp $
|
53 |
|
|
*/
|
54 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
55 |
|
|
/*
|
56 |
|
|
This program is free software; you can redistribute it and/or modify
|
57 |
|
|
it under the terms of the GNU General Public License as published by
|
58 |
|
|
the Free Software Foundation; version 2 of the License.
|
59 |
|
|
|
60 |
|
|
This program is distributed in the hope that it will be useful,
|
61 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
62 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
63 |
|
|
GNU General Public License for more details.
|
64 |
|
|
|
65 |
|
|
NO WARRANTY
|
66 |
|
|
THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
|
67 |
|
|
CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
68 |
|
|
LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
69 |
|
|
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
|
70 |
|
|
solely responsible for determining the appropriateness of using and
|
71 |
|
|
distributing the Program and assumes all risks associated with its
|
72 |
|
|
exercise of rights under this Agreement, including but not limited to
|
73 |
|
|
the risks and costs of program errors, damage to or loss of data,
|
74 |
|
|
programs or equipment, and unavailability or interruption of operations.
|
75 |
|
|
|
76 |
|
|
DISCLAIMER OF LIABILITY
|
77 |
|
|
NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
|
78 |
|
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
79 |
|
|
DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
|
80 |
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
81 |
|
|
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
82 |
|
|
USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
83 |
|
|
HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
|
84 |
|
|
|
85 |
|
|
You should have received a copy of the GNU General Public License
|
86 |
|
|
along with this program; if not, write to the Free Software
|
87 |
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
88 |
|
|
*/
|
89 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
90 |
|
|
|
91 |
|
|
#include <linux/config.h>
|
92 |
|
|
#include <linux/version.h>
|
93 |
|
|
#include <linux/kernel.h>
|
94 |
|
|
#include <linux/module.h>
|
95 |
|
|
#include <linux/errno.h>
|
96 |
|
|
#include <linux/init.h>
|
97 |
|
|
#include <linux/slab.h>
|
98 |
|
|
#include <linux/types.h>
|
99 |
|
|
#include <linux/pci.h>
|
100 |
|
|
#include <linux/kdev_t.h>
|
101 |
|
|
#include <linux/blkdev.h>
|
102 |
|
|
#include <linux/delay.h>
|
103 |
|
|
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
|
104 |
|
|
#include <asm/io.h>
|
105 |
|
|
#ifdef CONFIG_MTRR
|
106 |
|
|
#include <asm/mtrr.h>
|
107 |
|
|
#endif
|
108 |
|
|
#ifdef __sparc__
|
109 |
|
|
#include <asm/irq.h> /* needed for __irq_itoa() proto */
|
110 |
|
|
#endif
|
111 |
|
|
|
112 |
|
|
#include "mptbase.h"
|
113 |
|
|
|
114 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
115 |
|
|
#define my_NAME "Fusion MPT base driver"
|
116 |
|
|
#define my_VERSION MPT_LINUX_VERSION_COMMON
|
117 |
|
|
#define MYNAM "mptbase"
|
118 |
|
|
|
119 |
|
|
MODULE_AUTHOR(MODULEAUTHOR);
|
120 |
|
|
MODULE_DESCRIPTION(my_NAME);
|
121 |
|
|
MODULE_LICENSE("GPL");
|
122 |
|
|
|
123 |
|
|
/*
|
124 |
|
|
* cmd line parameters
|
125 |
|
|
*/
|
126 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,59)
|
127 |
|
|
MODULE_PARM(PortIo, "0-1i");
|
128 |
|
|
MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io");
|
129 |
|
|
#endif
|
130 |
|
|
static int PortIo = 0;
|
131 |
|
|
|
132 |
|
|
#ifdef MFCNT
|
133 |
|
|
static int mfcounter = 0;
|
134 |
|
|
#define PRINT_MF_COUNT 20000
|
135 |
|
|
#endif
|
136 |
|
|
|
137 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
138 |
|
|
/*
|
139 |
|
|
* Public data...
|
140 |
|
|
*/
|
141 |
|
|
int mpt_lan_index = -1;
|
142 |
|
|
int mpt_stm_index = -1;
|
143 |
|
|
|
144 |
|
|
struct proc_dir_entry *mpt_proc_root_dir;
|
145 |
|
|
|
146 |
|
|
DmpServices_t *DmpService;
|
147 |
|
|
|
148 |
|
|
void *mpt_v_ASCQ_TablePtr;
|
149 |
|
|
const char **mpt_ScsiOpcodesPtr;
|
150 |
|
|
int mpt_ASCQ_TableSz;
|
151 |
|
|
|
152 |
|
|
|
153 |
|
|
#define WHOINIT_UNKNOWN 0xAA
|
154 |
|
|
|
155 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
156 |
|
|
/*
|
157 |
|
|
* Private data...
|
158 |
|
|
*/
|
159 |
|
|
/* Adapter lookup table */
|
160 |
|
|
MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS];
|
161 |
|
|
static MPT_ADAPTER_TRACKER MptAdapters;
|
162 |
|
|
/* Callback lookup table */
|
163 |
|
|
static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
|
164 |
|
|
/* Protocol driver class lookup table */
|
165 |
|
|
static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
|
166 |
|
|
/* Event handler lookup table */
|
167 |
|
|
static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
|
168 |
|
|
/* Reset handler lookup table */
|
169 |
|
|
static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
|
170 |
|
|
|
171 |
|
|
static int FusionInitCalled = 0;
|
172 |
|
|
static int mpt_base_index = -1;
|
173 |
|
|
static int last_drv_idx = -1;
|
174 |
|
|
static int isense_idx = -1;
|
175 |
|
|
|
176 |
|
|
static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
|
177 |
|
|
|
178 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
179 |
|
|
/*
|
180 |
|
|
* Forward protos...
|
181 |
|
|
*/
|
182 |
|
|
static void mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
|
183 |
|
|
static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
|
184 |
|
|
|
185 |
|
|
static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
|
186 |
|
|
static int mpt_adapter_install(struct pci_dev *pdev);
|
187 |
|
|
static void mpt_detect_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
|
188 |
|
|
static void mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup);
|
189 |
|
|
static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
|
190 |
|
|
|
191 |
|
|
static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
|
192 |
|
|
static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
|
193 |
|
|
//static u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
|
194 |
|
|
static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
|
195 |
|
|
static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
|
196 |
|
|
static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
|
197 |
|
|
static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
|
198 |
|
|
static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
|
199 |
|
|
static int mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag);
|
200 |
|
|
static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
|
201 |
|
|
static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
|
202 |
|
|
static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
|
203 |
|
|
static int PrimeIocFifos(MPT_ADAPTER *ioc);
|
204 |
|
|
static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
|
205 |
|
|
static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
|
206 |
|
|
static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
|
207 |
|
|
static int GetLanConfigPages(MPT_ADAPTER *ioc);
|
208 |
|
|
static int GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
|
209 |
|
|
static int GetIoUnitPage2(MPT_ADAPTER *ioc);
|
210 |
|
|
static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
|
211 |
|
|
static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
|
212 |
|
|
static int mpt_findImVolumes(MPT_ADAPTER *ioc);
|
213 |
|
|
static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
|
214 |
|
|
static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
|
215 |
|
|
static void mpt_timer_expired(unsigned long data);
|
216 |
|
|
static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
|
217 |
|
|
static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
|
218 |
|
|
|
219 |
|
|
#ifdef CONFIG_PROC_FS
|
220 |
|
|
static int procmpt_create(void);
|
221 |
|
|
static int procmpt_destroy(void);
|
222 |
|
|
static int procmpt_summary_read(char *buf, char **start, off_t offset,
|
223 |
|
|
int request, int *eof, void *data);
|
224 |
|
|
static int procmpt_version_read(char *buf, char **start, off_t offset,
|
225 |
|
|
int request, int *eof, void *data);
|
226 |
|
|
static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
|
227 |
|
|
int request, int *eof, void *data);
|
228 |
|
|
#endif
|
229 |
|
|
static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
|
230 |
|
|
|
231 |
|
|
//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
|
232 |
|
|
static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
|
233 |
|
|
static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
|
234 |
|
|
static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
|
235 |
|
|
|
236 |
|
|
int fusion_init(void);
|
237 |
|
|
static void fusion_exit(void);
|
238 |
|
|
|
239 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
240 |
|
|
/*
|
241 |
|
|
* more Private data...
|
242 |
|
|
*/
|
243 |
|
|
#ifdef CONFIG_PROC_FS
|
244 |
|
|
struct _mpt_proc_list {
|
245 |
|
|
const char *name;
|
246 |
|
|
int (*f)(char *, char **, off_t, int, int *, void *);
|
247 |
|
|
} mpt_proc_list[] = {
|
248 |
|
|
{ "summary", procmpt_summary_read},
|
249 |
|
|
{ "version", procmpt_version_read},
|
250 |
|
|
};
|
251 |
|
|
#define MPT_PROC_ENTRIES (sizeof(mpt_proc_list)/sizeof(mpt_proc_list[0]))
|
252 |
|
|
|
253 |
|
|
struct _mpt_ioc_proc_list {
|
254 |
|
|
const char *name;
|
255 |
|
|
int (*f)(char *, char **, off_t, int, int *, void *);
|
256 |
|
|
} mpt_ioc_proc_list[] = {
|
257 |
|
|
{ "info", procmpt_iocinfo_read},
|
258 |
|
|
{ "summary", procmpt_summary_read},
|
259 |
|
|
};
|
260 |
|
|
#define MPT_IOC_PROC_ENTRIES (sizeof(mpt_ioc_proc_list)/sizeof(mpt_ioc_proc_list[0]))
|
261 |
|
|
|
262 |
|
|
#endif
|
263 |
|
|
|
264 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
265 |
|
|
/* 20000207 -sralston
|
266 |
|
|
* GRRRRR... IOSpace (port i/o) register access (for the 909) is back!
|
267 |
|
|
* 20000517 -sralston
|
268 |
|
|
* Let's trying going back to default mmap register access...
|
269 |
|
|
*/
|
270 |
|
|
|
271 |
|
|
static inline u32 CHIPREG_READ32(volatile u32 *a)
|
272 |
|
|
{
|
273 |
|
|
if (PortIo)
|
274 |
|
|
return inl((unsigned long)a);
|
275 |
|
|
else
|
276 |
|
|
return readl(a);
|
277 |
|
|
}
|
278 |
|
|
|
279 |
|
|
static inline void CHIPREG_WRITE32(volatile u32 *a, u32 v)
|
280 |
|
|
{
|
281 |
|
|
if (PortIo)
|
282 |
|
|
outl(v, (unsigned long)a);
|
283 |
|
|
else
|
284 |
|
|
writel(v, a);
|
285 |
|
|
}
|
286 |
|
|
|
287 |
|
|
static inline void CHIPREG_PIO_WRITE32(volatile u32 *a, u32 v)
|
288 |
|
|
{
|
289 |
|
|
outl(v, (unsigned long)a);
|
290 |
|
|
}
|
291 |
|
|
|
292 |
|
|
static inline u32 CHIPREG_PIO_READ32(volatile u32 *a)
|
293 |
|
|
{
|
294 |
|
|
return inl((unsigned long)a);
|
295 |
|
|
}
|
296 |
|
|
|
297 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
298 |
|
|
/*
|
299 |
|
|
* mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
|
300 |
|
|
* @irq: irq number (not used)
|
301 |
|
|
* @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
|
302 |
|
|
* @r: pt_regs pointer (not used)
|
303 |
|
|
*
|
304 |
|
|
* This routine is registered via the request_irq() kernel API call,
|
305 |
|
|
* and handles all interrupts generated from a specific MPT adapter
|
306 |
|
|
* (also referred to as a IO Controller or IOC).
|
307 |
|
|
* This routine must clear the interrupt from the adapter and does
|
308 |
|
|
* so by reading the reply FIFO. Multiple replies may be processed
|
309 |
|
|
* per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR
|
310 |
|
|
* which is currently set to 32 in mptbase.h.
|
311 |
|
|
*
|
312 |
|
|
* This routine handles register-level access of the adapter but
|
313 |
|
|
* dispatches (calls) a protocol-specific callback routine to handle
|
314 |
|
|
* the protocol-specific details of the MPT request completion.
|
315 |
|
|
*/
|
316 |
|
|
static void
|
317 |
|
|
mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
|
318 |
|
|
{
|
319 |
|
|
MPT_ADAPTER *ioc;
|
320 |
|
|
MPT_FRAME_HDR *mf;
|
321 |
|
|
MPT_FRAME_HDR *mr;
|
322 |
|
|
u32 pa;
|
323 |
|
|
int req_idx;
|
324 |
|
|
int cb_idx;
|
325 |
|
|
int type;
|
326 |
|
|
int freeme;
|
327 |
|
|
|
328 |
|
|
ioc = bus_id;
|
329 |
|
|
|
330 |
|
|
#ifdef MPT_DEBUG_IRQ
|
331 |
|
|
/*
|
332 |
|
|
* Verify ioc pointer is ok
|
333 |
|
|
*/
|
334 |
|
|
{
|
335 |
|
|
MPT_ADAPTER *iocCmp;
|
336 |
|
|
iocCmp = mpt_adapter_find_first();
|
337 |
|
|
while ((ioc != iocCmp) && iocCmp)
|
338 |
|
|
iocCmp = mpt_adapter_find_next(iocCmp);
|
339 |
|
|
|
340 |
|
|
if (!iocCmp) {
|
341 |
|
|
printk(KERN_WARNING "mpt_interrupt: Invalid ioc!\n");
|
342 |
|
|
return;
|
343 |
|
|
}
|
344 |
|
|
}
|
345 |
|
|
#endif
|
346 |
|
|
|
347 |
|
|
/*
|
348 |
|
|
* Drain the reply FIFO!
|
349 |
|
|
*
|
350 |
|
|
* NOTES: I've seen up to 10 replies processed in this loop, so far...
|
351 |
|
|
* Update: I've seen up to 9182 replies processed in this loop! ??
|
352 |
|
|
* Update: Limit ourselves to processing max of N replies
|
353 |
|
|
* (bottom of loop).
|
354 |
|
|
*/
|
355 |
|
|
while (1) {
|
356 |
|
|
|
357 |
|
|
if ((pa = CHIPREG_READ32(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF)
|
358 |
|
|
return;
|
359 |
|
|
|
360 |
|
|
cb_idx = 0;
|
361 |
|
|
freeme = 0;
|
362 |
|
|
|
363 |
|
|
/*
|
364 |
|
|
* Check for non-TURBO reply!
|
365 |
|
|
*/
|
366 |
|
|
if (pa & MPI_ADDRESS_REPLY_A_BIT) {
|
367 |
|
|
u32 reply_dma_low;
|
368 |
|
|
u16 ioc_stat;
|
369 |
|
|
|
370 |
|
|
/* non-TURBO reply! Hmmm, something may be up...
|
371 |
|
|
* Newest turbo reply mechanism; get address
|
372 |
|
|
* via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
|
373 |
|
|
*/
|
374 |
|
|
|
375 |
|
|
/* Map DMA address of reply header to cpu address.
|
376 |
|
|
* pa is 32 bits - but the dma address may be 32 or 64 bits
|
377 |
|
|
* get offset based only only the low addresses
|
378 |
|
|
*/
|
379 |
|
|
reply_dma_low = (pa = (pa << 1));
|
380 |
|
|
mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
|
381 |
|
|
(reply_dma_low - ioc->reply_frames_low_dma));
|
382 |
|
|
|
383 |
|
|
req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
|
384 |
|
|
cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
|
385 |
|
|
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
|
386 |
|
|
|
387 |
|
|
dprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p\n",
|
388 |
|
|
ioc->name, mr));
|
389 |
|
|
DBG_DUMP_REPLY_FRAME(mr)
|
390 |
|
|
|
391 |
|
|
/* NEW! 20010301 -sralston
|
392 |
|
|
* Check/log IOC log info
|
393 |
|
|
*/
|
394 |
|
|
ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
|
395 |
|
|
if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
|
396 |
|
|
u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
|
397 |
|
|
if ((int)ioc->chip_type <= (int)FC929)
|
398 |
|
|
mpt_fc_log_info(ioc, log_info);
|
399 |
|
|
else
|
400 |
|
|
mpt_sp_log_info(ioc, log_info);
|
401 |
|
|
}
|
402 |
|
|
} else {
|
403 |
|
|
/*
|
404 |
|
|
* Process turbo (context) reply...
|
405 |
|
|
*/
|
406 |
|
|
dirqprintk((MYIOC_s_INFO_FMT "Got TURBO reply(=%08x)\n", ioc->name, pa));
|
407 |
|
|
type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT);
|
408 |
|
|
if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) {
|
409 |
|
|
cb_idx = mpt_stm_index;
|
410 |
|
|
mf = NULL;
|
411 |
|
|
mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
|
412 |
|
|
} else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) {
|
413 |
|
|
cb_idx = mpt_lan_index;
|
414 |
|
|
/*
|
415 |
|
|
* BUG FIX! 20001218 -sralston
|
416 |
|
|
* Blind set of mf to NULL here was fatal
|
417 |
|
|
* after lan_reply says "freeme"
|
418 |
|
|
* Fix sort of combined with an optimization here;
|
419 |
|
|
* added explicit check for case where lan_reply
|
420 |
|
|
* was just returning 1 and doing nothing else.
|
421 |
|
|
* For this case skip the callback, but set up
|
422 |
|
|
* proper mf value first here:-)
|
423 |
|
|
*/
|
424 |
|
|
if ((pa & 0x58000000) == 0x58000000) {
|
425 |
|
|
req_idx = pa & 0x0000FFFF;
|
426 |
|
|
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
|
427 |
|
|
freeme = 1;
|
428 |
|
|
/*
|
429 |
|
|
* IMPORTANT! Invalidate the callback!
|
430 |
|
|
*/
|
431 |
|
|
cb_idx = 0;
|
432 |
|
|
} else {
|
433 |
|
|
mf = NULL;
|
434 |
|
|
}
|
435 |
|
|
mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
|
436 |
|
|
} else {
|
437 |
|
|
req_idx = pa & 0x0000FFFF;
|
438 |
|
|
cb_idx = (pa & 0x00FF0000) >> 16;
|
439 |
|
|
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
|
440 |
|
|
mr = NULL;
|
441 |
|
|
}
|
442 |
|
|
pa = 0; /* No reply flush! */
|
443 |
|
|
}
|
444 |
|
|
|
445 |
|
|
#ifdef MPT_DEBUG_IRQ
|
446 |
|
|
if ((int)ioc->chip_type > (int)FC929) {
|
447 |
|
|
/* Verify mf, mr are reasonable.
|
448 |
|
|
*/
|
449 |
|
|
if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
|
450 |
|
|
|| (mf < ioc->req_frames)) ) {
|
451 |
|
|
printk(MYIOC_s_WARN_FMT
|
452 |
|
|
"mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx);
|
453 |
|
|
cb_idx = 0;
|
454 |
|
|
pa = 0;
|
455 |
|
|
freeme = 0;
|
456 |
|
|
}
|
457 |
|
|
if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
|
458 |
|
|
|| (mr < ioc->reply_frames)) ) {
|
459 |
|
|
printk(MYIOC_s_WARN_FMT
|
460 |
|
|
"mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr);
|
461 |
|
|
cb_idx = 0;
|
462 |
|
|
pa = 0;
|
463 |
|
|
freeme = 0;
|
464 |
|
|
}
|
465 |
|
|
if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) {
|
466 |
|
|
printk(MYIOC_s_WARN_FMT
|
467 |
|
|
"mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
|
468 |
|
|
cb_idx = 0;
|
469 |
|
|
pa = 0;
|
470 |
|
|
freeme = 0;
|
471 |
|
|
}
|
472 |
|
|
}
|
473 |
|
|
#endif
|
474 |
|
|
|
475 |
|
|
/* Check for (valid) IO callback! */
|
476 |
|
|
if (cb_idx) {
|
477 |
|
|
/* Do the callback! */
|
478 |
|
|
freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr);
|
479 |
|
|
}
|
480 |
|
|
|
481 |
|
|
if (pa) {
|
482 |
|
|
/* Flush (non-TURBO) reply with a WRITE! */
|
483 |
|
|
CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
|
484 |
|
|
}
|
485 |
|
|
|
486 |
|
|
if (freeme) {
|
487 |
|
|
unsigned long flags;
|
488 |
|
|
|
489 |
|
|
/* Put Request back on FreeQ! */
|
490 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
491 |
|
|
Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
|
492 |
|
|
#ifdef MFCNT
|
493 |
|
|
ioc->mfcnt--;
|
494 |
|
|
#endif
|
495 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
496 |
|
|
}
|
497 |
|
|
|
498 |
|
|
mb();
|
499 |
|
|
} /* drain reply FIFO */
|
500 |
|
|
}
|
501 |
|
|
|
502 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
503 |
|
|
/*
|
504 |
|
|
* mpt_base_reply - MPT base driver's callback routine; all base driver
|
505 |
|
|
* "internal" request/reply processing is routed here.
|
506 |
|
|
* Currently used for EventNotification and EventAck handling.
|
507 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
508 |
|
|
* @mf: Pointer to original MPT request frame
|
509 |
|
|
* @reply: Pointer to MPT reply frame (NULL if TurboReply)
|
510 |
|
|
*
|
511 |
|
|
* Returns 1 indicating original alloc'd request frame ptr
|
512 |
|
|
* should be freed, or 0 if it shouldn't.
|
513 |
|
|
*/
|
514 |
|
|
static int
|
515 |
|
|
mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
|
516 |
|
|
{
|
517 |
|
|
int freereq = 1;
|
518 |
|
|
u8 func;
|
519 |
|
|
|
520 |
|
|
dprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
|
521 |
|
|
|
522 |
|
|
if ((mf == NULL) ||
|
523 |
|
|
(mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
|
524 |
|
|
printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n",
|
525 |
|
|
ioc->name, (void *)mf);
|
526 |
|
|
return 1;
|
527 |
|
|
}
|
528 |
|
|
|
529 |
|
|
if (reply == NULL) {
|
530 |
|
|
dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n",
|
531 |
|
|
ioc->name));
|
532 |
|
|
return 1;
|
533 |
|
|
}
|
534 |
|
|
|
535 |
|
|
if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
|
536 |
|
|
dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
|
537 |
|
|
DBG_DUMP_REQUEST_FRAME_HDR(mf)
|
538 |
|
|
}
|
539 |
|
|
|
540 |
|
|
func = reply->u.hdr.Function;
|
541 |
|
|
dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
|
542 |
|
|
ioc->name, func));
|
543 |
|
|
|
544 |
|
|
if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
|
545 |
|
|
EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
|
546 |
|
|
int evHandlers = 0;
|
547 |
|
|
int results;
|
548 |
|
|
|
549 |
|
|
results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
|
550 |
|
|
if (results != evHandlers) {
|
551 |
|
|
/* CHECKME! Any special handling needed here? */
|
552 |
|
|
dprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
|
553 |
|
|
ioc->name, evHandlers, results));
|
554 |
|
|
}
|
555 |
|
|
|
556 |
|
|
/*
|
557 |
|
|
* Hmmm... It seems that EventNotificationReply is an exception
|
558 |
|
|
* to the rule of one reply per request.
|
559 |
|
|
*/
|
560 |
|
|
if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
|
561 |
|
|
freereq = 0;
|
562 |
|
|
|
563 |
|
|
#ifdef CONFIG_PROC_FS
|
564 |
|
|
// LogEvent(ioc, pEvReply);
|
565 |
|
|
#endif
|
566 |
|
|
|
567 |
|
|
} else if (func == MPI_FUNCTION_EVENT_ACK) {
|
568 |
|
|
dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
|
569 |
|
|
ioc->name));
|
570 |
|
|
} else if (func == MPI_FUNCTION_CONFIG) {
|
571 |
|
|
CONFIGPARMS *pCfg;
|
572 |
|
|
unsigned long flags;
|
573 |
|
|
|
574 |
|
|
dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
|
575 |
|
|
ioc->name, mf, reply));
|
576 |
|
|
|
577 |
|
|
pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
|
578 |
|
|
|
579 |
|
|
if (pCfg) {
|
580 |
|
|
/* disable timer and remove from linked list */
|
581 |
|
|
del_timer(&pCfg->timer);
|
582 |
|
|
|
583 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
584 |
|
|
Q_DEL_ITEM(&pCfg->linkage);
|
585 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
586 |
|
|
|
587 |
|
|
/*
|
588 |
|
|
* If IOC Status is SUCCESS, save the header
|
589 |
|
|
* and set the status code to GOOD.
|
590 |
|
|
*/
|
591 |
|
|
pCfg->status = MPT_CONFIG_ERROR;
|
592 |
|
|
if (reply) {
|
593 |
|
|
ConfigReply_t *pReply = (ConfigReply_t *)reply;
|
594 |
|
|
u16 status;
|
595 |
|
|
|
596 |
|
|
status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
597 |
|
|
dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
|
598 |
|
|
status, le32_to_cpu(pReply->IOCLogInfo)));
|
599 |
|
|
|
600 |
|
|
pCfg->status = status;
|
601 |
|
|
if (status == MPI_IOCSTATUS_SUCCESS) {
|
602 |
|
|
pCfg->hdr->PageVersion = pReply->Header.PageVersion;
|
603 |
|
|
pCfg->hdr->PageLength = pReply->Header.PageLength;
|
604 |
|
|
pCfg->hdr->PageNumber = pReply->Header.PageNumber;
|
605 |
|
|
pCfg->hdr->PageType = pReply->Header.PageType;
|
606 |
|
|
}
|
607 |
|
|
}
|
608 |
|
|
|
609 |
|
|
/*
|
610 |
|
|
* Wake up the original calling thread
|
611 |
|
|
*/
|
612 |
|
|
pCfg->wait_done = 1;
|
613 |
|
|
wake_up(&mpt_waitq);
|
614 |
|
|
}
|
615 |
|
|
} else {
|
616 |
|
|
printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
|
617 |
|
|
ioc->name, func);
|
618 |
|
|
}
|
619 |
|
|
|
620 |
|
|
/*
|
621 |
|
|
* Conditionally tell caller to free the original
|
622 |
|
|
* EventNotification/EventAck/unexpected request frame!
|
623 |
|
|
*/
|
624 |
|
|
return freereq;
|
625 |
|
|
}
|
626 |
|
|
|
627 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
628 |
|
|
/**
|
629 |
|
|
* mpt_register - Register protocol-specific main callback handler.
|
630 |
|
|
* @cbfunc: callback function pointer
|
631 |
|
|
* @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
|
632 |
|
|
*
|
633 |
|
|
* This routine is called by a protocol-specific driver (SCSI host,
|
634 |
|
|
* LAN, SCSI target) to register it's reply callback routine. Each
|
635 |
|
|
* protocol-specific driver must do this before it will be able to
|
636 |
|
|
* use any IOC resources, such as obtaining request frames.
|
637 |
|
|
*
|
638 |
|
|
* NOTES: The SCSI protocol driver currently calls this routine thrice
|
639 |
|
|
* in order to register separate callbacks; one for "normal" SCSI IO;
|
640 |
|
|
* one for MptScsiTaskMgmt requests; one for Scan/DV requests.
|
641 |
|
|
*
|
642 |
|
|
* Returns a positive integer valued "handle" in the
|
643 |
|
|
* range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
|
644 |
|
|
* Any non-positive return value (including zero!) should be considered
|
645 |
|
|
* an error by the caller.
|
646 |
|
|
*/
|
647 |
|
|
int
|
648 |
|
|
mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
|
649 |
|
|
{
|
650 |
|
|
int i;
|
651 |
|
|
|
652 |
|
|
last_drv_idx = -1;
|
653 |
|
|
|
654 |
|
|
#ifndef MODULE
|
655 |
|
|
/*
|
656 |
|
|
* Handle possibility of the mptscsih_detect() routine getting
|
657 |
|
|
* called *before* fusion_init!
|
658 |
|
|
*/
|
659 |
|
|
if (!FusionInitCalled) {
|
660 |
|
|
dprintk((KERN_INFO MYNAM ": Hmmm, calling fusion_init from mpt_register!\n"));
|
661 |
|
|
/*
|
662 |
|
|
* NOTE! We'll get recursion here, as fusion_init()
|
663 |
|
|
* calls mpt_register()!
|
664 |
|
|
*/
|
665 |
|
|
fusion_init();
|
666 |
|
|
FusionInitCalled++;
|
667 |
|
|
}
|
668 |
|
|
#endif
|
669 |
|
|
|
670 |
|
|
/*
|
671 |
|
|
* Search for empty callback slot in this order: {N,...,7,6,5,...,1}
|
672 |
|
|
* (slot/handle 0 is reserved!)
|
673 |
|
|
*/
|
674 |
|
|
for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
|
675 |
|
|
if (MptCallbacks[i] == NULL) {
|
676 |
|
|
MptCallbacks[i] = cbfunc;
|
677 |
|
|
MptDriverClass[i] = dclass;
|
678 |
|
|
MptEvHandlers[i] = NULL;
|
679 |
|
|
last_drv_idx = i;
|
680 |
|
|
if (cbfunc != mpt_base_reply) {
|
681 |
|
|
mpt_inc_use_count();
|
682 |
|
|
}
|
683 |
|
|
break;
|
684 |
|
|
}
|
685 |
|
|
}
|
686 |
|
|
|
687 |
|
|
return last_drv_idx;
|
688 |
|
|
}
|
689 |
|
|
|
690 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
691 |
|
|
/**
|
692 |
|
|
* mpt_deregister - Deregister a protocol drivers resources.
|
693 |
|
|
* @cb_idx: previously registered callback handle
|
694 |
|
|
*
|
695 |
|
|
* Each protocol-specific driver should call this routine when it's
|
696 |
|
|
* module is unloaded.
|
697 |
|
|
*/
|
698 |
|
|
void
|
699 |
|
|
mpt_deregister(int cb_idx)
|
700 |
|
|
{
|
701 |
|
|
if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
|
702 |
|
|
MptCallbacks[cb_idx] = NULL;
|
703 |
|
|
MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
|
704 |
|
|
MptEvHandlers[cb_idx] = NULL;
|
705 |
|
|
|
706 |
|
|
last_drv_idx++;
|
707 |
|
|
if (isense_idx != -1 && isense_idx <= cb_idx)
|
708 |
|
|
isense_idx++;
|
709 |
|
|
|
710 |
|
|
if (cb_idx != mpt_base_index) {
|
711 |
|
|
mpt_dec_use_count();
|
712 |
|
|
}
|
713 |
|
|
}
|
714 |
|
|
}
|
715 |
|
|
|
716 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
717 |
|
|
/**
|
718 |
|
|
* mpt_event_register - Register protocol-specific event callback
|
719 |
|
|
* handler.
|
720 |
|
|
* @cb_idx: previously registered (via mpt_register) callback handle
|
721 |
|
|
* @ev_cbfunc: callback function
|
722 |
|
|
*
|
723 |
|
|
* This routine can be called by one or more protocol-specific drivers
|
724 |
|
|
* if/when they choose to be notified of MPT events.
|
725 |
|
|
*
|
726 |
|
|
* Returns 0 for success.
|
727 |
|
|
*/
|
728 |
|
|
int
|
729 |
|
|
mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
|
730 |
|
|
{
|
731 |
|
|
if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
|
732 |
|
|
return -1;
|
733 |
|
|
|
734 |
|
|
MptEvHandlers[cb_idx] = ev_cbfunc;
|
735 |
|
|
return 0;
|
736 |
|
|
}
|
737 |
|
|
|
738 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
739 |
|
|
/**
|
740 |
|
|
* mpt_event_deregister - Deregister protocol-specific event callback
|
741 |
|
|
* handler.
|
742 |
|
|
* @cb_idx: previously registered callback handle
|
743 |
|
|
*
|
744 |
|
|
* Each protocol-specific driver should call this routine
|
745 |
|
|
* when it does not (or can no longer) handle events,
|
746 |
|
|
* or when it's module is unloaded.
|
747 |
|
|
*/
|
748 |
|
|
void
|
749 |
|
|
mpt_event_deregister(int cb_idx)
|
750 |
|
|
{
|
751 |
|
|
if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
|
752 |
|
|
return;
|
753 |
|
|
|
754 |
|
|
MptEvHandlers[cb_idx] = NULL;
|
755 |
|
|
}
|
756 |
|
|
|
757 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
758 |
|
|
/**
|
759 |
|
|
* mpt_reset_register - Register protocol-specific IOC reset handler.
|
760 |
|
|
* @cb_idx: previously registered (via mpt_register) callback handle
|
761 |
|
|
* @reset_func: reset function
|
762 |
|
|
*
|
763 |
|
|
* This routine can be called by one or more protocol-specific drivers
|
764 |
|
|
* if/when they choose to be notified of IOC resets.
|
765 |
|
|
*
|
766 |
|
|
* Returns 0 for success.
|
767 |
|
|
*/
|
768 |
|
|
int
|
769 |
|
|
mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
|
770 |
|
|
{
|
771 |
|
|
if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
|
772 |
|
|
return -1;
|
773 |
|
|
|
774 |
|
|
MptResetHandlers[cb_idx] = reset_func;
|
775 |
|
|
return 0;
|
776 |
|
|
}
|
777 |
|
|
|
778 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
779 |
|
|
/**
|
780 |
|
|
* mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
|
781 |
|
|
* @cb_idx: previously registered callback handle
|
782 |
|
|
*
|
783 |
|
|
* Each protocol-specific driver should call this routine
|
784 |
|
|
* when it does not (or can no longer) handle IOC reset handling,
|
785 |
|
|
* or when it's module is unloaded.
|
786 |
|
|
*/
|
787 |
|
|
void
|
788 |
|
|
mpt_reset_deregister(int cb_idx)
|
789 |
|
|
{
|
790 |
|
|
if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
|
791 |
|
|
return;
|
792 |
|
|
|
793 |
|
|
MptResetHandlers[cb_idx] = NULL;
|
794 |
|
|
}
|
795 |
|
|
|
796 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
797 |
|
|
/**
|
798 |
|
|
* mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
|
799 |
|
|
* allocated per MPT adapter.
|
800 |
|
|
* @handle: Handle of registered MPT protocol driver
|
801 |
|
|
* @iocid: IOC unique identifier (integer)
|
802 |
|
|
*
|
803 |
|
|
* Returns pointer to a MPT request frame or %NULL if none are available
|
804 |
|
|
* or IOC is not active.
|
805 |
|
|
*/
|
806 |
|
|
MPT_FRAME_HDR*
|
807 |
|
|
mpt_get_msg_frame(int handle, int iocid)
|
808 |
|
|
{
|
809 |
|
|
MPT_FRAME_HDR *mf;
|
810 |
|
|
MPT_ADAPTER *iocp;
|
811 |
|
|
unsigned long flags;
|
812 |
|
|
|
813 |
|
|
/* validate handle and ioc identifier */
|
814 |
|
|
iocp = mpt_adapters[iocid];
|
815 |
|
|
|
816 |
|
|
#ifdef MFCNT
|
817 |
|
|
if (!iocp->active)
|
818 |
|
|
printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
|
819 |
|
|
#endif
|
820 |
|
|
|
821 |
|
|
/* If interrupts are not attached, do not return a request frame */
|
822 |
|
|
if (!iocp->active)
|
823 |
|
|
return NULL;
|
824 |
|
|
|
825 |
|
|
spin_lock_irqsave(&iocp->FreeQlock, flags);
|
826 |
|
|
if (! Q_IS_EMPTY(&iocp->FreeQ)) {
|
827 |
|
|
int req_offset;
|
828 |
|
|
|
829 |
|
|
mf = iocp->FreeQ.head;
|
830 |
|
|
Q_DEL_ITEM(&mf->u.frame.linkage);
|
831 |
|
|
mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
|
832 |
|
|
req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
|
833 |
|
|
/* u16! */
|
834 |
|
|
mf->u.frame.hwhdr.msgctxu.fld.req_idx =
|
835 |
|
|
cpu_to_le16(req_offset / iocp->req_sz);
|
836 |
|
|
mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
|
837 |
|
|
#ifdef MFCNT
|
838 |
|
|
iocp->mfcnt++;
|
839 |
|
|
#endif
|
840 |
|
|
}
|
841 |
|
|
else
|
842 |
|
|
mf = NULL;
|
843 |
|
|
spin_unlock_irqrestore(&iocp->FreeQlock, flags);
|
844 |
|
|
|
845 |
|
|
#ifdef MFCNT
|
846 |
|
|
if (mf == NULL)
|
847 |
|
|
printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", iocp->mfcnt, iocp->req_depth);
|
848 |
|
|
mfcounter++;
|
849 |
|
|
if (mfcounter == PRINT_MF_COUNT)
|
850 |
|
|
printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", iocp->mfcnt, iocp->req_depth);
|
851 |
|
|
#endif
|
852 |
|
|
|
853 |
|
|
dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
|
854 |
|
|
iocp->name, handle, iocid, mf));
|
855 |
|
|
return mf;
|
856 |
|
|
}
|
857 |
|
|
|
858 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
859 |
|
|
/**
|
860 |
|
|
* mpt_put_msg_frame - Send a protocol specific MPT request frame
|
861 |
|
|
* to a IOC.
|
862 |
|
|
* @handle: Handle of registered MPT protocol driver
|
863 |
|
|
* @iocid: IOC unique identifier (integer)
|
864 |
|
|
* @mf: Pointer to MPT request frame
|
865 |
|
|
*
|
866 |
|
|
* This routine posts a MPT request frame to the request post FIFO of a
|
867 |
|
|
* specific MPT adapter.
|
868 |
|
|
*/
|
869 |
|
|
void
|
870 |
|
|
mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
|
871 |
|
|
{
|
872 |
|
|
MPT_ADAPTER *iocp;
|
873 |
|
|
|
874 |
|
|
iocp = mpt_adapters[iocid];
|
875 |
|
|
if (iocp != NULL) {
|
876 |
|
|
u32 mf_dma_addr;
|
877 |
|
|
int req_offset;
|
878 |
|
|
|
879 |
|
|
/* ensure values are reset properly! */
|
880 |
|
|
mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
|
881 |
|
|
req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
|
882 |
|
|
/* u16! */
|
883 |
|
|
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz);
|
884 |
|
|
mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
|
885 |
|
|
|
886 |
|
|
#ifdef MPT_DEBUG_MSG_FRAME
|
887 |
|
|
{
|
888 |
|
|
u32 *m = mf->u.frame.hwhdr.__hdr;
|
889 |
|
|
int ii, n;
|
890 |
|
|
|
891 |
|
|
printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
|
892 |
|
|
iocp->name, m);
|
893 |
|
|
n = iocp->req_sz/4 - 1;
|
894 |
|
|
while (m[n] == 0)
|
895 |
|
|
n--;
|
896 |
|
|
for (ii=0; ii<=n; ii++) {
|
897 |
|
|
if (ii && ((ii%8)==0))
|
898 |
|
|
printk("\n" KERN_INFO " ");
|
899 |
|
|
printk(" %08x", le32_to_cpu(m[ii]));
|
900 |
|
|
}
|
901 |
|
|
printk("\n");
|
902 |
|
|
}
|
903 |
|
|
#endif
|
904 |
|
|
|
905 |
|
|
mf_dma_addr = iocp->req_frames_low_dma + req_offset;
|
906 |
|
|
CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr);
|
907 |
|
|
}
|
908 |
|
|
}
|
909 |
|
|
|
910 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
911 |
|
|
/**
|
912 |
|
|
* mpt_free_msg_frame - Place MPT request frame back on FreeQ.
|
913 |
|
|
* @handle: Handle of registered MPT protocol driver
|
914 |
|
|
* @iocid: IOC unique identifier (integer)
|
915 |
|
|
* @mf: Pointer to MPT request frame
|
916 |
|
|
*
|
917 |
|
|
* This routine places a MPT request frame back on the MPT adapter's
|
918 |
|
|
* FreeQ.
|
919 |
|
|
*/
|
920 |
|
|
void
|
921 |
|
|
mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
|
922 |
|
|
{
|
923 |
|
|
MPT_ADAPTER *iocp;
|
924 |
|
|
unsigned long flags;
|
925 |
|
|
|
926 |
|
|
iocp = mpt_adapters[iocid];
|
927 |
|
|
if (iocp != NULL) {
|
928 |
|
|
/* Put Request back on FreeQ! */
|
929 |
|
|
spin_lock_irqsave(&iocp->FreeQlock, flags);
|
930 |
|
|
Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
|
931 |
|
|
#ifdef MFCNT
|
932 |
|
|
iocp->mfcnt--;
|
933 |
|
|
#endif
|
934 |
|
|
spin_unlock_irqrestore(&iocp->FreeQlock, flags);
|
935 |
|
|
}
|
936 |
|
|
}
|
937 |
|
|
|
938 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
939 |
|
|
/**
|
940 |
|
|
* mpt_add_sge - Place a simple SGE at address pAddr.
|
941 |
|
|
* @pAddr: virtual address for SGE
|
942 |
|
|
* @flagslength: SGE flags and data transfer length
|
943 |
|
|
* @dma_addr: Physical address
|
944 |
|
|
*
|
945 |
|
|
* This routine places a MPT request frame back on the MPT adapter's
|
946 |
|
|
* FreeQ.
|
947 |
|
|
*/
|
948 |
|
|
void
|
949 |
|
|
mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
|
950 |
|
|
{
|
951 |
|
|
if (sizeof(dma_addr_t) == sizeof(u64)) {
|
952 |
|
|
SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
|
953 |
|
|
u32 tmp = dma_addr & 0xFFFFFFFF;
|
954 |
|
|
|
955 |
|
|
pSge->FlagsLength = cpu_to_le32(flagslength);
|
956 |
|
|
pSge->Address.Low = cpu_to_le32(tmp);
|
957 |
|
|
tmp = (u32) ((u64)dma_addr >> 32);
|
958 |
|
|
pSge->Address.High = cpu_to_le32(tmp);
|
959 |
|
|
|
960 |
|
|
} else {
|
961 |
|
|
SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
|
962 |
|
|
pSge->FlagsLength = cpu_to_le32(flagslength);
|
963 |
|
|
pSge->Address = cpu_to_le32(dma_addr);
|
964 |
|
|
}
|
965 |
|
|
}
|
966 |
|
|
|
967 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
968 |
|
|
/**
|
969 |
|
|
* mpt_add_chain - Place a chain SGE at address pAddr.
|
970 |
|
|
* @pAddr: virtual address for SGE
|
971 |
|
|
* @next: nextChainOffset value (u32's)
|
972 |
|
|
* @length: length of next SGL segment
|
973 |
|
|
* @dma_addr: Physical address
|
974 |
|
|
*
|
975 |
|
|
* This routine places a MPT request frame back on the MPT adapter's
|
976 |
|
|
* FreeQ.
|
977 |
|
|
*/
|
978 |
|
|
void
|
979 |
|
|
mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
|
980 |
|
|
{
|
981 |
|
|
if (sizeof(dma_addr_t) == sizeof(u64)) {
|
982 |
|
|
SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
|
983 |
|
|
u32 tmp = dma_addr & 0xFFFFFFFF;
|
984 |
|
|
|
985 |
|
|
pChain->Length = cpu_to_le16(length);
|
986 |
|
|
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
|
987 |
|
|
|
988 |
|
|
pChain->NextChainOffset = next;
|
989 |
|
|
|
990 |
|
|
pChain->Address.Low = cpu_to_le32(tmp);
|
991 |
|
|
tmp = (u32) ((u64)dma_addr >> 32);
|
992 |
|
|
pChain->Address.High = cpu_to_le32(tmp);
|
993 |
|
|
} else {
|
994 |
|
|
SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
|
995 |
|
|
pChain->Length = cpu_to_le16(length);
|
996 |
|
|
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
|
997 |
|
|
pChain->NextChainOffset = next;
|
998 |
|
|
pChain->Address = cpu_to_le32(dma_addr);
|
999 |
|
|
}
|
1000 |
|
|
}
|
1001 |
|
|
|
1002 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1003 |
|
|
/**
|
1004 |
|
|
* mpt_send_handshake_request - Send MPT request via doorbell
|
1005 |
|
|
* handshake method.
|
1006 |
|
|
* @handle: Handle of registered MPT protocol driver
|
1007 |
|
|
* @iocid: IOC unique identifier (integer)
|
1008 |
|
|
* @reqBytes: Size of the request in bytes
|
1009 |
|
|
* @req: Pointer to MPT request frame
|
1010 |
|
|
* @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
|
1011 |
|
|
*
|
1012 |
|
|
* This routine is used exclusively to send MptScsiTaskMgmt
|
1013 |
|
|
* requests since they are required to be sent via doorbell handshake.
|
1014 |
|
|
*
|
1015 |
|
|
* NOTE: It is the callers responsibility to byte-swap fields in the
|
1016 |
|
|
* request which are greater than 1 byte in size.
|
1017 |
|
|
*
|
1018 |
|
|
* Returns 0 for success, non-zero for failure.
|
1019 |
|
|
*/
|
1020 |
|
|
int
|
1021 |
|
|
mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag)
|
1022 |
|
|
{
|
1023 |
|
|
MPT_ADAPTER *iocp;
|
1024 |
|
|
int r = 0;
|
1025 |
|
|
|
1026 |
|
|
iocp = mpt_adapters[iocid];
|
1027 |
|
|
if (iocp != NULL) {
|
1028 |
|
|
u8 *req_as_bytes;
|
1029 |
|
|
int ii;
|
1030 |
|
|
|
1031 |
|
|
/* State is known to be good upon entering
|
1032 |
|
|
* this function so issue the bus reset
|
1033 |
|
|
* request.
|
1034 |
|
|
*/
|
1035 |
|
|
|
1036 |
|
|
/*
|
1037 |
|
|
* Emulate what mpt_put_msg_frame() does /wrt to sanity
|
1038 |
|
|
* setting cb_idx/req_idx. But ONLY if this request
|
1039 |
|
|
* is in proper (pre-alloc'd) request buffer range...
|
1040 |
|
|
*/
|
1041 |
|
|
ii = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
|
1042 |
|
|
if (reqBytes >= 12 && ii >= 0 && ii < iocp->req_depth) {
|
1043 |
|
|
MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
|
1044 |
|
|
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
|
1045 |
|
|
mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
|
1046 |
|
|
}
|
1047 |
|
|
|
1048 |
|
|
/* Make sure there are no doorbells */
|
1049 |
|
|
CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
|
1050 |
|
|
|
1051 |
|
|
CHIPREG_WRITE32(&iocp->chip->Doorbell,
|
1052 |
|
|
((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
|
1053 |
|
|
((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
|
1054 |
|
|
|
1055 |
|
|
/* Wait for IOC doorbell int */
|
1056 |
|
|
if ((ii = WaitForDoorbellInt(iocp, 2, sleepFlag)) < 0) {
|
1057 |
|
|
return ii;
|
1058 |
|
|
}
|
1059 |
|
|
|
1060 |
|
|
/* Read doorbell and check for active bit */
|
1061 |
|
|
if (!(CHIPREG_READ32(&iocp->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
|
1062 |
|
|
return -5;
|
1063 |
|
|
|
1064 |
|
|
dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
|
1065 |
|
|
iocp->name, ii));
|
1066 |
|
|
|
1067 |
|
|
CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
|
1068 |
|
|
|
1069 |
|
|
if ((r = WaitForDoorbellAck(iocp, 2, sleepFlag)) < 0) {
|
1070 |
|
|
return -2;
|
1071 |
|
|
}
|
1072 |
|
|
|
1073 |
|
|
/* Send request via doorbell handshake */
|
1074 |
|
|
req_as_bytes = (u8 *) req;
|
1075 |
|
|
for (ii = 0; ii < reqBytes/4; ii++) {
|
1076 |
|
|
u32 word;
|
1077 |
|
|
|
1078 |
|
|
word = ((req_as_bytes[(ii*4) + 0] << 0) |
|
1079 |
|
|
(req_as_bytes[(ii*4) + 1] << 8) |
|
1080 |
|
|
(req_as_bytes[(ii*4) + 2] << 16) |
|
1081 |
|
|
(req_as_bytes[(ii*4) + 3] << 24));
|
1082 |
|
|
CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
|
1083 |
|
|
if ((r = WaitForDoorbellAck(iocp, 2, sleepFlag)) < 0) {
|
1084 |
|
|
r = -3;
|
1085 |
|
|
break;
|
1086 |
|
|
}
|
1087 |
|
|
}
|
1088 |
|
|
|
1089 |
|
|
if (r >= 0 && WaitForDoorbellInt(iocp, 10, sleepFlag) >= 0)
|
1090 |
|
|
r = 0;
|
1091 |
|
|
else
|
1092 |
|
|
r = -4;
|
1093 |
|
|
|
1094 |
|
|
/* Make sure there are no doorbells */
|
1095 |
|
|
CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
|
1096 |
|
|
}
|
1097 |
|
|
|
1098 |
|
|
return r;
|
1099 |
|
|
}
|
1100 |
|
|
|
1101 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1102 |
|
|
/**
|
1103 |
|
|
* mpt_adapter_find_first - Find first MPT adapter pointer.
|
1104 |
|
|
*
|
1105 |
|
|
* Returns first MPT adapter pointer or %NULL if no MPT adapters
|
1106 |
|
|
* are present.
|
1107 |
|
|
*/
|
1108 |
|
|
MPT_ADAPTER *
|
1109 |
|
|
mpt_adapter_find_first(void)
|
1110 |
|
|
{
|
1111 |
|
|
MPT_ADAPTER *this;
|
1112 |
|
|
|
1113 |
|
|
if (! Q_IS_EMPTY(&MptAdapters))
|
1114 |
|
|
this = MptAdapters.head;
|
1115 |
|
|
else
|
1116 |
|
|
this = NULL;
|
1117 |
|
|
|
1118 |
|
|
return this;
|
1119 |
|
|
}
|
1120 |
|
|
|
1121 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1122 |
|
|
/**
|
1123 |
|
|
* mpt_adapter_find_next - Find next MPT adapter pointer.
|
1124 |
|
|
* @prev: Pointer to previous MPT adapter
|
1125 |
|
|
*
|
1126 |
|
|
* Returns next MPT adapter pointer or %NULL if there are no more.
|
1127 |
|
|
*/
|
1128 |
|
|
MPT_ADAPTER *
|
1129 |
|
|
mpt_adapter_find_next(MPT_ADAPTER *prev)
|
1130 |
|
|
{
|
1131 |
|
|
MPT_ADAPTER *next;
|
1132 |
|
|
|
1133 |
|
|
if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head))
|
1134 |
|
|
next = prev->forw;
|
1135 |
|
|
else
|
1136 |
|
|
next = NULL;
|
1137 |
|
|
|
1138 |
|
|
return next;
|
1139 |
|
|
}
|
1140 |
|
|
|
1141 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1142 |
|
|
/*
|
1143 |
|
|
* mpt_pci_scan - Scan PCI devices for MPT adapters.
|
1144 |
|
|
*
|
1145 |
|
|
* Returns count of MPT adapters found, keying off of PCI vendor and
|
1146 |
|
|
* device_id's.
|
1147 |
|
|
*/
|
1148 |
|
|
static int __init
|
1149 |
|
|
mpt_pci_scan(void)
|
1150 |
|
|
{
|
1151 |
|
|
struct pci_dev *pdev;
|
1152 |
|
|
struct pci_dev *pdev2;
|
1153 |
|
|
int found = 0;
|
1154 |
|
|
int count = 0;
|
1155 |
|
|
int r;
|
1156 |
|
|
|
1157 |
|
|
dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n"));
|
1158 |
|
|
|
1159 |
|
|
/*
|
1160 |
|
|
* NOTE: The 929, 929X, 1030 and 1035 will appear as 2 separate PCI devices,
|
1161 |
|
|
* one for each channel.
|
1162 |
|
|
*/
|
1163 |
|
|
pci_for_each_dev(pdev) {
|
1164 |
|
|
pdev2 = NULL;
|
1165 |
|
|
if (pdev->vendor != 0x1000)
|
1166 |
|
|
continue;
|
1167 |
|
|
|
1168 |
|
|
if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
|
1169 |
|
|
(pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
|
1170 |
|
|
(pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
|
1171 |
|
|
(pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929X) &&
|
1172 |
|
|
(pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919X) &&
|
1173 |
|
|
(pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
|
1174 |
|
|
(pdev->device != MPI_MANUFACTPAGE_DEVID_1030_53C1035) &&
|
1175 |
|
|
1) {
|
1176 |
|
|
dprintk((KERN_INFO MYNAM ": Skipping LSI device=%04xh\n", pdev->device));
|
1177 |
|
|
continue;
|
1178 |
|
|
}
|
1179 |
|
|
|
1180 |
|
|
/* GRRRRR
|
1181 |
|
|
* dual function devices (929, 929X, 1030, 1035) may be presented in Func 1,0 order,
|
1182 |
|
|
* but we'd really really rather have them in Func 0,1 order.
|
1183 |
|
|
* Do some kind of look ahead here...
|
1184 |
|
|
*/
|
1185 |
|
|
if (pdev->devfn & 1) {
|
1186 |
|
|
pdev2 = pci_peek_next_dev(pdev);
|
1187 |
|
|
if (pdev2 && (pdev2->vendor == 0x1000) &&
|
1188 |
|
|
(PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) &&
|
1189 |
|
|
(pdev2->device == pdev->device) &&
|
1190 |
|
|
(pdev2->bus->number == pdev->bus->number) &&
|
1191 |
|
|
!(pdev2->devfn & 1)) {
|
1192 |
|
|
dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
|
1193 |
|
|
pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
|
1194 |
|
|
found++;
|
1195 |
|
|
if ((r = mpt_adapter_install(pdev2)) == 0)
|
1196 |
|
|
count++;
|
1197 |
|
|
} else {
|
1198 |
|
|
pdev2 = NULL;
|
1199 |
|
|
}
|
1200 |
|
|
}
|
1201 |
|
|
|
1202 |
|
|
dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
|
1203 |
|
|
pdev->bus->number, pdev->devfn, pdev->class, pdev->device));
|
1204 |
|
|
found++;
|
1205 |
|
|
if ((r = mpt_adapter_install(pdev)) == 0)
|
1206 |
|
|
count++;
|
1207 |
|
|
|
1208 |
|
|
if (pdev2)
|
1209 |
|
|
pdev = pdev2;
|
1210 |
|
|
}
|
1211 |
|
|
|
1212 |
|
|
printk(KERN_INFO MYNAM ": %d MPT adapter%s found, %d installed.\n",
|
1213 |
|
|
found, (found==1) ? "" : "s", count);
|
1214 |
|
|
|
1215 |
|
|
if (!found || !count) {
|
1216 |
|
|
fusion_exit();
|
1217 |
|
|
return -ENODEV;
|
1218 |
|
|
}
|
1219 |
|
|
|
1220 |
|
|
#ifdef CONFIG_PROC_FS
|
1221 |
|
|
(void) procmpt_create();
|
1222 |
|
|
#endif
|
1223 |
|
|
|
1224 |
|
|
return count;
|
1225 |
|
|
}
|
1226 |
|
|
|
1227 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1228 |
|
|
/**
|
1229 |
|
|
* mpt_verify_adapter - Given a unique IOC identifier, set pointer to
|
1230 |
|
|
* the associated MPT adapter structure.
|
1231 |
|
|
* @iocid: IOC unique identifier (integer)
|
1232 |
|
|
* @iocpp: Pointer to pointer to IOC adapter
|
1233 |
|
|
*
|
1234 |
|
|
* Returns iocid and sets iocpp.
|
1235 |
|
|
*/
|
1236 |
|
|
int
|
1237 |
|
|
mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
|
1238 |
|
|
{
|
1239 |
|
|
MPT_ADAPTER *p;
|
1240 |
|
|
|
1241 |
|
|
*iocpp = NULL;
|
1242 |
|
|
if (iocid >= MPT_MAX_ADAPTERS)
|
1243 |
|
|
return -1;
|
1244 |
|
|
|
1245 |
|
|
p = mpt_adapters[iocid];
|
1246 |
|
|
if (p == NULL)
|
1247 |
|
|
return -1;
|
1248 |
|
|
|
1249 |
|
|
*iocpp = p;
|
1250 |
|
|
return iocid;
|
1251 |
|
|
}
|
1252 |
|
|
|
1253 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1254 |
|
|
/*
|
1255 |
|
|
* mpt_adapter_install - Install a PCI intelligent MPT adapter.
|
1256 |
|
|
* @pdev: Pointer to pci_dev structure
|
1257 |
|
|
*
|
1258 |
|
|
* This routine performs all the steps necessary to bring the IOC of
|
1259 |
|
|
* a MPT adapter to a OPERATIONAL state. This includes registering
|
1260 |
|
|
* memory regions, registering the interrupt, and allocating request
|
1261 |
|
|
* and reply memory pools.
|
1262 |
|
|
*
|
1263 |
|
|
* This routine also pre-fetches the LAN MAC address of a Fibre Channel
|
1264 |
|
|
* MPT adapter.
|
1265 |
|
|
*
|
1266 |
|
|
* Returns 0 for success, non-zero for failure.
|
1267 |
|
|
*
|
1268 |
|
|
* TODO: Add support for polled controllers
|
1269 |
|
|
*/
|
1270 |
|
|
static int __init
|
1271 |
|
|
mpt_adapter_install(struct pci_dev *pdev)
|
1272 |
|
|
{
|
1273 |
|
|
MPT_ADAPTER *ioc;
|
1274 |
|
|
u8 *mem;
|
1275 |
|
|
unsigned long mem_phys;
|
1276 |
|
|
unsigned long port;
|
1277 |
|
|
u32 msize;
|
1278 |
|
|
u32 psize;
|
1279 |
|
|
int ii;
|
1280 |
|
|
int r = -ENODEV;
|
1281 |
|
|
u64 mask = 0xffffffffffffffffULL;
|
1282 |
|
|
|
1283 |
|
|
if (pci_enable_device(pdev))
|
1284 |
|
|
return r;
|
1285 |
|
|
|
1286 |
|
|
/* For some kernels, broken kernel limits memory allocation for target mode
|
1287 |
|
|
* driver. Shirron. Fixed in 2.4.20-8
|
1288 |
|
|
* if ((sizeof(dma_addr_t) == sizeof(u64)) && (!pci_set_dma_mask(pdev, mask))) {
|
1289 |
|
|
*/
|
1290 |
|
|
if ((!pci_set_dma_mask(pdev, mask))) {
|
1291 |
|
|
dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
|
1292 |
|
|
} else {
|
1293 |
|
|
if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
|
1294 |
|
|
printk(KERN_WARNING MYNAM
|
1295 |
|
|
": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
|
1296 |
|
|
return r;
|
1297 |
|
|
}
|
1298 |
|
|
}
|
1299 |
|
|
|
1300 |
|
|
ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
|
1301 |
|
|
if (ioc == NULL) {
|
1302 |
|
|
printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
|
1303 |
|
|
return -ENOMEM;
|
1304 |
|
|
}
|
1305 |
|
|
memset(ioc, 0, sizeof(MPT_ADAPTER));
|
1306 |
|
|
ioc->alloc_total = sizeof(MPT_ADAPTER);
|
1307 |
|
|
ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
|
1308 |
|
|
ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
|
1309 |
|
|
|
1310 |
|
|
ioc->pcidev = pdev;
|
1311 |
|
|
ioc->diagPending = 0;
|
1312 |
|
|
spin_lock_init(&ioc->diagLock);
|
1313 |
|
|
|
1314 |
|
|
/* Initialize the event logging.
|
1315 |
|
|
*/
|
1316 |
|
|
ioc->eventTypes = 0; /* None */
|
1317 |
|
|
ioc->eventContext = 0;
|
1318 |
|
|
ioc->eventLogSize = 0;
|
1319 |
|
|
ioc->events = NULL;
|
1320 |
|
|
|
1321 |
|
|
#ifdef MFCNT
|
1322 |
|
|
ioc->mfcnt = 0;
|
1323 |
|
|
#endif
|
1324 |
|
|
|
1325 |
|
|
ioc->cached_fw = NULL;
|
1326 |
|
|
|
1327 |
|
|
/* Initilize SCSI Config Data structure
|
1328 |
|
|
*/
|
1329 |
|
|
memset(&ioc->spi_data, 0, sizeof(ScsiCfgData));
|
1330 |
|
|
|
1331 |
|
|
/* Initialize the running configQ head.
|
1332 |
|
|
*/
|
1333 |
|
|
Q_INIT(&ioc->configQ, Q_ITEM);
|
1334 |
|
|
|
1335 |
|
|
/* Find lookup slot. */
|
1336 |
|
|
for (ii=0; ii < MPT_MAX_ADAPTERS; ii++) {
|
1337 |
|
|
if (mpt_adapters[ii] == NULL) {
|
1338 |
|
|
ioc->id = ii; /* Assign adapter unique id (lookup) */
|
1339 |
|
|
break;
|
1340 |
|
|
}
|
1341 |
|
|
}
|
1342 |
|
|
if (ii == MPT_MAX_ADAPTERS) {
|
1343 |
|
|
printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", ii);
|
1344 |
|
|
kfree(ioc);
|
1345 |
|
|
return -ENFILE;
|
1346 |
|
|
}
|
1347 |
|
|
|
1348 |
|
|
mem_phys = msize = 0;
|
1349 |
|
|
port = psize = 0;
|
1350 |
|
|
for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
|
1351 |
|
|
if (pdev->PCI_BASEADDR_FLAGS(ii) & PCI_BASE_ADDRESS_SPACE_IO) {
|
1352 |
|
|
/* Get I/O space! */
|
1353 |
|
|
port = pdev->PCI_BASEADDR_START(ii);
|
1354 |
|
|
psize = PCI_BASEADDR_SIZE(pdev,ii);
|
1355 |
|
|
} else {
|
1356 |
|
|
/* Get memmap */
|
1357 |
|
|
mem_phys = pdev->PCI_BASEADDR_START(ii);
|
1358 |
|
|
msize = PCI_BASEADDR_SIZE(pdev,ii);
|
1359 |
|
|
break;
|
1360 |
|
|
}
|
1361 |
|
|
}
|
1362 |
|
|
ioc->mem_size = msize;
|
1363 |
|
|
|
1364 |
|
|
if (ii == DEVICE_COUNT_RESOURCE) {
|
1365 |
|
|
printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
|
1366 |
|
|
kfree(ioc);
|
1367 |
|
|
return -EINVAL;
|
1368 |
|
|
}
|
1369 |
|
|
|
1370 |
|
|
dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
|
1371 |
|
|
dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
|
1372 |
|
|
dprintk((KERN_INFO MYNAM ": Using %s register access method\n", PortIo ? "PortIo" : "MemMap"));
|
1373 |
|
|
|
1374 |
|
|
mem = NULL;
|
1375 |
|
|
if (! PortIo) {
|
1376 |
|
|
/* Get logical ptr for PciMem0 space */
|
1377 |
|
|
/*mem = ioremap(mem_phys, msize);*/
|
1378 |
|
|
mem = ioremap(mem_phys, 0x100);
|
1379 |
|
|
if (mem == NULL) {
|
1380 |
|
|
printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
|
1381 |
|
|
kfree(ioc);
|
1382 |
|
|
return -EINVAL;
|
1383 |
|
|
}
|
1384 |
|
|
ioc->memmap = mem;
|
1385 |
|
|
}
|
1386 |
|
|
dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
|
1387 |
|
|
|
1388 |
|
|
dprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
|
1389 |
|
|
&ioc->facts, &ioc->pfacts[0]));
|
1390 |
|
|
if (PortIo) {
|
1391 |
|
|
u8 *pmem = (u8*)port;
|
1392 |
|
|
ioc->mem_phys = port;
|
1393 |
|
|
ioc->chip = (SYSIF_REGS*)pmem;
|
1394 |
|
|
} else {
|
1395 |
|
|
ioc->mem_phys = mem_phys;
|
1396 |
|
|
ioc->chip = (SYSIF_REGS*)mem;
|
1397 |
|
|
}
|
1398 |
|
|
|
1399 |
|
|
/* Save Port IO values incase we need to do downloadboot */
|
1400 |
|
|
{
|
1401 |
|
|
u8 *pmem = (u8*)port;
|
1402 |
|
|
ioc->pio_mem_phys = port;
|
1403 |
|
|
ioc->pio_chip = (SYSIF_REGS*)pmem;
|
1404 |
|
|
}
|
1405 |
|
|
|
1406 |
|
|
ioc->chip_type = FCUNK;
|
1407 |
|
|
if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
|
1408 |
|
|
ioc->chip_type = FC909;
|
1409 |
|
|
ioc->prod_name = "LSIFC909";
|
1410 |
|
|
}
|
1411 |
|
|
else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
|
1412 |
|
|
ioc->chip_type = FC929;
|
1413 |
|
|
ioc->prod_name = "LSIFC929";
|
1414 |
|
|
}
|
1415 |
|
|
else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
|
1416 |
|
|
ioc->chip_type = FC919;
|
1417 |
|
|
ioc->prod_name = "LSIFC919";
|
1418 |
|
|
}
|
1419 |
|
|
else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
|
1420 |
|
|
ioc->chip_type = FC929X;
|
1421 |
|
|
ioc->prod_name = "LSIFC929X";
|
1422 |
|
|
{
|
1423 |
|
|
/* 929X Chip Fix. Set Split transactions level
|
1424 |
|
|
* for PCIX. Set MOST bits to zero.
|
1425 |
|
|
*/
|
1426 |
|
|
u8 pcixcmd;
|
1427 |
|
|
pci_read_config_byte(pdev, 0x6a, &pcixcmd);
|
1428 |
|
|
pcixcmd &= 0x8F;
|
1429 |
|
|
pci_write_config_byte(pdev, 0x6a, pcixcmd);
|
1430 |
|
|
}
|
1431 |
|
|
}
|
1432 |
|
|
else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
|
1433 |
|
|
ioc->chip_type = FC919X;
|
1434 |
|
|
ioc->prod_name = "LSIFC919X";
|
1435 |
|
|
{
|
1436 |
|
|
/* 919X Chip Fix. Set Split transactions level
|
1437 |
|
|
* for PCIX. Set MOST bits to zero.
|
1438 |
|
|
*/
|
1439 |
|
|
u8 pcixcmd;
|
1440 |
|
|
pci_read_config_byte(pdev, 0x6a, &pcixcmd);
|
1441 |
|
|
pcixcmd &= 0x8F;
|
1442 |
|
|
pci_write_config_byte(pdev, 0x6a, pcixcmd);
|
1443 |
|
|
}
|
1444 |
|
|
}
|
1445 |
|
|
else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
|
1446 |
|
|
ioc->chip_type = C1030;
|
1447 |
|
|
ioc->prod_name = "LSI53C1030";
|
1448 |
|
|
{
|
1449 |
|
|
u8 revision;
|
1450 |
|
|
|
1451 |
|
|
/* 1030 Chip Fix. Disable Split transactions
|
1452 |
|
|
* for PCIX. Set MOST bits to zero if Rev < C0( = 8).
|
1453 |
|
|
*/
|
1454 |
|
|
pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
|
1455 |
|
|
if (revision < 0x08) {
|
1456 |
|
|
u8 pcixcmd;
|
1457 |
|
|
pci_read_config_byte(pdev, 0x6a, &pcixcmd);
|
1458 |
|
|
pcixcmd &= 0x8F;
|
1459 |
|
|
pci_write_config_byte(pdev, 0x6a, pcixcmd);
|
1460 |
|
|
}
|
1461 |
|
|
}
|
1462 |
|
|
}
|
1463 |
|
|
else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
|
1464 |
|
|
ioc->chip_type = C1035;
|
1465 |
|
|
ioc->prod_name = "LSI53C1035";
|
1466 |
|
|
}
|
1467 |
|
|
|
1468 |
|
|
sprintf(ioc->name, "ioc%d", ioc->id);
|
1469 |
|
|
|
1470 |
|
|
Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
|
1471 |
|
|
spin_lock_init(&ioc->FreeQlock);
|
1472 |
|
|
|
1473 |
|
|
/* Disable all! */
|
1474 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
|
1475 |
|
|
ioc->active = 0;
|
1476 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
|
1477 |
|
|
|
1478 |
|
|
/* tack onto tail of our MPT adapter list */
|
1479 |
|
|
Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
|
1480 |
|
|
|
1481 |
|
|
/* Set lookup ptr. */
|
1482 |
|
|
mpt_adapters[ioc->id] = ioc;
|
1483 |
|
|
|
1484 |
|
|
ioc->pci_irq = -1;
|
1485 |
|
|
if (pdev->irq) {
|
1486 |
|
|
r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
|
1487 |
|
|
|
1488 |
|
|
if (r < 0) {
|
1489 |
|
|
#ifndef __sparc__
|
1490 |
|
|
printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
|
1491 |
|
|
ioc->name, pdev->irq);
|
1492 |
|
|
#else
|
1493 |
|
|
printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
|
1494 |
|
|
ioc->name, __irq_itoa(pdev->irq));
|
1495 |
|
|
#endif
|
1496 |
|
|
Q_DEL_ITEM(ioc);
|
1497 |
|
|
mpt_adapters[ioc->id] = NULL;
|
1498 |
|
|
iounmap(mem);
|
1499 |
|
|
kfree(ioc);
|
1500 |
|
|
return -EBUSY;
|
1501 |
|
|
}
|
1502 |
|
|
|
1503 |
|
|
ioc->pci_irq = pdev->irq;
|
1504 |
|
|
|
1505 |
|
|
pci_set_master(pdev); /* ?? */
|
1506 |
|
|
|
1507 |
|
|
#ifndef __sparc__
|
1508 |
|
|
dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
|
1509 |
|
|
#else
|
1510 |
|
|
dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
|
1511 |
|
|
#endif
|
1512 |
|
|
}
|
1513 |
|
|
|
1514 |
|
|
/* NEW! 20010220 -sralston
|
1515 |
|
|
* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
|
1516 |
|
|
*/
|
1517 |
|
|
if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030)
|
1518 |
|
|
|| (ioc->chip_type == C1035) || (ioc->chip_type == FC929X))
|
1519 |
|
|
mpt_detect_bound_ports(ioc, pdev);
|
1520 |
|
|
|
1521 |
|
|
if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
|
1522 |
|
|
printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n",
|
1523 |
|
|
ioc->name, r);
|
1524 |
|
|
}
|
1525 |
|
|
|
1526 |
|
|
return r;
|
1527 |
|
|
}
|
1528 |
|
|
|
1529 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1530 |
|
|
/*
|
1531 |
|
|
* mpt_do_ioc_recovery - Initialize or recover MPT adapter.
|
1532 |
|
|
* @ioc: Pointer to MPT adapter structure
|
1533 |
|
|
* @reason: Event word / reason
|
1534 |
|
|
* @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
|
1535 |
|
|
*
|
1536 |
|
|
* This routine performs all the steps necessary to bring the IOC
|
1537 |
|
|
* to a OPERATIONAL state.
|
1538 |
|
|
*
|
1539 |
|
|
* This routine also pre-fetches the LAN MAC address of a Fibre Channel
|
1540 |
|
|
* MPT adapter.
|
1541 |
|
|
*
|
1542 |
|
|
* Returns:
|
1543 |
|
|
* 0 for success
|
1544 |
|
|
* -1 if failed to get board READY
|
1545 |
|
|
* -2 if READY but IOCFacts Failed
|
1546 |
|
|
* -3 if READY but PrimeIOCFifos Failed
|
1547 |
|
|
* -4 if READY but IOCInit Failed
|
1548 |
|
|
*/
|
1549 |
|
|
static int
|
1550 |
|
|
mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
|
1551 |
|
|
{
|
1552 |
|
|
int hard_reset_done = 0;
|
1553 |
|
|
int alt_ioc_ready = 0;
|
1554 |
|
|
int hard;
|
1555 |
|
|
int r;
|
1556 |
|
|
int ii;
|
1557 |
|
|
int handlers;
|
1558 |
|
|
int ret = 0;
|
1559 |
|
|
int reset_alt_ioc_active = 0;
|
1560 |
|
|
|
1561 |
|
|
printk(KERN_INFO MYNAM ": Initiating %s %s\n",
|
1562 |
|
|
ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
|
1563 |
|
|
|
1564 |
|
|
/* Disable reply interrupts (also blocks FreeQ) */
|
1565 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
|
1566 |
|
|
ioc->active = 0;
|
1567 |
|
|
|
1568 |
|
|
if (ioc->alt_ioc) {
|
1569 |
|
|
if (ioc->alt_ioc->active)
|
1570 |
|
|
reset_alt_ioc_active = 1;
|
1571 |
|
|
|
1572 |
|
|
/* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
|
1573 |
|
|
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
|
1574 |
|
|
ioc->alt_ioc->active = 0;
|
1575 |
|
|
}
|
1576 |
|
|
|
1577 |
|
|
hard = 1;
|
1578 |
|
|
if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
|
1579 |
|
|
hard = 0;
|
1580 |
|
|
|
1581 |
|
|
if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
|
1582 |
|
|
if (hard_reset_done == -4) {
|
1583 |
|
|
printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
|
1584 |
|
|
ioc->name);
|
1585 |
|
|
|
1586 |
|
|
if (reset_alt_ioc_active && ioc->alt_ioc) {
|
1587 |
|
|
/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
|
1588 |
|
|
dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
|
1589 |
|
|
ioc->alt_ioc->name));
|
1590 |
|
|
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
|
1591 |
|
|
ioc->alt_ioc->active = 1;
|
1592 |
|
|
}
|
1593 |
|
|
|
1594 |
|
|
} else {
|
1595 |
|
|
printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
|
1596 |
|
|
ioc->name);
|
1597 |
|
|
}
|
1598 |
|
|
return -1;
|
1599 |
|
|
}
|
1600 |
|
|
|
1601 |
|
|
/* hard_reset_done = 0 if a soft reset was performed
|
1602 |
|
|
* and 1 if a hard reset was performed.
|
1603 |
|
|
*/
|
1604 |
|
|
if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
|
1605 |
|
|
if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
|
1606 |
|
|
alt_ioc_ready = 1;
|
1607 |
|
|
else
|
1608 |
|
|
printk(KERN_WARNING MYNAM
|
1609 |
|
|
": alt-%s: (%d) Not ready WARNING!\n",
|
1610 |
|
|
ioc->alt_ioc->name, r);
|
1611 |
|
|
}
|
1612 |
|
|
|
1613 |
|
|
/* Get IOC facts! Allow 1 retry */
|
1614 |
|
|
if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0)
|
1615 |
|
|
r = GetIocFacts(ioc, sleepFlag, reason);
|
1616 |
|
|
|
1617 |
|
|
if (r) {
|
1618 |
|
|
ret = -2;
|
1619 |
|
|
} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
|
1620 |
|
|
MptDisplayIocCapabilities(ioc);
|
1621 |
|
|
}
|
1622 |
|
|
|
1623 |
|
|
if (alt_ioc_ready) {
|
1624 |
|
|
if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
|
1625 |
|
|
/* Retry - alt IOC was initialized once
|
1626 |
|
|
*/
|
1627 |
|
|
r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
|
1628 |
|
|
}
|
1629 |
|
|
if (r) {
|
1630 |
|
|
alt_ioc_ready = 0;
|
1631 |
|
|
reset_alt_ioc_active = 0;
|
1632 |
|
|
} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
|
1633 |
|
|
MptDisplayIocCapabilities(ioc->alt_ioc);
|
1634 |
|
|
}
|
1635 |
|
|
}
|
1636 |
|
|
|
1637 |
|
|
/* Prime reply & request queues!
|
1638 |
|
|
* (mucho alloc's) Must be done prior to
|
1639 |
|
|
* init as upper addresses are needed for init.
|
1640 |
|
|
* If fails, continue with alt-ioc processing
|
1641 |
|
|
*/
|
1642 |
|
|
if ((ret == 0) && ((r = PrimeIocFifos(ioc)) != 0))
|
1643 |
|
|
ret = -3;
|
1644 |
|
|
|
1645 |
|
|
/* May need to check/upload firmware & data here!
|
1646 |
|
|
* If fails, continue with alt-ioc processing
|
1647 |
|
|
*/
|
1648 |
|
|
if ((ret == 0) && ((r = SendIocInit(ioc, sleepFlag)) != 0))
|
1649 |
|
|
ret = -4;
|
1650 |
|
|
// NEW!
|
1651 |
|
|
if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
|
1652 |
|
|
printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
|
1653 |
|
|
ioc->alt_ioc->name, r);
|
1654 |
|
|
alt_ioc_ready = 0;
|
1655 |
|
|
reset_alt_ioc_active = 0;
|
1656 |
|
|
}
|
1657 |
|
|
|
1658 |
|
|
if (alt_ioc_ready) {
|
1659 |
|
|
if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
|
1660 |
|
|
alt_ioc_ready = 0;
|
1661 |
|
|
reset_alt_ioc_active = 0;
|
1662 |
|
|
printk(KERN_WARNING MYNAM
|
1663 |
|
|
": alt-%s: (%d) init failure WARNING!\n",
|
1664 |
|
|
ioc->alt_ioc->name, r);
|
1665 |
|
|
}
|
1666 |
|
|
}
|
1667 |
|
|
|
1668 |
|
|
if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
|
1669 |
|
|
if (ioc->upload_fw) {
|
1670 |
|
|
ddlprintk((MYIOC_s_INFO_FMT
|
1671 |
|
|
"firmware upload required!\n", ioc->name));
|
1672 |
|
|
|
1673 |
|
|
/* Controller is not operational, cannot do upload
|
1674 |
|
|
*/
|
1675 |
|
|
if (ret == 0) {
|
1676 |
|
|
r = mpt_do_upload(ioc, sleepFlag);
|
1677 |
|
|
if (r != 0)
|
1678 |
|
|
printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
|
1679 |
|
|
}
|
1680 |
|
|
|
1681 |
|
|
/* Handle the alt IOC too */
|
1682 |
|
|
if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){
|
1683 |
|
|
ddlprintk((MYIOC_s_INFO_FMT
|
1684 |
|
|
"Alt-ioc firmware upload required!\n",
|
1685 |
|
|
ioc->name));
|
1686 |
|
|
r = mpt_do_upload(ioc->alt_ioc, sleepFlag);
|
1687 |
|
|
if (r != 0)
|
1688 |
|
|
printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
|
1689 |
|
|
}
|
1690 |
|
|
}
|
1691 |
|
|
}
|
1692 |
|
|
|
1693 |
|
|
if (ret == 0) {
|
1694 |
|
|
/* Enable! (reply interrupt) */
|
1695 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
|
1696 |
|
|
ioc->active = 1;
|
1697 |
|
|
}
|
1698 |
|
|
|
1699 |
|
|
if (reset_alt_ioc_active && ioc->alt_ioc) {
|
1700 |
|
|
/* (re)Enable alt-IOC! (reply interrupt) */
|
1701 |
|
|
dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
|
1702 |
|
|
ioc->alt_ioc->name));
|
1703 |
|
|
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
|
1704 |
|
|
ioc->alt_ioc->active = 1;
|
1705 |
|
|
}
|
1706 |
|
|
|
1707 |
|
|
/* NEW! 20010120 -sralston
|
1708 |
|
|
* Enable MPT base driver management of EventNotification
|
1709 |
|
|
* and EventAck handling.
|
1710 |
|
|
*/
|
1711 |
|
|
if ((ret == 0) && (!ioc->facts.EventState))
|
1712 |
|
|
(void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
|
1713 |
|
|
|
1714 |
|
|
if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
|
1715 |
|
|
(void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
|
1716 |
|
|
|
1717 |
|
|
/* (Bugzilla:fibrebugs, #513)
|
1718 |
|
|
* Bug fix (part 2)! 20010905 -sralston
|
1719 |
|
|
* Add additional "reason" check before call to GetLanConfigPages
|
1720 |
|
|
* (combined with GetIoUnitPage2 call). This prevents a somewhat
|
1721 |
|
|
* recursive scenario; GetLanConfigPages times out, timer expired
|
1722 |
|
|
* routine calls HardResetHandler, which calls into here again,
|
1723 |
|
|
* and we try GetLanConfigPages again...
|
1724 |
|
|
*/
|
1725 |
|
|
if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
|
1726 |
|
|
if ((int)ioc->chip_type <= (int)FC929) {
|
1727 |
|
|
/*
|
1728 |
|
|
* Pre-fetch FC port WWN and stuff...
|
1729 |
|
|
* (FCPortPage0_t stuff)
|
1730 |
|
|
*/
|
1731 |
|
|
for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
|
1732 |
|
|
(void) GetFcPortPage0(ioc, ii);
|
1733 |
|
|
}
|
1734 |
|
|
|
1735 |
|
|
if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
|
1736 |
|
|
(ioc->lan_cnfg_page0.Header.PageLength == 0)) {
|
1737 |
|
|
/*
|
1738 |
|
|
* Pre-fetch the ports LAN MAC address!
|
1739 |
|
|
* (LANPage1_t stuff)
|
1740 |
|
|
*/
|
1741 |
|
|
(void) GetLanConfigPages(ioc);
|
1742 |
|
|
#ifdef MPT_DEBUG
|
1743 |
|
|
{
|
1744 |
|
|
u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
|
1745 |
|
|
dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
|
1746 |
|
|
ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
|
1747 |
|
|
}
|
1748 |
|
|
#endif
|
1749 |
|
|
}
|
1750 |
|
|
} else {
|
1751 |
|
|
/* Get NVRAM and adapter maximums from SPP 0 and 2
|
1752 |
|
|
*/
|
1753 |
|
|
mpt_GetScsiPortSettings(ioc, 0);
|
1754 |
|
|
|
1755 |
|
|
/* Get version and length of SDP 1
|
1756 |
|
|
*/
|
1757 |
|
|
mpt_readScsiDevicePageHeaders(ioc, 0);
|
1758 |
|
|
|
1759 |
|
|
/* Find IM volumes
|
1760 |
|
|
*/
|
1761 |
|
|
if (ioc->facts.MsgVersion >= 0x0102)
|
1762 |
|
|
mpt_findImVolumes(ioc);
|
1763 |
|
|
|
1764 |
|
|
/* Check, and possibly reset, the coalescing value
|
1765 |
|
|
*/
|
1766 |
|
|
mpt_read_ioc_pg_1(ioc);
|
1767 |
|
|
|
1768 |
|
|
mpt_read_ioc_pg_4(ioc);
|
1769 |
|
|
}
|
1770 |
|
|
|
1771 |
|
|
GetIoUnitPage2(ioc);
|
1772 |
|
|
}
|
1773 |
|
|
|
1774 |
|
|
/*
|
1775 |
|
|
* Call each currently registered protocol IOC reset handler
|
1776 |
|
|
* with post-reset indication.
|
1777 |
|
|
* NOTE: If we're doing _IOC_BRINGUP, there can be no
|
1778 |
|
|
* MptResetHandlers[] registered yet.
|
1779 |
|
|
*/
|
1780 |
|
|
if (hard_reset_done) {
|
1781 |
|
|
r = handlers = 0;
|
1782 |
|
|
for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
|
1783 |
|
|
if ((ret == 0) && MptResetHandlers[ii]) {
|
1784 |
|
|
dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
|
1785 |
|
|
ioc->name, ii));
|
1786 |
|
|
r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
|
1787 |
|
|
handlers++;
|
1788 |
|
|
}
|
1789 |
|
|
|
1790 |
|
|
if (alt_ioc_ready && MptResetHandlers[ii]) {
|
1791 |
|
|
dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
|
1792 |
|
|
ioc->name, ioc->alt_ioc->name, ii));
|
1793 |
|
|
r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
|
1794 |
|
|
handlers++;
|
1795 |
|
|
}
|
1796 |
|
|
}
|
1797 |
|
|
/* FIXME? Examine results here? */
|
1798 |
|
|
}
|
1799 |
|
|
|
1800 |
|
|
return ret;
|
1801 |
|
|
}
|
1802 |
|
|
|
1803 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1804 |
|
|
/*
|
1805 |
|
|
* mpt_detect_bound_ports - Search for PCI bus/dev_function
|
1806 |
|
|
* which matches PCI bus/dev_function (+/-1) for newly discovered 929,
|
1807 |
|
|
* 929X, 1030 or 1035.
|
1808 |
|
|
* @ioc: Pointer to MPT adapter structure
|
1809 |
|
|
* @pdev: Pointer to (struct pci_dev) structure
|
1810 |
|
|
*
|
1811 |
|
|
* If match on PCI dev_function +/-1 is found, bind the two MPT adapters
|
1812 |
|
|
* using alt_ioc pointer fields in their %MPT_ADAPTER structures.
|
1813 |
|
|
*/
|
1814 |
|
|
static void
|
1815 |
|
|
mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
|
1816 |
|
|
{
|
1817 |
|
|
MPT_ADAPTER *ioc_srch = mpt_adapter_find_first();
|
1818 |
|
|
unsigned int match_lo, match_hi;
|
1819 |
|
|
|
1820 |
|
|
match_lo = pdev->devfn-1;
|
1821 |
|
|
match_hi = pdev->devfn+1;
|
1822 |
|
|
dprintk((MYIOC_s_INFO_FMT "PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
|
1823 |
|
|
ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi));
|
1824 |
|
|
|
1825 |
|
|
while (ioc_srch != NULL) {
|
1826 |
|
|
struct pci_dev *_pcidev = ioc_srch->pcidev;
|
1827 |
|
|
|
1828 |
|
|
if ((_pcidev->device == pdev->device) &&
|
1829 |
|
|
(_pcidev->bus->number == pdev->bus->number) &&
|
1830 |
|
|
(_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
|
1831 |
|
|
/* Paranoia checks */
|
1832 |
|
|
if (ioc->alt_ioc != NULL) {
|
1833 |
|
|
printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
|
1834 |
|
|
ioc->name, ioc->alt_ioc->name);
|
1835 |
|
|
break;
|
1836 |
|
|
} else if (ioc_srch->alt_ioc != NULL) {
|
1837 |
|
|
printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
|
1838 |
|
|
ioc_srch->name, ioc_srch->alt_ioc->name);
|
1839 |
|
|
break;
|
1840 |
|
|
}
|
1841 |
|
|
dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
|
1842 |
|
|
ioc->name, ioc_srch->name));
|
1843 |
|
|
ioc_srch->alt_ioc = ioc;
|
1844 |
|
|
ioc->alt_ioc = ioc_srch;
|
1845 |
|
|
break;
|
1846 |
|
|
}
|
1847 |
|
|
ioc_srch = mpt_adapter_find_next(ioc_srch);
|
1848 |
|
|
}
|
1849 |
|
|
}
|
1850 |
|
|
|
1851 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1852 |
|
|
/*
|
1853 |
|
|
* mpt_adapter_disable - Disable misbehaving MPT adapter.
|
1854 |
|
|
* @this: Pointer to MPT adapter structure
|
1855 |
|
|
* @free: Free up alloc'd reply, request, etc.
|
1856 |
|
|
*/
|
1857 |
|
|
static void
|
1858 |
|
|
mpt_adapter_disable(MPT_ADAPTER *this, int freeup)
|
1859 |
|
|
{
|
1860 |
|
|
if (this != NULL) {
|
1861 |
|
|
int sz;
|
1862 |
|
|
u32 state;
|
1863 |
|
|
int ret;
|
1864 |
|
|
|
1865 |
|
|
/* Disable the FW */
|
1866 |
|
|
state = mpt_GetIocState(this, 1);
|
1867 |
|
|
if (state == MPI_IOC_STATE_OPERATIONAL) {
|
1868 |
|
|
SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP);
|
1869 |
|
|
}
|
1870 |
|
|
|
1871 |
|
|
if (this->cached_fw != NULL) {
|
1872 |
|
|
ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n"));
|
1873 |
|
|
|
1874 |
|
|
if ((ret = mpt_downloadboot(this, NO_SLEEP)) < 0) {
|
1875 |
|
|
printk(KERN_WARNING MYNAM
|
1876 |
|
|
": firmware downloadboot failure (%d)!\n", ret);
|
1877 |
|
|
}
|
1878 |
|
|
}
|
1879 |
|
|
|
1880 |
|
|
/* Disable adapter interrupts! */
|
1881 |
|
|
CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
|
1882 |
|
|
this->active = 0;
|
1883 |
|
|
/* Clear any lingering interrupt */
|
1884 |
|
|
CHIPREG_WRITE32(&this->chip->IntStatus, 0);
|
1885 |
|
|
|
1886 |
|
|
if (freeup && this->reply_alloc != NULL) {
|
1887 |
|
|
sz = (this->reply_sz * this->reply_depth) + 128;
|
1888 |
|
|
pci_free_consistent(this->pcidev, sz,
|
1889 |
|
|
this->reply_alloc, this->reply_alloc_dma);
|
1890 |
|
|
this->reply_frames = NULL;
|
1891 |
|
|
this->reply_alloc = NULL;
|
1892 |
|
|
this->alloc_total -= sz;
|
1893 |
|
|
}
|
1894 |
|
|
|
1895 |
|
|
if (freeup && this->req_alloc != NULL) {
|
1896 |
|
|
sz = (this->req_sz * this->req_depth) + 128;
|
1897 |
|
|
/*
|
1898 |
|
|
* Rounding UP to nearest 4-kB boundary here...
|
1899 |
|
|
*/
|
1900 |
|
|
sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
|
1901 |
|
|
pci_free_consistent(this->pcidev, sz,
|
1902 |
|
|
this->req_alloc, this->req_alloc_dma);
|
1903 |
|
|
this->req_frames = NULL;
|
1904 |
|
|
this->req_alloc = NULL;
|
1905 |
|
|
this->alloc_total -= sz;
|
1906 |
|
|
}
|
1907 |
|
|
|
1908 |
|
|
if (freeup && this->sense_buf_pool != NULL) {
|
1909 |
|
|
sz = (this->req_depth * MPT_SENSE_BUFFER_ALLOC);
|
1910 |
|
|
pci_free_consistent(this->pcidev, sz,
|
1911 |
|
|
this->sense_buf_pool, this->sense_buf_pool_dma);
|
1912 |
|
|
this->sense_buf_pool = NULL;
|
1913 |
|
|
this->alloc_total -= sz;
|
1914 |
|
|
}
|
1915 |
|
|
|
1916 |
|
|
if (freeup && this->events != NULL){
|
1917 |
|
|
sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
|
1918 |
|
|
kfree(this->events);
|
1919 |
|
|
this->events = NULL;
|
1920 |
|
|
this->alloc_total -= sz;
|
1921 |
|
|
}
|
1922 |
|
|
|
1923 |
|
|
if (freeup && this->cached_fw != NULL) {
|
1924 |
|
|
int ii = 0;
|
1925 |
|
|
|
1926 |
|
|
while ((ii < this->num_fw_frags) && (this->cached_fw[ii]!= NULL)) {
|
1927 |
|
|
sz = this->cached_fw[ii]->size;
|
1928 |
|
|
pci_free_consistent(this->pcidev, sz,
|
1929 |
|
|
this->cached_fw[ii]->fw, this->cached_fw[ii]->fw_dma);
|
1930 |
|
|
this->cached_fw[ii]->fw = NULL;
|
1931 |
|
|
this->alloc_total -= sz;
|
1932 |
|
|
|
1933 |
|
|
kfree(this->cached_fw[ii]);
|
1934 |
|
|
this->cached_fw[ii] = NULL;
|
1935 |
|
|
this->alloc_total -= sizeof(fw_image_t);
|
1936 |
|
|
|
1937 |
|
|
ii++;
|
1938 |
|
|
}
|
1939 |
|
|
|
1940 |
|
|
kfree(this->cached_fw);
|
1941 |
|
|
this->cached_fw = NULL;
|
1942 |
|
|
sz = this->num_fw_frags * sizeof(void *);
|
1943 |
|
|
this->alloc_total -= sz;
|
1944 |
|
|
}
|
1945 |
|
|
|
1946 |
|
|
if (freeup && this->spi_data.nvram != NULL) {
|
1947 |
|
|
kfree(this->spi_data.nvram);
|
1948 |
|
|
this->spi_data.nvram = NULL;
|
1949 |
|
|
}
|
1950 |
|
|
|
1951 |
|
|
if (freeup && this->spi_data.pIocPg3 != NULL) {
|
1952 |
|
|
kfree(this->spi_data.pIocPg3);
|
1953 |
|
|
this->spi_data.pIocPg3 = NULL;
|
1954 |
|
|
}
|
1955 |
|
|
|
1956 |
|
|
if (freeup && this->spi_data.pIocPg4 != NULL) {
|
1957 |
|
|
sz = this->spi_data.IocPg4Sz;
|
1958 |
|
|
pci_free_consistent(this->pcidev, sz,
|
1959 |
|
|
this->spi_data.pIocPg4,
|
1960 |
|
|
this->spi_data.IocPg4_dma);
|
1961 |
|
|
this->spi_data.pIocPg4 = NULL;
|
1962 |
|
|
this->alloc_total -= sz;
|
1963 |
|
|
}
|
1964 |
|
|
}
|
1965 |
|
|
}
|
1966 |
|
|
|
1967 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1968 |
|
|
/*
|
1969 |
|
|
* mpt_adapter_dispose - Free all resources associated with a MPT
|
1970 |
|
|
* adapter.
|
1971 |
|
|
* @this: Pointer to MPT adapter structure
|
1972 |
|
|
*
|
1973 |
|
|
* This routine unregisters h/w resources and frees all alloc'd memory
|
1974 |
|
|
* associated with a MPT adapter structure.
|
1975 |
|
|
*/
|
1976 |
|
|
static void
|
1977 |
|
|
mpt_adapter_dispose(MPT_ADAPTER *this)
|
1978 |
|
|
{
|
1979 |
|
|
if (this != NULL) {
|
1980 |
|
|
int sz_first, sz_last;
|
1981 |
|
|
|
1982 |
|
|
sz_first = this->alloc_total;
|
1983 |
|
|
|
1984 |
|
|
if (this->alt_ioc != NULL) {
|
1985 |
|
|
this->alt_ioc->alt_ioc = NULL;
|
1986 |
|
|
this->alt_ioc = NULL;
|
1987 |
|
|
}
|
1988 |
|
|
|
1989 |
|
|
mpt_adapter_disable(this, 1);
|
1990 |
|
|
|
1991 |
|
|
if (this->pci_irq != -1) {
|
1992 |
|
|
free_irq(this->pci_irq, this);
|
1993 |
|
|
this->pci_irq = -1;
|
1994 |
|
|
}
|
1995 |
|
|
|
1996 |
|
|
if (this->memmap != NULL)
|
1997 |
|
|
iounmap((u8 *) this->memmap);
|
1998 |
|
|
|
1999 |
|
|
#if defined(CONFIG_MTRR) && 0
|
2000 |
|
|
if (this->mtrr_reg > 0) {
|
2001 |
|
|
mtrr_del(this->mtrr_reg, 0, 0);
|
2002 |
|
|
dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name));
|
2003 |
|
|
}
|
2004 |
|
|
#endif
|
2005 |
|
|
|
2006 |
|
|
/* Zap the adapter lookup ptr! */
|
2007 |
|
|
mpt_adapters[this->id] = NULL;
|
2008 |
|
|
|
2009 |
|
|
sz_last = this->alloc_total;
|
2010 |
|
|
dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
|
2011 |
|
|
this->name, sz_first-sz_last+(int)sizeof(*this), sz_first));
|
2012 |
|
|
kfree(this);
|
2013 |
|
|
}
|
2014 |
|
|
}
|
2015 |
|
|
|
2016 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2017 |
|
|
/*
|
2018 |
|
|
* MptDisplayIocCapabilities - Disply IOC's capacilities.
|
2019 |
|
|
* @ioc: Pointer to MPT adapter structure
|
2020 |
|
|
*/
|
2021 |
|
|
static void
|
2022 |
|
|
MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
|
2023 |
|
|
{
|
2024 |
|
|
int i = 0;
|
2025 |
|
|
|
2026 |
|
|
printk(KERN_INFO "%s: ", ioc->name);
|
2027 |
|
|
if (ioc->prod_name && strlen(ioc->prod_name) > 3)
|
2028 |
|
|
printk("%s: ", ioc->prod_name+3);
|
2029 |
|
|
printk("Capabilities={");
|
2030 |
|
|
|
2031 |
|
|
if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
|
2032 |
|
|
printk("Initiator");
|
2033 |
|
|
i++;
|
2034 |
|
|
}
|
2035 |
|
|
|
2036 |
|
|
if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
|
2037 |
|
|
printk("%sTarget", i ? "," : "");
|
2038 |
|
|
i++;
|
2039 |
|
|
}
|
2040 |
|
|
|
2041 |
|
|
if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
|
2042 |
|
|
printk("%sLAN", i ? "," : "");
|
2043 |
|
|
i++;
|
2044 |
|
|
}
|
2045 |
|
|
|
2046 |
|
|
#if 0
|
2047 |
|
|
/*
|
2048 |
|
|
* This would probably evoke more questions than it's worth
|
2049 |
|
|
*/
|
2050 |
|
|
if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
|
2051 |
|
|
printk("%sLogBusAddr", i ? "," : "");
|
2052 |
|
|
i++;
|
2053 |
|
|
}
|
2054 |
|
|
#endif
|
2055 |
|
|
|
2056 |
|
|
printk("}\n");
|
2057 |
|
|
}
|
2058 |
|
|
|
2059 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2060 |
|
|
/*
|
2061 |
|
|
* MakeIocReady - Get IOC to a READY state, using KickStart if needed.
|
2062 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2063 |
|
|
* @force: Force hard KickStart of IOC
|
2064 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
2065 |
|
|
*
|
2066 |
|
|
* Returns:
|
2067 |
|
|
* 1 - DIAG reset and READY
|
2068 |
|
|
* 0 - READY initially OR soft reset and READY
|
2069 |
|
|
* -1 - Any failure on KickStart
|
2070 |
|
|
* -2 - Msg Unit Reset Failed
|
2071 |
|
|
* -3 - IO Unit Reset Failed
|
2072 |
|
|
* -4 - IOC owned by a PEER
|
2073 |
|
|
*/
|
2074 |
|
|
static int
|
2075 |
|
|
MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
|
2076 |
|
|
{
|
2077 |
|
|
u32 ioc_state;
|
2078 |
|
|
int statefault = 0;
|
2079 |
|
|
int cntdn;
|
2080 |
|
|
int hard_reset_done = 0;
|
2081 |
|
|
int r;
|
2082 |
|
|
int ii;
|
2083 |
|
|
int whoinit;
|
2084 |
|
|
|
2085 |
|
|
/* Get current [raw] IOC state */
|
2086 |
|
|
ioc_state = mpt_GetIocState(ioc, 0);
|
2087 |
|
|
dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
|
2088 |
|
|
|
2089 |
|
|
/*
|
2090 |
|
|
* Check to see if IOC got left/stuck in doorbell handshake
|
2091 |
|
|
* grip of death. If so, hard reset the IOC.
|
2092 |
|
|
*/
|
2093 |
|
|
if (ioc_state & MPI_DOORBELL_ACTIVE) {
|
2094 |
|
|
statefault = 1;
|
2095 |
|
|
printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
|
2096 |
|
|
ioc->name);
|
2097 |
|
|
}
|
2098 |
|
|
|
2099 |
|
|
/* Is it already READY? */
|
2100 |
|
|
if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) {
|
2101 |
|
|
if ((int)ioc->chip_type <= (int)FC929)
|
2102 |
|
|
return 0;
|
2103 |
|
|
else {
|
2104 |
|
|
/* Workaround from broken 1030 FW.
|
2105 |
|
|
* Force a diagnostic reset if fails.
|
2106 |
|
|
*/
|
2107 |
|
|
if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
|
2108 |
|
|
return 0;
|
2109 |
|
|
else
|
2110 |
|
|
statefault = 4;
|
2111 |
|
|
}
|
2112 |
|
|
}
|
2113 |
|
|
|
2114 |
|
|
/*
|
2115 |
|
|
* Check to see if IOC is in FAULT state.
|
2116 |
|
|
*/
|
2117 |
|
|
if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
|
2118 |
|
|
statefault = 2;
|
2119 |
|
|
printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
|
2120 |
|
|
ioc->name);
|
2121 |
|
|
printk(KERN_WARNING " FAULT code = %04xh\n",
|
2122 |
|
|
ioc_state & MPI_DOORBELL_DATA_MASK);
|
2123 |
|
|
}
|
2124 |
|
|
|
2125 |
|
|
/*
|
2126 |
|
|
* Hmmm... Did it get left operational?
|
2127 |
|
|
*/
|
2128 |
|
|
if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
|
2129 |
|
|
dprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n",
|
2130 |
|
|
ioc->name));
|
2131 |
|
|
|
2132 |
|
|
/* Check WhoInit.
|
2133 |
|
|
* If PCI Peer, exit.
|
2134 |
|
|
* Else, if no fault conditions are present, issue a MessageUnitReset
|
2135 |
|
|
* Else, fall through to KickStart case
|
2136 |
|
|
*/
|
2137 |
|
|
whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
|
2138 |
|
|
dprintk((KERN_WARNING MYNAM
|
2139 |
|
|
": whoinit 0x%x\n statefault %d force %d\n",
|
2140 |
|
|
whoinit, statefault, force));
|
2141 |
|
|
if (whoinit == MPI_WHOINIT_PCI_PEER)
|
2142 |
|
|
return -4;
|
2143 |
|
|
else {
|
2144 |
|
|
if ((statefault == 0 ) && (force == 0)) {
|
2145 |
|
|
if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
|
2146 |
|
|
return 0;
|
2147 |
|
|
}
|
2148 |
|
|
statefault = 3;
|
2149 |
|
|
}
|
2150 |
|
|
}
|
2151 |
|
|
|
2152 |
|
|
hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
|
2153 |
|
|
if (hard_reset_done < 0)
|
2154 |
|
|
return -1;
|
2155 |
|
|
|
2156 |
|
|
/*
|
2157 |
|
|
* Loop here waiting for IOC to come READY.
|
2158 |
|
|
*/
|
2159 |
|
|
ii = 0;
|
2160 |
|
|
cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
|
2161 |
|
|
|
2162 |
|
|
while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
|
2163 |
|
|
if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
|
2164 |
|
|
/*
|
2165 |
|
|
* BIOS or previous driver load left IOC in OP state.
|
2166 |
|
|
* Reset messaging FIFOs.
|
2167 |
|
|
*/
|
2168 |
|
|
if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
|
2169 |
|
|
printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
|
2170 |
|
|
return -2;
|
2171 |
|
|
}
|
2172 |
|
|
} else if (ioc_state == MPI_IOC_STATE_RESET) {
|
2173 |
|
|
/*
|
2174 |
|
|
* Something is wrong. Try to get IOC back
|
2175 |
|
|
* to a known state.
|
2176 |
|
|
*/
|
2177 |
|
|
if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
|
2178 |
|
|
printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
|
2179 |
|
|
return -3;
|
2180 |
|
|
}
|
2181 |
|
|
}
|
2182 |
|
|
|
2183 |
|
|
ii++; cntdn--;
|
2184 |
|
|
if (!cntdn) {
|
2185 |
|
|
printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
|
2186 |
|
|
ioc->name, (ii+5)/HZ);
|
2187 |
|
|
return -ETIME;
|
2188 |
|
|
}
|
2189 |
|
|
|
2190 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
2191 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
2192 |
|
|
schedule_timeout(1);
|
2193 |
|
|
} else {
|
2194 |
|
|
mdelay (1); /* 1 msec delay */
|
2195 |
|
|
}
|
2196 |
|
|
|
2197 |
|
|
}
|
2198 |
|
|
|
2199 |
|
|
if (statefault < 3) {
|
2200 |
|
|
printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
|
2201 |
|
|
ioc->name,
|
2202 |
|
|
statefault==1 ? "stuck handshake" : "IOC FAULT");
|
2203 |
|
|
}
|
2204 |
|
|
|
2205 |
|
|
return hard_reset_done;
|
2206 |
|
|
}
|
2207 |
|
|
|
2208 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2209 |
|
|
/*
|
2210 |
|
|
* mpt_GetIocState - Get the current state of a MPT adapter.
|
2211 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2212 |
|
|
* @cooked: Request raw or cooked IOC state
|
2213 |
|
|
*
|
2214 |
|
|
* Returns all IOC Doorbell register bits if cooked==0, else just the
|
2215 |
|
|
* Doorbell bits in MPI_IOC_STATE_MASK.
|
2216 |
|
|
*/
|
2217 |
|
|
u32
|
2218 |
|
|
mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
|
2219 |
|
|
{
|
2220 |
|
|
u32 s, sc;
|
2221 |
|
|
|
2222 |
|
|
/* Get! */
|
2223 |
|
|
s = CHIPREG_READ32(&ioc->chip->Doorbell);
|
2224 |
|
|
// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
|
2225 |
|
|
sc = s & MPI_IOC_STATE_MASK;
|
2226 |
|
|
|
2227 |
|
|
/* Save! */
|
2228 |
|
|
ioc->last_state = sc;
|
2229 |
|
|
|
2230 |
|
|
return cooked ? sc : s;
|
2231 |
|
|
}
|
2232 |
|
|
|
2233 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2234 |
|
|
/*
|
2235 |
|
|
* GetIocFacts - Send IOCFacts request to MPT adapter.
|
2236 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2237 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
2238 |
|
|
* @reason: If recovery, only update facts.
|
2239 |
|
|
*
|
2240 |
|
|
* Returns 0 for success, non-zero for failure.
|
2241 |
|
|
*/
|
2242 |
|
|
static int
|
2243 |
|
|
GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
|
2244 |
|
|
{
|
2245 |
|
|
IOCFacts_t get_facts;
|
2246 |
|
|
IOCFactsReply_t *facts;
|
2247 |
|
|
int r;
|
2248 |
|
|
int req_sz;
|
2249 |
|
|
int reply_sz;
|
2250 |
|
|
u32 status;
|
2251 |
|
|
|
2252 |
|
|
/* IOC *must* NOT be in RESET state! */
|
2253 |
|
|
if (ioc->last_state == MPI_IOC_STATE_RESET) {
|
2254 |
|
|
printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
|
2255 |
|
|
ioc->name,
|
2256 |
|
|
ioc->last_state );
|
2257 |
|
|
return -44;
|
2258 |
|
|
}
|
2259 |
|
|
|
2260 |
|
|
facts = &ioc->facts;
|
2261 |
|
|
|
2262 |
|
|
/* Destination (reply area)... */
|
2263 |
|
|
reply_sz = sizeof(*facts);
|
2264 |
|
|
memset(facts, 0, reply_sz);
|
2265 |
|
|
|
2266 |
|
|
/* Request area (get_facts on the stack right now!) */
|
2267 |
|
|
req_sz = sizeof(get_facts);
|
2268 |
|
|
memset(&get_facts, 0, req_sz);
|
2269 |
|
|
|
2270 |
|
|
get_facts.Function = MPI_FUNCTION_IOC_FACTS;
|
2271 |
|
|
/* Assert: All other get_facts fields are zero! */
|
2272 |
|
|
|
2273 |
|
|
dprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name));
|
2274 |
|
|
|
2275 |
|
|
/* No non-zero fields in the get_facts request are greater than
|
2276 |
|
|
* 1 byte in size, so we can just fire it off as is.
|
2277 |
|
|
*/
|
2278 |
|
|
r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
|
2279 |
|
|
reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag);
|
2280 |
|
|
if (r != 0)
|
2281 |
|
|
return r;
|
2282 |
|
|
|
2283 |
|
|
/*
|
2284 |
|
|
* Now byte swap (GRRR) the necessary fields before any further
|
2285 |
|
|
* inspection of reply contents.
|
2286 |
|
|
*
|
2287 |
|
|
* But need to do some sanity checks on MsgLength (byte) field
|
2288 |
|
|
* to make sure we don't zero IOC's req_sz!
|
2289 |
|
|
*/
|
2290 |
|
|
/* Did we get a valid reply? */
|
2291 |
|
|
if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
|
2292 |
|
|
if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
|
2293 |
|
|
/*
|
2294 |
|
|
* If not been here, done that, save off first WhoInit value
|
2295 |
|
|
*/
|
2296 |
|
|
if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
|
2297 |
|
|
ioc->FirstWhoInit = facts->WhoInit;
|
2298 |
|
|
}
|
2299 |
|
|
|
2300 |
|
|
facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
|
2301 |
|
|
facts->MsgContext = le32_to_cpu(facts->MsgContext);
|
2302 |
|
|
facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
|
2303 |
|
|
facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
|
2304 |
|
|
facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
|
2305 |
|
|
status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
|
2306 |
|
|
/* CHECKME! IOCStatus, IOCLogInfo */
|
2307 |
|
|
|
2308 |
|
|
facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
|
2309 |
|
|
facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
|
2310 |
|
|
|
2311 |
|
|
/*
|
2312 |
|
|
* FC f/w version changed between 1.1 and 1.2
|
2313 |
|
|
* Old: u16{Major(4),Minor(4),SubMinor(8)}
|
2314 |
|
|
* New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
|
2315 |
|
|
*/
|
2316 |
|
|
if (facts->MsgVersion < 0x0102) {
|
2317 |
|
|
/*
|
2318 |
|
|
* Handle old FC f/w style, convert to new...
|
2319 |
|
|
*/
|
2320 |
|
|
u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
|
2321 |
|
|
facts->FWVersion.Word =
|
2322 |
|
|
((oldv<<12) & 0xFF000000) |
|
2323 |
|
|
((oldv<<8) & 0x000FFF00);
|
2324 |
|
|
} else
|
2325 |
|
|
facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
|
2326 |
|
|
|
2327 |
|
|
facts->ProductID = le16_to_cpu(facts->ProductID);
|
2328 |
|
|
facts->CurrentHostMfaHighAddr =
|
2329 |
|
|
le32_to_cpu(facts->CurrentHostMfaHighAddr);
|
2330 |
|
|
facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
|
2331 |
|
|
facts->CurrentSenseBufferHighAddr =
|
2332 |
|
|
le32_to_cpu(facts->CurrentSenseBufferHighAddr);
|
2333 |
|
|
facts->CurReplyFrameSize =
|
2334 |
|
|
le16_to_cpu(facts->CurReplyFrameSize);
|
2335 |
|
|
|
2336 |
|
|
/*
|
2337 |
|
|
* Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
|
2338 |
|
|
* Older MPI-1.00.xx struct had 13 dwords, and enlarged
|
2339 |
|
|
* to 14 in MPI-1.01.0x.
|
2340 |
|
|
*/
|
2341 |
|
|
if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
|
2342 |
|
|
facts->MsgVersion > 0x0100) {
|
2343 |
|
|
facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
|
2344 |
|
|
}
|
2345 |
|
|
|
2346 |
|
|
if (!facts->RequestFrameSize) {
|
2347 |
|
|
/* Something is wrong! */
|
2348 |
|
|
printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
|
2349 |
|
|
ioc->name);
|
2350 |
|
|
return -55;
|
2351 |
|
|
}
|
2352 |
|
|
|
2353 |
|
|
if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
|
2354 |
|
|
/*
|
2355 |
|
|
* Set values for this IOC's request & reply frame sizes,
|
2356 |
|
|
* and request & reply queue depths...
|
2357 |
|
|
*/
|
2358 |
|
|
ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
|
2359 |
|
|
ioc->req_depth = MIN(MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
|
2360 |
|
|
ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
|
2361 |
|
|
ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
|
2362 |
|
|
|
2363 |
|
|
dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
|
2364 |
|
|
ioc->name, ioc->reply_sz, ioc->reply_depth));
|
2365 |
|
|
dprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
|
2366 |
|
|
ioc->name, ioc->req_sz, ioc->req_depth));
|
2367 |
|
|
|
2368 |
|
|
/* Get port facts! */
|
2369 |
|
|
if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
|
2370 |
|
|
return r;
|
2371 |
|
|
}
|
2372 |
|
|
} else {
|
2373 |
|
|
printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply!\n",
|
2374 |
|
|
ioc->name);
|
2375 |
|
|
return -66;
|
2376 |
|
|
}
|
2377 |
|
|
|
2378 |
|
|
return 0;
|
2379 |
|
|
}
|
2380 |
|
|
|
2381 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2382 |
|
|
/*
|
2383 |
|
|
* GetPortFacts - Send PortFacts request to MPT adapter.
|
2384 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2385 |
|
|
* @portnum: Port number
|
2386 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
2387 |
|
|
*
|
2388 |
|
|
* Returns 0 for success, non-zero for failure.
|
2389 |
|
|
*/
|
2390 |
|
|
static int
|
2391 |
|
|
GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
|
2392 |
|
|
{
|
2393 |
|
|
PortFacts_t get_pfacts;
|
2394 |
|
|
PortFactsReply_t *pfacts;
|
2395 |
|
|
int ii;
|
2396 |
|
|
int req_sz;
|
2397 |
|
|
int reply_sz;
|
2398 |
|
|
|
2399 |
|
|
/* IOC *must* NOT be in RESET state! */
|
2400 |
|
|
if (ioc->last_state == MPI_IOC_STATE_RESET) {
|
2401 |
|
|
printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
|
2402 |
|
|
ioc->name,
|
2403 |
|
|
ioc->last_state );
|
2404 |
|
|
return -4;
|
2405 |
|
|
}
|
2406 |
|
|
|
2407 |
|
|
pfacts = &ioc->pfacts[portnum];
|
2408 |
|
|
|
2409 |
|
|
/* Destination (reply area)... */
|
2410 |
|
|
reply_sz = sizeof(*pfacts);
|
2411 |
|
|
memset(pfacts, 0, reply_sz);
|
2412 |
|
|
|
2413 |
|
|
/* Request area (get_pfacts on the stack right now!) */
|
2414 |
|
|
req_sz = sizeof(get_pfacts);
|
2415 |
|
|
memset(&get_pfacts, 0, req_sz);
|
2416 |
|
|
|
2417 |
|
|
get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
|
2418 |
|
|
get_pfacts.PortNumber = portnum;
|
2419 |
|
|
/* Assert: All other get_pfacts fields are zero! */
|
2420 |
|
|
|
2421 |
|
|
dprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
|
2422 |
|
|
ioc->name, portnum));
|
2423 |
|
|
|
2424 |
|
|
/* No non-zero fields in the get_pfacts request are greater than
|
2425 |
|
|
* 1 byte in size, so we can just fire it off as is.
|
2426 |
|
|
*/
|
2427 |
|
|
ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
|
2428 |
|
|
reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag);
|
2429 |
|
|
if (ii != 0)
|
2430 |
|
|
return ii;
|
2431 |
|
|
|
2432 |
|
|
/* Did we get a valid reply? */
|
2433 |
|
|
|
2434 |
|
|
/* Now byte swap the necessary fields in the response. */
|
2435 |
|
|
pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
|
2436 |
|
|
pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
|
2437 |
|
|
pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
|
2438 |
|
|
pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
|
2439 |
|
|
pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
|
2440 |
|
|
pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
|
2441 |
|
|
pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
|
2442 |
|
|
pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
|
2443 |
|
|
pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
|
2444 |
|
|
|
2445 |
|
|
return 0;
|
2446 |
|
|
}
|
2447 |
|
|
|
2448 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2449 |
|
|
/*
|
2450 |
|
|
* SendIocInit - Send IOCInit request to MPT adapter.
|
2451 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2452 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
2453 |
|
|
*
|
2454 |
|
|
* Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
|
2455 |
|
|
*
|
2456 |
|
|
* Returns 0 for success, non-zero for failure.
|
2457 |
|
|
*/
|
2458 |
|
|
static int
|
2459 |
|
|
SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
|
2460 |
|
|
{
|
2461 |
|
|
IOCInit_t ioc_init;
|
2462 |
|
|
MPIDefaultReply_t init_reply;
|
2463 |
|
|
u32 state;
|
2464 |
|
|
int r;
|
2465 |
|
|
int count;
|
2466 |
|
|
int cntdn;
|
2467 |
|
|
|
2468 |
|
|
memset(&ioc_init, 0, sizeof(ioc_init));
|
2469 |
|
|
memset(&init_reply, 0, sizeof(init_reply));
|
2470 |
|
|
|
2471 |
|
|
ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
|
2472 |
|
|
/* ioc_init.ChainOffset = 0; */
|
2473 |
|
|
ioc_init.Function = MPI_FUNCTION_IOC_INIT;
|
2474 |
|
|
/* ioc_init.Flags = 0; */
|
2475 |
|
|
|
2476 |
|
|
/* If we are in a recovery mode and we uploaded the FW image,
|
2477 |
|
|
* then this pointer is not NULL. Skip the upload a second time.
|
2478 |
|
|
* Set this flag if cached_fw set for either IOC.
|
2479 |
|
|
*/
|
2480 |
|
|
ioc->upload_fw = 0;
|
2481 |
|
|
ioc_init.Flags = 0;
|
2482 |
|
|
if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
|
2483 |
|
|
if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw))
|
2484 |
|
|
ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE;
|
2485 |
|
|
else
|
2486 |
|
|
ioc->upload_fw = 1;
|
2487 |
|
|
}
|
2488 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n",
|
2489 |
|
|
ioc->name, ioc_init.Flags, ioc->upload_fw));
|
2490 |
|
|
|
2491 |
|
|
if ((int)ioc->chip_type <= (int)FC929) {
|
2492 |
|
|
ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
|
2493 |
|
|
} else {
|
2494 |
|
|
ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
|
2495 |
|
|
}
|
2496 |
|
|
ioc_init.MaxBuses = MPT_MAX_BUS;
|
2497 |
|
|
|
2498 |
|
|
/* ioc_init.MsgFlags = 0; */
|
2499 |
|
|
/* ioc_init.MsgContext = cpu_to_le32(0x00000000); */
|
2500 |
|
|
ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
|
2501 |
|
|
|
2502 |
|
|
if (sizeof(dma_addr_t) == sizeof(u64)) {
|
2503 |
|
|
/* Save the upper 32-bits of the request
|
2504 |
|
|
* (reply) and sense buffers.
|
2505 |
|
|
*/
|
2506 |
|
|
ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
|
2507 |
|
|
ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
|
2508 |
|
|
} else {
|
2509 |
|
|
/* Force 32-bit addressing */
|
2510 |
|
|
ioc_init.HostMfaHighAddr = cpu_to_le32(0);
|
2511 |
|
|
ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
|
2512 |
|
|
}
|
2513 |
|
|
|
2514 |
|
|
dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
|
2515 |
|
|
ioc->name, &ioc_init));
|
2516 |
|
|
|
2517 |
|
|
r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
|
2518 |
|
|
sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
|
2519 |
|
|
if (r != 0)
|
2520 |
|
|
return r;
|
2521 |
|
|
|
2522 |
|
|
/* No need to byte swap the multibyte fields in the reply
|
2523 |
|
|
* since we don't even look at it's contents.
|
2524 |
|
|
*/
|
2525 |
|
|
|
2526 |
|
|
if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0)
|
2527 |
|
|
return r;
|
2528 |
|
|
|
2529 |
|
|
/* YIKES! SUPER IMPORTANT!!!
|
2530 |
|
|
* Poll IocState until _OPERATIONAL while IOC is doing
|
2531 |
|
|
* LoopInit and TargetDiscovery!
|
2532 |
|
|
*/
|
2533 |
|
|
count = 0;
|
2534 |
|
|
cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
|
2535 |
|
|
state = mpt_GetIocState(ioc, 1);
|
2536 |
|
|
while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
|
2537 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
2538 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
2539 |
|
|
schedule_timeout(1);
|
2540 |
|
|
} else {
|
2541 |
|
|
mdelay(1);
|
2542 |
|
|
}
|
2543 |
|
|
|
2544 |
|
|
if (!cntdn) {
|
2545 |
|
|
printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
|
2546 |
|
|
ioc->name, (count+5)/HZ);
|
2547 |
|
|
return -9;
|
2548 |
|
|
}
|
2549 |
|
|
|
2550 |
|
|
state = mpt_GetIocState(ioc, 1);
|
2551 |
|
|
count++;
|
2552 |
|
|
}
|
2553 |
|
|
dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
|
2554 |
|
|
ioc->name, count));
|
2555 |
|
|
|
2556 |
|
|
return r;
|
2557 |
|
|
}
|
2558 |
|
|
|
2559 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2560 |
|
|
/*
|
2561 |
|
|
* SendPortEnable - Send PortEnable request to MPT adapter port.
|
2562 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2563 |
|
|
* @portnum: Port number to enable
|
2564 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
2565 |
|
|
*
|
2566 |
|
|
* Send PortEnable to bring IOC to OPERATIONAL state.
|
2567 |
|
|
*
|
2568 |
|
|
* Returns 0 for success, non-zero for failure.
|
2569 |
|
|
*/
|
2570 |
|
|
static int
|
2571 |
|
|
SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
|
2572 |
|
|
{
|
2573 |
|
|
PortEnable_t port_enable;
|
2574 |
|
|
MPIDefaultReply_t reply_buf;
|
2575 |
|
|
int ii;
|
2576 |
|
|
int req_sz;
|
2577 |
|
|
int reply_sz;
|
2578 |
|
|
|
2579 |
|
|
/* Destination... */
|
2580 |
|
|
reply_sz = sizeof(MPIDefaultReply_t);
|
2581 |
|
|
memset(&reply_buf, 0, reply_sz);
|
2582 |
|
|
|
2583 |
|
|
req_sz = sizeof(PortEnable_t);
|
2584 |
|
|
memset(&port_enable, 0, req_sz);
|
2585 |
|
|
|
2586 |
|
|
port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
|
2587 |
|
|
port_enable.PortNumber = portnum;
|
2588 |
|
|
/* port_enable.ChainOffset = 0; */
|
2589 |
|
|
/* port_enable.MsgFlags = 0; */
|
2590 |
|
|
/* port_enable.MsgContext = 0; */
|
2591 |
|
|
|
2592 |
|
|
dprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
|
2593 |
|
|
ioc->name, portnum, &port_enable));
|
2594 |
|
|
|
2595 |
|
|
/* RAID FW may take a long time to enable
|
2596 |
|
|
*/
|
2597 |
|
|
if ((int)ioc->chip_type <= (int)FC929) {
|
2598 |
|
|
ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
|
2599 |
|
|
reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag);
|
2600 |
|
|
} else {
|
2601 |
|
|
ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
|
2602 |
|
|
reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag);
|
2603 |
|
|
}
|
2604 |
|
|
|
2605 |
|
|
if (ii != 0)
|
2606 |
|
|
return ii;
|
2607 |
|
|
|
2608 |
|
|
/* We do not even look at the reply, so we need not
|
2609 |
|
|
* swap the multi-byte fields.
|
2610 |
|
|
*/
|
2611 |
|
|
|
2612 |
|
|
return 0;
|
2613 |
|
|
}
|
2614 |
|
|
|
2615 |
|
|
/*
|
2616 |
|
|
* Inputs: size - total FW bytes
|
2617 |
|
|
* Outputs: frags - number of fragments needed
|
2618 |
|
|
* Return NULL if failed.
|
2619 |
|
|
*/
|
2620 |
|
|
void *
|
2621 |
|
|
mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
|
2622 |
|
|
{
|
2623 |
|
|
fw_image_t **cached_fw;
|
2624 |
|
|
u8 *mem;
|
2625 |
|
|
dma_addr_t fw_dma;
|
2626 |
|
|
int alloc_total = 0;
|
2627 |
|
|
int bytes_left, bytes, num_frags;
|
2628 |
|
|
int sz, ii;
|
2629 |
|
|
|
2630 |
|
|
/* cached_fw
|
2631 |
|
|
*/
|
2632 |
|
|
sz = ioc->num_fw_frags * sizeof(void *);
|
2633 |
|
|
mem = kmalloc(sz, GFP_ATOMIC);
|
2634 |
|
|
if (mem == NULL)
|
2635 |
|
|
return NULL;
|
2636 |
|
|
|
2637 |
|
|
memset(mem, 0, sz);
|
2638 |
|
|
cached_fw = (fw_image_t **)mem;
|
2639 |
|
|
alloc_total += sz;
|
2640 |
|
|
|
2641 |
|
|
/* malloc fragment memory
|
2642 |
|
|
* fw_image_t struct and dma for fw data
|
2643 |
|
|
*/
|
2644 |
|
|
bytes_left = size;
|
2645 |
|
|
ii = 0;
|
2646 |
|
|
num_frags = 0;
|
2647 |
|
|
bytes = bytes_left;
|
2648 |
|
|
while((bytes_left) && (num_frags < ioc->num_fw_frags)) {
|
2649 |
|
|
if (cached_fw[ii] == NULL) {
|
2650 |
|
|
mem = kmalloc(sizeof(fw_image_t), GFP_ATOMIC);
|
2651 |
|
|
if (mem == NULL)
|
2652 |
|
|
break;
|
2653 |
|
|
|
2654 |
|
|
memset(mem, 0, sizeof(fw_image_t));
|
2655 |
|
|
cached_fw[ii] = (fw_image_t *)mem;
|
2656 |
|
|
alloc_total += sizeof(fw_image_t);
|
2657 |
|
|
}
|
2658 |
|
|
|
2659 |
|
|
mem = pci_alloc_consistent(ioc->pcidev, bytes, &fw_dma);
|
2660 |
|
|
if (mem == NULL) {
|
2661 |
|
|
if (bytes > 0x10000)
|
2662 |
|
|
bytes = 0x10000;
|
2663 |
|
|
else if (bytes > 0x8000)
|
2664 |
|
|
bytes = 0x8000;
|
2665 |
|
|
else if (bytes > 0x4000)
|
2666 |
|
|
bytes = 0x4000;
|
2667 |
|
|
else if (bytes > 0x2000)
|
2668 |
|
|
bytes = 0x2000;
|
2669 |
|
|
else if (bytes > 0x1000)
|
2670 |
|
|
bytes = 0x1000;
|
2671 |
|
|
else
|
2672 |
|
|
break;
|
2673 |
|
|
|
2674 |
|
|
continue;
|
2675 |
|
|
}
|
2676 |
|
|
|
2677 |
|
|
cached_fw[ii]->fw = mem;
|
2678 |
|
|
cached_fw[ii]->fw_dma = fw_dma;
|
2679 |
|
|
cached_fw[ii]->size = bytes;
|
2680 |
|
|
memset(mem, 0, bytes);
|
2681 |
|
|
alloc_total += bytes;
|
2682 |
|
|
|
2683 |
|
|
bytes_left -= bytes;
|
2684 |
|
|
|
2685 |
|
|
num_frags++;
|
2686 |
|
|
ii++;
|
2687 |
|
|
}
|
2688 |
|
|
|
2689 |
|
|
if (bytes_left ) {
|
2690 |
|
|
/* Major Failure.
|
2691 |
|
|
*/
|
2692 |
|
|
mpt_free_fw_memory(ioc, cached_fw);
|
2693 |
|
|
return NULL;
|
2694 |
|
|
}
|
2695 |
|
|
|
2696 |
|
|
*frags = num_frags;
|
2697 |
|
|
*alloc_sz = alloc_total;
|
2698 |
|
|
|
2699 |
|
|
return (void *) cached_fw;
|
2700 |
|
|
}
|
2701 |
|
|
|
2702 |
|
|
/*
|
2703 |
|
|
* If alt_img is NULL, delete from ioc structure.
|
2704 |
|
|
* Else, delete a secondary image in same format.
|
2705 |
|
|
*/
|
2706 |
|
|
void
|
2707 |
|
|
mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img)
|
2708 |
|
|
{
|
2709 |
|
|
fw_image_t **cached_fw;
|
2710 |
|
|
int ii;
|
2711 |
|
|
int sz;
|
2712 |
|
|
int alloc_freed = 0;
|
2713 |
|
|
|
2714 |
|
|
if (alt_img != NULL)
|
2715 |
|
|
cached_fw = alt_img;
|
2716 |
|
|
else
|
2717 |
|
|
cached_fw = ioc->cached_fw;
|
2718 |
|
|
|
2719 |
|
|
if (cached_fw == NULL)
|
2720 |
|
|
return;
|
2721 |
|
|
|
2722 |
|
|
ii = 0;
|
2723 |
|
|
while ((ii < ioc->num_fw_frags) && (cached_fw[ii]!= NULL)) {
|
2724 |
|
|
sz = cached_fw[ii]->size;
|
2725 |
|
|
if (sz > 0) {
|
2726 |
|
|
pci_free_consistent(ioc->pcidev, sz,
|
2727 |
|
|
cached_fw[ii]->fw, cached_fw[ii]->fw_dma);
|
2728 |
|
|
}
|
2729 |
|
|
cached_fw[ii]->fw = NULL;
|
2730 |
|
|
alloc_freed += sz;
|
2731 |
|
|
|
2732 |
|
|
kfree(cached_fw[ii]);
|
2733 |
|
|
cached_fw[ii] = NULL;
|
2734 |
|
|
alloc_freed += sizeof(fw_image_t);
|
2735 |
|
|
|
2736 |
|
|
ii++;
|
2737 |
|
|
}
|
2738 |
|
|
|
2739 |
|
|
kfree(cached_fw);
|
2740 |
|
|
cached_fw = NULL;
|
2741 |
|
|
sz = ioc->num_fw_frags * sizeof(void *);
|
2742 |
|
|
alloc_freed += sz;
|
2743 |
|
|
|
2744 |
|
|
if (alt_img == NULL)
|
2745 |
|
|
ioc->alloc_total -= alloc_freed;
|
2746 |
|
|
|
2747 |
|
|
return;
|
2748 |
|
|
}
|
2749 |
|
|
|
2750 |
|
|
|
2751 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2752 |
|
|
/*
|
2753 |
|
|
* mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
|
2754 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2755 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
2756 |
|
|
*
|
2757 |
|
|
* Returns 0 for success, >0 for handshake failure
|
2758 |
|
|
* <0 for fw upload failure.
|
2759 |
|
|
*
|
2760 |
|
|
* Remark: If bound IOC and a successful FWUpload was performed
|
2761 |
|
|
* on the bound IOC, the second image is discarded
|
2762 |
|
|
* and memory is free'd. Both channels must upload to prevent
|
2763 |
|
|
* IOC from running in degraded mode.
|
2764 |
|
|
*/
|
2765 |
|
|
static int
|
2766 |
|
|
mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
|
2767 |
|
|
{
|
2768 |
|
|
u8 request[ioc->req_sz];
|
2769 |
|
|
u8 reply[sizeof(FWUploadReply_t)];
|
2770 |
|
|
FWUpload_t *prequest;
|
2771 |
|
|
FWUploadReply_t *preply;
|
2772 |
|
|
FWUploadTCSGE_t *ptcsge;
|
2773 |
|
|
int sgeoffset;
|
2774 |
|
|
int ii, sz, reply_sz;
|
2775 |
|
|
int cmdStatus, freeMem = 0;
|
2776 |
|
|
int num_frags, alloc_sz;
|
2777 |
|
|
|
2778 |
|
|
/* If the image size is 0 or if the pointer is
|
2779 |
|
|
* not NULL (error), we are done.
|
2780 |
|
|
*/
|
2781 |
|
|
if (((sz = ioc->facts.FWImageSize) == 0) || ioc->cached_fw)
|
2782 |
|
|
return 0;
|
2783 |
|
|
|
2784 |
|
|
ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1;
|
2785 |
|
|
ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32);
|
2786 |
|
|
|
2787 |
|
|
ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc,
|
2788 |
|
|
ioc->facts.FWImageSize, &num_frags, &alloc_sz);
|
2789 |
|
|
|
2790 |
|
|
if (ioc->cached_fw == NULL) {
|
2791 |
|
|
/* Major Failure.
|
2792 |
|
|
*/
|
2793 |
|
|
mpt_free_fw_memory(ioc, NULL);
|
2794 |
|
|
ioc->cached_fw = NULL;
|
2795 |
|
|
|
2796 |
|
|
return -ENOMEM;
|
2797 |
|
|
}
|
2798 |
|
|
ioc->alloc_total += alloc_sz;
|
2799 |
|
|
|
2800 |
|
|
ddlprintk((KERN_INFO MYNAM ": FW Image @ %p, sz=%d bytes\n",
|
2801 |
|
|
(void *)(ulong)ioc->cached_fw, ioc->facts.FWImageSize));
|
2802 |
|
|
|
2803 |
|
|
prequest = (FWUpload_t *)&request;
|
2804 |
|
|
preply = (FWUploadReply_t *)&reply;
|
2805 |
|
|
|
2806 |
|
|
/* Destination... */
|
2807 |
|
|
memset(prequest, 0, ioc->req_sz);
|
2808 |
|
|
|
2809 |
|
|
reply_sz = sizeof(reply);
|
2810 |
|
|
memset(preply, 0, reply_sz);
|
2811 |
|
|
|
2812 |
|
|
prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
|
2813 |
|
|
prequest->Function = MPI_FUNCTION_FW_UPLOAD;
|
2814 |
|
|
prequest->MsgContext = 0; /* anything */
|
2815 |
|
|
|
2816 |
|
|
ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
|
2817 |
|
|
ptcsge->Reserved = 0;
|
2818 |
|
|
ptcsge->ContextSize = 0;
|
2819 |
|
|
ptcsge->DetailsLength = 12;
|
2820 |
|
|
ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
|
2821 |
|
|
ptcsge->Reserved1 = 0;
|
2822 |
|
|
ptcsge->ImageOffset = 0;
|
2823 |
|
|
ptcsge->ImageSize = cpu_to_le32(sz);
|
2824 |
|
|
|
2825 |
|
|
sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
|
2826 |
|
|
|
2827 |
|
|
for (ii = 0; ii < (num_frags-1); ii++) {
|
2828 |
|
|
mpt_add_sge(&request[sgeoffset], MPT_SGE_FLAGS_SIMPLE_ELEMENT |
|
2829 |
|
|
MPT_SGE_FLAGS_ADDRESSING | MPT_TRANSFER_IOC_TO_HOST |
|
2830 |
|
|
(u32) ioc->cached_fw[ii]->size, ioc->cached_fw[ii]->fw_dma);
|
2831 |
|
|
|
2832 |
|
|
sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
|
2833 |
|
|
}
|
2834 |
|
|
|
2835 |
|
|
mpt_add_sge(&request[sgeoffset],
|
2836 |
|
|
MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size,
|
2837 |
|
|
ioc->cached_fw[ii]->fw_dma);
|
2838 |
|
|
|
2839 |
|
|
sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
|
2840 |
|
|
|
2841 |
|
|
dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p) size %d \n",
|
2842 |
|
|
ioc->name, prequest, sgeoffset));
|
2843 |
|
|
|
2844 |
|
|
ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
|
2845 |
|
|
reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
|
2846 |
|
|
|
2847 |
|
|
cmdStatus = -EFAULT;
|
2848 |
|
|
if (ii == 0) {
|
2849 |
|
|
/* Handshake transfer was complete and successful.
|
2850 |
|
|
* Check the Reply Frame.
|
2851 |
|
|
*/
|
2852 |
|
|
int status, transfer_sz;
|
2853 |
|
|
status = le16_to_cpu(preply->IOCStatus);
|
2854 |
|
|
if (status == MPI_IOCSTATUS_SUCCESS) {
|
2855 |
|
|
transfer_sz = le32_to_cpu(preply->ActualImageSize);
|
2856 |
|
|
if (transfer_sz == sz)
|
2857 |
|
|
cmdStatus = 0;
|
2858 |
|
|
}
|
2859 |
|
|
}
|
2860 |
|
|
ddlprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
|
2861 |
|
|
ioc->name, cmdStatus));
|
2862 |
|
|
|
2863 |
|
|
/* Check to see if we have a copy of this image in
|
2864 |
|
|
* host memory already.
|
2865 |
|
|
*/
|
2866 |
|
|
if (cmdStatus == 0) {
|
2867 |
|
|
ioc->upload_fw = 0;
|
2868 |
|
|
if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
|
2869 |
|
|
freeMem = 1;
|
2870 |
|
|
}
|
2871 |
|
|
|
2872 |
|
|
/* We already have a copy of this image or
|
2873 |
|
|
* we had some type of an error - either the handshake
|
2874 |
|
|
* failed (i != 0) or the command did not complete successfully.
|
2875 |
|
|
*/
|
2876 |
|
|
if (cmdStatus || freeMem) {
|
2877 |
|
|
|
2878 |
|
|
ddlprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n",
|
2879 |
|
|
ioc->name, cmdStatus ? "incomplete" : "duplicate"));
|
2880 |
|
|
mpt_free_fw_memory(ioc, NULL);
|
2881 |
|
|
ioc->cached_fw = NULL;
|
2882 |
|
|
}
|
2883 |
|
|
|
2884 |
|
|
return cmdStatus;
|
2885 |
|
|
}
|
2886 |
|
|
|
2887 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2888 |
|
|
/*
|
2889 |
|
|
* mpt_downloadboot - DownloadBoot code
|
2890 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2891 |
|
|
* @flag: Specify which part of IOC memory is to be uploaded.
|
2892 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
2893 |
|
|
*
|
2894 |
|
|
* FwDownloadBoot requires Programmed IO access.
|
2895 |
|
|
*
|
2896 |
|
|
* Returns 0 for success
|
2897 |
|
|
* -1 FW Image size is 0
|
2898 |
|
|
* -2 No valid cached_fw Pointer
|
2899 |
|
|
* <0 for fw upload failure.
|
2900 |
|
|
*/
|
2901 |
|
|
static int
|
2902 |
|
|
mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
|
2903 |
|
|
{
|
2904 |
|
|
MpiFwHeader_t *FwHdr;
|
2905 |
|
|
MpiExtImageHeader_t *ExtHdr;
|
2906 |
|
|
fw_image_t **pCached;
|
2907 |
|
|
int fw_sz;
|
2908 |
|
|
u32 diag0val;
|
2909 |
|
|
#ifdef MPT_DEBUG
|
2910 |
|
|
u32 diag1val = 0;
|
2911 |
|
|
#endif
|
2912 |
|
|
int count = 0;
|
2913 |
|
|
u32 *ptru32;
|
2914 |
|
|
u32 diagRwData;
|
2915 |
|
|
u32 nextImage;
|
2916 |
|
|
u32 ext_offset;
|
2917 |
|
|
u32 load_addr;
|
2918 |
|
|
int max_idx, fw_idx, ext_idx;
|
2919 |
|
|
int left_u32s;
|
2920 |
|
|
|
2921 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n",
|
2922 |
|
|
ioc->name));
|
2923 |
|
|
#ifdef MPT_DEBUG
|
2924 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
2925 |
|
|
if (ioc->alt_ioc)
|
2926 |
|
|
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
|
2927 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n",
|
2928 |
|
|
ioc->name, diag0val, diag1val));
|
2929 |
|
|
#endif
|
2930 |
|
|
|
2931 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n",
|
2932 |
|
|
ioc->name, ioc->facts.FWImageSize, ioc->cached_fw));
|
2933 |
|
|
if (ioc->alt_ioc)
|
2934 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n",
|
2935 |
|
|
ioc->name, ioc->alt_ioc->cached_fw));
|
2936 |
|
|
|
2937 |
|
|
/* Get dma_addr and data transfer size.
|
2938 |
|
|
*/
|
2939 |
|
|
if ((fw_sz = ioc->facts.FWImageSize) == 0)
|
2940 |
|
|
return -1;
|
2941 |
|
|
|
2942 |
|
|
/* Get the DMA from ioc or ioc->alt_ioc */
|
2943 |
|
|
if (ioc->cached_fw != NULL)
|
2944 |
|
|
pCached = (fw_image_t **)ioc->cached_fw;
|
2945 |
|
|
else if (ioc->alt_ioc && (ioc->alt_ioc->cached_fw != NULL))
|
2946 |
|
|
pCached = (fw_image_t **)ioc->alt_ioc->cached_fw;
|
2947 |
|
|
|
2948 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n",
|
2949 |
|
|
ioc->name, pCached));
|
2950 |
|
|
if (!pCached)
|
2951 |
|
|
return -2;
|
2952 |
|
|
|
2953 |
|
|
/* Write magic sequence to WriteSequence register
|
2954 |
|
|
* until enter diagnostic mode
|
2955 |
|
|
*/
|
2956 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
2957 |
|
|
while ((diag0val & MPI_DIAG_DRWE) == 0) {
|
2958 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
|
2959 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
|
2960 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
|
2961 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
|
2962 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
|
2963 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
|
2964 |
|
|
|
2965 |
|
|
/* wait 100 msec */
|
2966 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
2967 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
2968 |
|
|
schedule_timeout(100 * HZ / 1000);
|
2969 |
|
|
} else {
|
2970 |
|
|
mdelay (100);
|
2971 |
|
|
}
|
2972 |
|
|
|
2973 |
|
|
count++;
|
2974 |
|
|
if (count > 20) {
|
2975 |
|
|
printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
|
2976 |
|
|
ioc->name, diag0val);
|
2977 |
|
|
return -EFAULT;
|
2978 |
|
|
|
2979 |
|
|
}
|
2980 |
|
|
|
2981 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
2982 |
|
|
#ifdef MPT_DEBUG
|
2983 |
|
|
if (ioc->alt_ioc)
|
2984 |
|
|
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
|
2985 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
|
2986 |
|
|
ioc->name, diag0val, diag1val));
|
2987 |
|
|
#endif
|
2988 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
|
2989 |
|
|
ioc->name, diag0val));
|
2990 |
|
|
}
|
2991 |
|
|
|
2992 |
|
|
/* Set the DiagRwEn and Disable ARM bits */
|
2993 |
|
|
diag0val |= (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM);
|
2994 |
|
|
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
|
2995 |
|
|
|
2996 |
|
|
#ifdef MPT_DEBUG
|
2997 |
|
|
if (ioc->alt_ioc)
|
2998 |
|
|
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
|
2999 |
|
|
|
3000 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
|
3001 |
|
|
ioc->name, diag0val, diag1val));
|
3002 |
|
|
#endif
|
3003 |
|
|
|
3004 |
|
|
/* max_idx = 1 + maximum valid buffer index
|
3005 |
|
|
*/
|
3006 |
|
|
max_idx = 0;
|
3007 |
|
|
while (pCached[max_idx])
|
3008 |
|
|
max_idx++;
|
3009 |
|
|
|
3010 |
|
|
fw_idx = 0;
|
3011 |
|
|
FwHdr = (MpiFwHeader_t *) pCached[fw_idx]->fw;
|
3012 |
|
|
ptru32 = (u32 *) FwHdr;
|
3013 |
|
|
count = (FwHdr->ImageSize + 3)/4;
|
3014 |
|
|
nextImage = FwHdr->NextImageHeaderOffset;
|
3015 |
|
|
|
3016 |
|
|
/* Write the LoadStartAddress to the DiagRw Address Register
|
3017 |
|
|
* using Programmed IO
|
3018 |
|
|
*/
|
3019 |
|
|
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->LoadStartAddress);
|
3020 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
|
3021 |
|
|
ioc->name, FwHdr->LoadStartAddress));
|
3022 |
|
|
|
3023 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n",
|
3024 |
|
|
ioc->name, count, ptru32));
|
3025 |
|
|
left_u32s = pCached[fw_idx]->size/4;
|
3026 |
|
|
while (count--) {
|
3027 |
|
|
if (left_u32s == 0) {
|
3028 |
|
|
fw_idx++;
|
3029 |
|
|
if (fw_idx >= max_idx) {
|
3030 |
|
|
/* FIXME
|
3031 |
|
|
ERROR CASE
|
3032 |
|
|
*/
|
3033 |
|
|
;
|
3034 |
|
|
}
|
3035 |
|
|
ptru32 = (u32 *) pCached[fw_idx]->fw;
|
3036 |
|
|
left_u32s = pCached[fw_idx]->size / 4;
|
3037 |
|
|
}
|
3038 |
|
|
left_u32s--;
|
3039 |
|
|
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
|
3040 |
|
|
ptru32++;
|
3041 |
|
|
}
|
3042 |
|
|
|
3043 |
|
|
/* left_u32s, fw_idx and ptru32 are all valid
|
3044 |
|
|
*/
|
3045 |
|
|
while (nextImage) {
|
3046 |
|
|
ext_idx = 0;
|
3047 |
|
|
ext_offset = nextImage;
|
3048 |
|
|
while (ext_offset > pCached[ext_idx]->size) {
|
3049 |
|
|
ext_idx++;
|
3050 |
|
|
if (ext_idx >= max_idx) {
|
3051 |
|
|
/* FIXME
|
3052 |
|
|
ERROR CASE
|
3053 |
|
|
*/
|
3054 |
|
|
;
|
3055 |
|
|
}
|
3056 |
|
|
ext_offset -= pCached[ext_idx]->size;
|
3057 |
|
|
}
|
3058 |
|
|
ptru32 = (u32 *) ((char *)pCached[ext_idx]->fw + ext_offset);
|
3059 |
|
|
left_u32s = pCached[ext_idx]->size - ext_offset;
|
3060 |
|
|
|
3061 |
|
|
if ((left_u32s * 4) >= sizeof(MpiExtImageHeader_t)) {
|
3062 |
|
|
ExtHdr = (MpiExtImageHeader_t *) ptru32;
|
3063 |
|
|
count = (ExtHdr->ImageSize + 3 )/4;
|
3064 |
|
|
nextImage = ExtHdr->NextImageHeaderOffset;
|
3065 |
|
|
load_addr = ExtHdr->LoadStartAddress;
|
3066 |
|
|
} else {
|
3067 |
|
|
u32 * ptmp = (u32 *)pCached[ext_idx+1]->fw;
|
3068 |
|
|
|
3069 |
|
|
switch (left_u32s) {
|
3070 |
|
|
case 5:
|
3071 |
|
|
count = *(ptru32 + 2);
|
3072 |
|
|
nextImage = *(ptru32 + 3);
|
3073 |
|
|
load_addr = *(ptru32 + 4);
|
3074 |
|
|
break;
|
3075 |
|
|
case 4:
|
3076 |
|
|
count = *(ptru32 + 2);
|
3077 |
|
|
nextImage = *(ptru32 + 3);
|
3078 |
|
|
load_addr = *ptmp;
|
3079 |
|
|
break;
|
3080 |
|
|
case 3:
|
3081 |
|
|
count = *(ptru32 + 2);
|
3082 |
|
|
nextImage = *ptmp;
|
3083 |
|
|
load_addr = *(ptmp + 1);
|
3084 |
|
|
break;
|
3085 |
|
|
case 2:
|
3086 |
|
|
count = *ptmp;
|
3087 |
|
|
nextImage = *(ptmp + 1);
|
3088 |
|
|
load_addr = *(ptmp + 2);
|
3089 |
|
|
break;
|
3090 |
|
|
|
3091 |
|
|
case 1:
|
3092 |
|
|
count = *(ptmp + 1);
|
3093 |
|
|
nextImage = *(ptmp + 2);
|
3094 |
|
|
load_addr = *(ptmp + 3);
|
3095 |
|
|
break;
|
3096 |
|
|
|
3097 |
|
|
default:
|
3098 |
|
|
count = 0;
|
3099 |
|
|
nextImage = 0;
|
3100 |
|
|
load_addr = 0;
|
3101 |
|
|
/* FIXME
|
3102 |
|
|
ERROR CASE
|
3103 |
|
|
*/
|
3104 |
|
|
;
|
3105 |
|
|
|
3106 |
|
|
}
|
3107 |
|
|
count = (count +3)/4;
|
3108 |
|
|
}
|
3109 |
|
|
|
3110 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n",
|
3111 |
|
|
ioc->name, count, ptru32));
|
3112 |
|
|
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
|
3113 |
|
|
|
3114 |
|
|
while (count--) {
|
3115 |
|
|
if (left_u32s == 0) {
|
3116 |
|
|
fw_idx++;
|
3117 |
|
|
if (fw_idx >= max_idx) {
|
3118 |
|
|
/* FIXME
|
3119 |
|
|
ERROR CASE
|
3120 |
|
|
*/
|
3121 |
|
|
;
|
3122 |
|
|
}
|
3123 |
|
|
ptru32 = (u32 *) pCached[fw_idx]->fw;
|
3124 |
|
|
left_u32s = pCached[fw_idx]->size / 4;
|
3125 |
|
|
}
|
3126 |
|
|
left_u32s--;
|
3127 |
|
|
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
|
3128 |
|
|
ptru32++;
|
3129 |
|
|
}
|
3130 |
|
|
}
|
3131 |
|
|
|
3132 |
|
|
/* Write the IopResetVectorRegAddr */
|
3133 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name));
|
3134 |
|
|
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->IopResetRegAddr);
|
3135 |
|
|
|
3136 |
|
|
/* Write the IopResetVectorValue */
|
3137 |
|
|
ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name));
|
3138 |
|
|
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, FwHdr->IopResetVectorValue);
|
3139 |
|
|
|
3140 |
|
|
/* Clear the internal flash bad bit - autoincrementing register,
|
3141 |
|
|
* so must do two writes.
|
3142 |
|
|
*/
|
3143 |
|
|
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
|
3144 |
|
|
diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
|
3145 |
|
|
diagRwData |= 0x4000000;
|
3146 |
|
|
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
|
3147 |
|
|
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
|
3148 |
|
|
|
3149 |
|
|
/* clear the RW enable and DISARM bits */
|
3150 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
3151 |
|
|
diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_FLASH_BAD_SIG);
|
3152 |
|
|
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
|
3153 |
|
|
|
3154 |
|
|
/* Write 0xFF to reset the sequencer */
|
3155 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
|
3156 |
|
|
|
3157 |
|
|
return 0;
|
3158 |
|
|
}
|
3159 |
|
|
|
3160 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3161 |
|
|
/*
|
3162 |
|
|
* KickStart - Perform hard reset of MPT adapter.
|
3163 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
3164 |
|
|
* @force: Force hard reset
|
3165 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
3166 |
|
|
*
|
3167 |
|
|
* This routine places MPT adapter in diagnostic mode via the
|
3168 |
|
|
* WriteSequence register, and then performs a hard reset of adapter
|
3169 |
|
|
* via the Diagnostic register.
|
3170 |
|
|
*
|
3171 |
|
|
* Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
|
3172 |
|
|
* or NO_SLEEP (interrupt thread, use mdelay)
|
3173 |
|
|
* force - 1 if doorbell active, board fault state
|
3174 |
|
|
* board operational, IOC_RECOVERY or
|
3175 |
|
|
* IOC_BRINGUP and there is an alt_ioc.
|
3176 |
|
|
* 0 else
|
3177 |
|
|
*
|
3178 |
|
|
* Returns:
|
3179 |
|
|
* 1 - hard reset, READY
|
3180 |
|
|
* 0 - no reset due to History bit, READY
|
3181 |
|
|
* -1 - no reset due to History bit but not READY
|
3182 |
|
|
* OR reset but failed to come READY
|
3183 |
|
|
* -2 - no reset, could not enter DIAG mode
|
3184 |
|
|
* -3 - reset but bad FW bit
|
3185 |
|
|
*/
|
3186 |
|
|
static int
|
3187 |
|
|
KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
|
3188 |
|
|
{
|
3189 |
|
|
int hard_reset_done = 0;
|
3190 |
|
|
u32 ioc_state;
|
3191 |
|
|
int cnt = 0;
|
3192 |
|
|
|
3193 |
|
|
dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
|
3194 |
|
|
if ((int)ioc->chip_type > (int)FC929) {
|
3195 |
|
|
/* Always issue a Msg Unit Reset first. This will clear some
|
3196 |
|
|
* SCSI bus hang conditions.
|
3197 |
|
|
*/
|
3198 |
|
|
SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
|
3199 |
|
|
|
3200 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
3201 |
|
|
schedule_timeout(HZ);
|
3202 |
|
|
} else {
|
3203 |
|
|
mdelay (1000);
|
3204 |
|
|
}
|
3205 |
|
|
}
|
3206 |
|
|
|
3207 |
|
|
hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
|
3208 |
|
|
if (hard_reset_done < 0)
|
3209 |
|
|
return hard_reset_done;
|
3210 |
|
|
|
3211 |
|
|
dprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
|
3212 |
|
|
ioc->name));
|
3213 |
|
|
|
3214 |
|
|
for (cnt=0; cnt<HZ*20; cnt++) {
|
3215 |
|
|
if ((ioc_state = mpt_GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
|
3216 |
|
|
dprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
|
3217 |
|
|
ioc->name, cnt));
|
3218 |
|
|
return hard_reset_done;
|
3219 |
|
|
}
|
3220 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
3221 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
3222 |
|
|
schedule_timeout(1);
|
3223 |
|
|
} else {
|
3224 |
|
|
mdelay (10);
|
3225 |
|
|
}
|
3226 |
|
|
}
|
3227 |
|
|
|
3228 |
|
|
printk(MYIOC_s_ERR_FMT "Failed to come READY after reset!\n",
|
3229 |
|
|
ioc->name);
|
3230 |
|
|
return -1;
|
3231 |
|
|
}
|
3232 |
|
|
|
3233 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3234 |
|
|
/*
|
3235 |
|
|
* mpt_diag_reset - Perform hard reset of the adapter.
|
3236 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
3237 |
|
|
* @ignore: Set if to honor and clear to ignore
|
3238 |
|
|
* the reset history bit
|
3239 |
|
|
* @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
|
3240 |
|
|
* else set to NO_SLEEP (use mdelay instead)
|
3241 |
|
|
*
|
3242 |
|
|
* This routine places the adapter in diagnostic mode via the
|
3243 |
|
|
* WriteSequence register and then performs a hard reset of adapter
|
3244 |
|
|
* via the Diagnostic register. Adapter should be in ready state
|
3245 |
|
|
* upon successful completion.
|
3246 |
|
|
*
|
3247 |
|
|
* Returns: 1 hard reset successful
|
3248 |
|
|
* 0 no reset performed because reset history bit set
|
3249 |
|
|
* -2 enabling diagnostic mode failed
|
3250 |
|
|
* -3 diagnostic reset failed
|
3251 |
|
|
*/
|
3252 |
|
|
static int
|
3253 |
|
|
mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
|
3254 |
|
|
{
|
3255 |
|
|
u32 diag0val;
|
3256 |
|
|
u32 doorbell;
|
3257 |
|
|
int hard_reset_done = 0;
|
3258 |
|
|
int count = 0;
|
3259 |
|
|
#ifdef MPT_DEBUG
|
3260 |
|
|
u32 diag1val = 0;
|
3261 |
|
|
#endif
|
3262 |
|
|
|
3263 |
|
|
/* Clear any existing interrupts */
|
3264 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
|
3265 |
|
|
|
3266 |
|
|
/* Use "Diagnostic reset" method! (only thing available!) */
|
3267 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
3268 |
|
|
|
3269 |
|
|
#ifdef MPT_DEBUG
|
3270 |
|
|
if (ioc->alt_ioc)
|
3271 |
|
|
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
|
3272 |
|
|
dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
|
3273 |
|
|
ioc->name, diag0val, diag1val));
|
3274 |
|
|
#endif
|
3275 |
|
|
|
3276 |
|
|
/* Do the reset if we are told to ignore the reset history
|
3277 |
|
|
* or if the reset history is 0
|
3278 |
|
|
*/
|
3279 |
|
|
if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
|
3280 |
|
|
while ((diag0val & MPI_DIAG_DRWE) == 0) {
|
3281 |
|
|
/* Write magic sequence to WriteSequence register
|
3282 |
|
|
* Loop until in diagnostic mode
|
3283 |
|
|
*/
|
3284 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
|
3285 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
|
3286 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
|
3287 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
|
3288 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
|
3289 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
|
3290 |
|
|
|
3291 |
|
|
/* wait 100 msec */
|
3292 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
3293 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
3294 |
|
|
schedule_timeout(100 * HZ / 1000);
|
3295 |
|
|
} else {
|
3296 |
|
|
mdelay (100);
|
3297 |
|
|
}
|
3298 |
|
|
|
3299 |
|
|
count++;
|
3300 |
|
|
if (count > 20) {
|
3301 |
|
|
printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
|
3302 |
|
|
ioc->name, diag0val);
|
3303 |
|
|
return -2;
|
3304 |
|
|
|
3305 |
|
|
}
|
3306 |
|
|
|
3307 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
3308 |
|
|
|
3309 |
|
|
dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
|
3310 |
|
|
ioc->name, diag0val));
|
3311 |
|
|
}
|
3312 |
|
|
|
3313 |
|
|
#ifdef MPT_DEBUG
|
3314 |
|
|
if (ioc->alt_ioc)
|
3315 |
|
|
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
|
3316 |
|
|
dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
|
3317 |
|
|
ioc->name, diag0val, diag1val));
|
3318 |
|
|
#endif
|
3319 |
|
|
/* Write the PreventIocBoot bit */
|
3320 |
|
|
if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
|
3321 |
|
|
diag0val |= MPI_DIAG_PREVENT_IOC_BOOT;
|
3322 |
|
|
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
|
3323 |
|
|
}
|
3324 |
|
|
|
3325 |
|
|
/*
|
3326 |
|
|
* Disable the ARM (Bug fix)
|
3327 |
|
|
*
|
3328 |
|
|
*/
|
3329 |
|
|
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
|
3330 |
|
|
mdelay (1);
|
3331 |
|
|
|
3332 |
|
|
/*
|
3333 |
|
|
* Now hit the reset bit in the Diagnostic register
|
3334 |
|
|
* (THE BIG HAMMER!) (Clears DRWE bit).
|
3335 |
|
|
*/
|
3336 |
|
|
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
|
3337 |
|
|
hard_reset_done = 1;
|
3338 |
|
|
dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
|
3339 |
|
|
ioc->name));
|
3340 |
|
|
|
3341 |
|
|
/*
|
3342 |
|
|
* Call each currently registered protocol IOC reset handler
|
3343 |
|
|
* with pre-reset indication.
|
3344 |
|
|
* NOTE: If we're doing _IOC_BRINGUP, there can be no
|
3345 |
|
|
* MptResetHandlers[] registered yet.
|
3346 |
|
|
*/
|
3347 |
|
|
{
|
3348 |
|
|
int ii;
|
3349 |
|
|
int r = 0;
|
3350 |
|
|
|
3351 |
|
|
for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
|
3352 |
|
|
if (MptResetHandlers[ii]) {
|
3353 |
|
|
dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
|
3354 |
|
|
ioc->name, ii));
|
3355 |
|
|
r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
|
3356 |
|
|
if (ioc->alt_ioc) {
|
3357 |
|
|
dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
|
3358 |
|
|
ioc->name, ioc->alt_ioc->name, ii));
|
3359 |
|
|
r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
|
3360 |
|
|
}
|
3361 |
|
|
}
|
3362 |
|
|
}
|
3363 |
|
|
/* FIXME? Examine results here? */
|
3364 |
|
|
}
|
3365 |
|
|
|
3366 |
|
|
if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
|
3367 |
|
|
/* If the DownloadBoot operation fails, the
|
3368 |
|
|
* IOC will be left unusable. This is a fatal error
|
3369 |
|
|
* case. _diag_reset will return < 0
|
3370 |
|
|
*/
|
3371 |
|
|
for (count = 0; count < 30; count ++) {
|
3372 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
3373 |
|
|
#ifdef MPT_DEBUG
|
3374 |
|
|
if (ioc->alt_ioc)
|
3375 |
|
|
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
|
3376 |
|
|
dprintk((MYIOC_s_INFO_FMT
|
3377 |
|
|
"DbG2b: diag0=%08x, diag1=%08x\n",
|
3378 |
|
|
ioc->name, diag0val, diag1val));
|
3379 |
|
|
#endif
|
3380 |
|
|
if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
|
3381 |
|
|
break;
|
3382 |
|
|
}
|
3383 |
|
|
|
3384 |
|
|
/* wait 1 sec */
|
3385 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
3386 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
3387 |
|
|
schedule_timeout(HZ);
|
3388 |
|
|
} else {
|
3389 |
|
|
mdelay (1000);
|
3390 |
|
|
}
|
3391 |
|
|
}
|
3392 |
|
|
if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
|
3393 |
|
|
printk(KERN_WARNING MYNAM
|
3394 |
|
|
": firmware downloadboot failure (%d)!\n", count);
|
3395 |
|
|
}
|
3396 |
|
|
|
3397 |
|
|
} else {
|
3398 |
|
|
/* Wait for FW to reload and for board
|
3399 |
|
|
* to go to the READY state.
|
3400 |
|
|
* Maximum wait is 60 seconds.
|
3401 |
|
|
* If fail, no error will check again
|
3402 |
|
|
* with calling program.
|
3403 |
|
|
*/
|
3404 |
|
|
for (count = 0; count < 60; count ++) {
|
3405 |
|
|
doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
|
3406 |
|
|
doorbell &= MPI_IOC_STATE_MASK;
|
3407 |
|
|
|
3408 |
|
|
if (doorbell == MPI_IOC_STATE_READY) {
|
3409 |
|
|
break;
|
3410 |
|
|
}
|
3411 |
|
|
|
3412 |
|
|
/* wait 1 sec */
|
3413 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
3414 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
3415 |
|
|
schedule_timeout(HZ);
|
3416 |
|
|
} else {
|
3417 |
|
|
mdelay (1000);
|
3418 |
|
|
}
|
3419 |
|
|
}
|
3420 |
|
|
}
|
3421 |
|
|
}
|
3422 |
|
|
|
3423 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
3424 |
|
|
#ifdef MPT_DEBUG
|
3425 |
|
|
if (ioc->alt_ioc)
|
3426 |
|
|
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
|
3427 |
|
|
dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
|
3428 |
|
|
ioc->name, diag0val, diag1val));
|
3429 |
|
|
#endif
|
3430 |
|
|
|
3431 |
|
|
/* Clear RESET_HISTORY bit! Place board in the
|
3432 |
|
|
* diagnostic mode to update the diag register.
|
3433 |
|
|
*/
|
3434 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
3435 |
|
|
count = 0;
|
3436 |
|
|
while ((diag0val & MPI_DIAG_DRWE) == 0) {
|
3437 |
|
|
/* Write magic sequence to WriteSequence register
|
3438 |
|
|
* Loop until in diagnostic mode
|
3439 |
|
|
*/
|
3440 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
|
3441 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
|
3442 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
|
3443 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
|
3444 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
|
3445 |
|
|
|
3446 |
|
|
/* wait 100 msec */
|
3447 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
3448 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
3449 |
|
|
schedule_timeout(100 * HZ / 1000);
|
3450 |
|
|
} else {
|
3451 |
|
|
mdelay (100);
|
3452 |
|
|
}
|
3453 |
|
|
|
3454 |
|
|
count++;
|
3455 |
|
|
if (count > 20) {
|
3456 |
|
|
printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
|
3457 |
|
|
ioc->name, diag0val);
|
3458 |
|
|
break;
|
3459 |
|
|
}
|
3460 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
3461 |
|
|
}
|
3462 |
|
|
diag0val &= ~MPI_DIAG_RESET_HISTORY;
|
3463 |
|
|
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
|
3464 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
3465 |
|
|
if (diag0val & MPI_DIAG_RESET_HISTORY) {
|
3466 |
|
|
printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
|
3467 |
|
|
ioc->name);
|
3468 |
|
|
}
|
3469 |
|
|
|
3470 |
|
|
/* Disable Diagnostic Mode
|
3471 |
|
|
*/
|
3472 |
|
|
CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
|
3473 |
|
|
|
3474 |
|
|
/* Check FW reload status flags.
|
3475 |
|
|
*/
|
3476 |
|
|
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
|
3477 |
|
|
if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
|
3478 |
|
|
printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
|
3479 |
|
|
ioc->name, diag0val);
|
3480 |
|
|
return -3;
|
3481 |
|
|
}
|
3482 |
|
|
|
3483 |
|
|
#ifdef MPT_DEBUG
|
3484 |
|
|
if (ioc->alt_ioc)
|
3485 |
|
|
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
|
3486 |
|
|
dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
|
3487 |
|
|
ioc->name, diag0val, diag1val));
|
3488 |
|
|
#endif
|
3489 |
|
|
|
3490 |
|
|
/*
|
3491 |
|
|
* Reset flag that says we've enabled event notification
|
3492 |
|
|
*/
|
3493 |
|
|
ioc->facts.EventState = 0;
|
3494 |
|
|
|
3495 |
|
|
if (ioc->alt_ioc)
|
3496 |
|
|
ioc->alt_ioc->facts.EventState = 0;
|
3497 |
|
|
|
3498 |
|
|
return hard_reset_done;
|
3499 |
|
|
}
|
3500 |
|
|
|
3501 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3502 |
|
|
/*
|
3503 |
|
|
* SendIocReset - Send IOCReset request to MPT adapter.
|
3504 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
3505 |
|
|
* @reset_type: reset type, expected values are
|
3506 |
|
|
* %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
|
3507 |
|
|
*
|
3508 |
|
|
* Send IOCReset request to the MPT adapter.
|
3509 |
|
|
*
|
3510 |
|
|
* Returns 0 for success, non-zero for failure.
|
3511 |
|
|
*/
|
3512 |
|
|
static int
|
3513 |
|
|
SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
|
3514 |
|
|
{
|
3515 |
|
|
int r;
|
3516 |
|
|
u32 state;
|
3517 |
|
|
int cntdn, count;
|
3518 |
|
|
|
3519 |
|
|
dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
|
3520 |
|
|
ioc->name, reset_type));
|
3521 |
|
|
CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
|
3522 |
|
|
if ((r = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0)
|
3523 |
|
|
return r;
|
3524 |
|
|
|
3525 |
|
|
/* FW ACK'd request, wait for READY state
|
3526 |
|
|
*/
|
3527 |
|
|
count = 0;
|
3528 |
|
|
cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
|
3529 |
|
|
|
3530 |
|
|
while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
|
3531 |
|
|
cntdn--;
|
3532 |
|
|
count++;
|
3533 |
|
|
if (!cntdn) {
|
3534 |
|
|
if (sleepFlag != CAN_SLEEP)
|
3535 |
|
|
count *= 10;
|
3536 |
|
|
|
3537 |
|
|
printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
|
3538 |
|
|
ioc->name, (count+5)/HZ);
|
3539 |
|
|
return -ETIME;
|
3540 |
|
|
}
|
3541 |
|
|
|
3542 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
3543 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
3544 |
|
|
schedule_timeout(1);
|
3545 |
|
|
} else {
|
3546 |
|
|
mdelay (1); /* 1 msec delay */
|
3547 |
|
|
}
|
3548 |
|
|
}
|
3549 |
|
|
|
3550 |
|
|
/* TODO!
|
3551 |
|
|
* Cleanup all event stuff for this IOC; re-issue EventNotification
|
3552 |
|
|
* request if needed.
|
3553 |
|
|
*/
|
3554 |
|
|
if (ioc->facts.Function)
|
3555 |
|
|
ioc->facts.EventState = 0;
|
3556 |
|
|
|
3557 |
|
|
return 0;
|
3558 |
|
|
}
|
3559 |
|
|
|
3560 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3561 |
|
|
/*
|
3562 |
|
|
* PrimeIocFifos - Initialize IOC request and reply FIFOs.
|
3563 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
3564 |
|
|
*
|
3565 |
|
|
* This routine allocates memory for the MPT reply and request frame
|
3566 |
|
|
* pools (if necessary), and primes the IOC reply FIFO with
|
3567 |
|
|
* reply frames.
|
3568 |
|
|
*
|
3569 |
|
|
* Returns 0 for success, non-zero for failure.
|
3570 |
|
|
*/
|
3571 |
|
|
static int
|
3572 |
|
|
PrimeIocFifos(MPT_ADAPTER *ioc)
|
3573 |
|
|
{
|
3574 |
|
|
MPT_FRAME_HDR *mf;
|
3575 |
|
|
unsigned long b;
|
3576 |
|
|
unsigned long flags;
|
3577 |
|
|
dma_addr_t aligned_mem_dma;
|
3578 |
|
|
u8 *mem, *aligned_mem;
|
3579 |
|
|
int i, sz;
|
3580 |
|
|
|
3581 |
|
|
/* Prime reply FIFO... */
|
3582 |
|
|
|
3583 |
|
|
if (ioc->reply_frames == NULL) {
|
3584 |
|
|
sz = (ioc->reply_sz * ioc->reply_depth) + 128;
|
3585 |
|
|
mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma);
|
3586 |
|
|
if (mem == NULL)
|
3587 |
|
|
goto out_fail;
|
3588 |
|
|
|
3589 |
|
|
memset(mem, 0, sz);
|
3590 |
|
|
ioc->alloc_total += sz;
|
3591 |
|
|
ioc->reply_alloc = mem;
|
3592 |
|
|
dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%p], sz=%d bytes\n",
|
3593 |
|
|
ioc->name, mem, (void *)(ulong)ioc->reply_alloc_dma, sz));
|
3594 |
|
|
|
3595 |
|
|
b = (unsigned long) mem;
|
3596 |
|
|
b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
|
3597 |
|
|
aligned_mem = (u8 *) b;
|
3598 |
|
|
ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem;
|
3599 |
|
|
ioc->reply_frames_dma =
|
3600 |
|
|
(ioc->reply_alloc_dma + (aligned_mem - mem));
|
3601 |
|
|
|
3602 |
|
|
ioc->reply_frames_low_dma = (u32) (ioc->reply_frames_dma & 0xFFFFFFFF);
|
3603 |
|
|
}
|
3604 |
|
|
|
3605 |
|
|
/* Post Reply frames to FIFO
|
3606 |
|
|
*/
|
3607 |
|
|
aligned_mem_dma = ioc->reply_frames_dma;
|
3608 |
|
|
dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%p]\n",
|
3609 |
|
|
ioc->name, ioc->reply_frames, (void *)(ulong)aligned_mem_dma));
|
3610 |
|
|
|
3611 |
|
|
for (i = 0; i < ioc->reply_depth; i++) {
|
3612 |
|
|
/* Write each address to the IOC! */
|
3613 |
|
|
CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma);
|
3614 |
|
|
aligned_mem_dma += ioc->reply_sz;
|
3615 |
|
|
}
|
3616 |
|
|
|
3617 |
|
|
|
3618 |
|
|
/* Request FIFO - WE manage this! */
|
3619 |
|
|
|
3620 |
|
|
if (ioc->req_frames == NULL) {
|
3621 |
|
|
sz = (ioc->req_sz * ioc->req_depth) + 128;
|
3622 |
|
|
/*
|
3623 |
|
|
* Rounding UP to nearest 4-kB boundary here...
|
3624 |
|
|
*/
|
3625 |
|
|
sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
|
3626 |
|
|
|
3627 |
|
|
mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma);
|
3628 |
|
|
if (mem == NULL)
|
3629 |
|
|
goto out_fail;
|
3630 |
|
|
|
3631 |
|
|
memset(mem, 0, sz);
|
3632 |
|
|
ioc->alloc_total += sz;
|
3633 |
|
|
ioc->req_alloc = mem;
|
3634 |
|
|
dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%p], sz=%d bytes\n",
|
3635 |
|
|
ioc->name, mem, (void *)(ulong)ioc->req_alloc_dma, sz));
|
3636 |
|
|
|
3637 |
|
|
b = (unsigned long) mem;
|
3638 |
|
|
b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
|
3639 |
|
|
aligned_mem = (u8 *) b;
|
3640 |
|
|
ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem;
|
3641 |
|
|
ioc->req_frames_dma =
|
3642 |
|
|
(ioc->req_alloc_dma + (aligned_mem - mem));
|
3643 |
|
|
|
3644 |
|
|
ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF);
|
3645 |
|
|
|
3646 |
|
|
if (sizeof(dma_addr_t) == sizeof(u64)) {
|
3647 |
|
|
/* Check: upper 32-bits of the request and reply frame
|
3648 |
|
|
* physical addresses must be the same.
|
3649 |
|
|
*/
|
3650 |
|
|
if (((u64)ioc->req_frames_dma >> 32) != ((u64)ioc->reply_frames_dma >> 32)){
|
3651 |
|
|
goto out_fail;
|
3652 |
|
|
}
|
3653 |
|
|
}
|
3654 |
|
|
|
3655 |
|
|
#if defined(CONFIG_MTRR) && 0
|
3656 |
|
|
/*
|
3657 |
|
|
* Enable Write Combining MTRR for IOC's memory region.
|
3658 |
|
|
* (at least as much as we can; "size and base must be
|
3659 |
|
|
* multiples of 4 kiB"
|
3660 |
|
|
*/
|
3661 |
|
|
ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma,
|
3662 |
|
|
sz,
|
3663 |
|
|
MTRR_TYPE_WRCOMB, 1);
|
3664 |
|
|
dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
|
3665 |
|
|
ioc->name, ioc->req_alloc_dma, sz));
|
3666 |
|
|
#endif
|
3667 |
|
|
}
|
3668 |
|
|
|
3669 |
|
|
/* Initialize Request frames linked list
|
3670 |
|
|
*/
|
3671 |
|
|
aligned_mem_dma = ioc->req_frames_dma;
|
3672 |
|
|
aligned_mem = (u8 *) ioc->req_frames;
|
3673 |
|
|
dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%p]\n",
|
3674 |
|
|
ioc->name, aligned_mem, (void *)(ulong)aligned_mem_dma));
|
3675 |
|
|
|
3676 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
3677 |
|
|
Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
|
3678 |
|
|
for (i = 0; i < ioc->req_depth; i++) {
|
3679 |
|
|
mf = (MPT_FRAME_HDR *) aligned_mem;
|
3680 |
|
|
|
3681 |
|
|
/* Queue REQUESTs *internally*! */
|
3682 |
|
|
Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
|
3683 |
|
|
aligned_mem += ioc->req_sz;
|
3684 |
|
|
}
|
3685 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
3686 |
|
|
|
3687 |
|
|
|
3688 |
|
|
if (ioc->sense_buf_pool == NULL) {
|
3689 |
|
|
sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
|
3690 |
|
|
ioc->sense_buf_pool =
|
3691 |
|
|
pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
|
3692 |
|
|
if (ioc->sense_buf_pool == NULL)
|
3693 |
|
|
goto out_fail;
|
3694 |
|
|
|
3695 |
|
|
ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
|
3696 |
|
|
ioc->alloc_total += sz;
|
3697 |
|
|
}
|
3698 |
|
|
|
3699 |
|
|
return 0;
|
3700 |
|
|
|
3701 |
|
|
out_fail:
|
3702 |
|
|
if (ioc->reply_alloc != NULL) {
|
3703 |
|
|
sz = (ioc->reply_sz * ioc->reply_depth) + 128;
|
3704 |
|
|
pci_free_consistent(ioc->pcidev,
|
3705 |
|
|
sz,
|
3706 |
|
|
ioc->reply_alloc, ioc->reply_alloc_dma);
|
3707 |
|
|
ioc->reply_frames = NULL;
|
3708 |
|
|
ioc->reply_alloc = NULL;
|
3709 |
|
|
ioc->alloc_total -= sz;
|
3710 |
|
|
}
|
3711 |
|
|
if (ioc->req_alloc != NULL) {
|
3712 |
|
|
sz = (ioc->req_sz * ioc->req_depth) + 128;
|
3713 |
|
|
/*
|
3714 |
|
|
* Rounding UP to nearest 4-kB boundary here...
|
3715 |
|
|
*/
|
3716 |
|
|
sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
|
3717 |
|
|
pci_free_consistent(ioc->pcidev,
|
3718 |
|
|
sz,
|
3719 |
|
|
ioc->req_alloc, ioc->req_alloc_dma);
|
3720 |
|
|
#if defined(CONFIG_MTRR) && 0
|
3721 |
|
|
if (ioc->mtrr_reg > 0) {
|
3722 |
|
|
mtrr_del(ioc->mtrr_reg, 0, 0);
|
3723 |
|
|
dprintk((MYIOC_s_INFO_FMT "MTRR region de-registered\n",
|
3724 |
|
|
ioc->name));
|
3725 |
|
|
}
|
3726 |
|
|
#endif
|
3727 |
|
|
ioc->req_frames = NULL;
|
3728 |
|
|
ioc->req_alloc = NULL;
|
3729 |
|
|
ioc->alloc_total -= sz;
|
3730 |
|
|
}
|
3731 |
|
|
if (ioc->sense_buf_pool != NULL) {
|
3732 |
|
|
sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
|
3733 |
|
|
pci_free_consistent(ioc->pcidev,
|
3734 |
|
|
sz,
|
3735 |
|
|
ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
|
3736 |
|
|
ioc->sense_buf_pool = NULL;
|
3737 |
|
|
}
|
3738 |
|
|
return -1;
|
3739 |
|
|
}
|
3740 |
|
|
|
3741 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3742 |
|
|
/**
|
3743 |
|
|
* mpt_handshake_req_reply_wait - Send MPT request to and receive reply from
|
3744 |
|
|
* IOC via doorbell handshake method.
|
3745 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
3746 |
|
|
* @reqBytes: Size of the request in bytes
|
3747 |
|
|
* @req: Pointer to MPT request frame
|
3748 |
|
|
* @replyBytes: Expected size of the reply in bytes
|
3749 |
|
|
* @u16reply: Pointer to area where reply should be written
|
3750 |
|
|
* @maxwait: Max wait time for a reply (in seconds)
|
3751 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
3752 |
|
|
*
|
3753 |
|
|
* NOTES: It is the callers responsibility to byte-swap fields in the
|
3754 |
|
|
* request which are greater than 1 byte in size. It is also the
|
3755 |
|
|
* callers responsibility to byte-swap response fields which are
|
3756 |
|
|
* greater than 1 byte in size.
|
3757 |
|
|
*
|
3758 |
|
|
* Returns 0 for success, non-zero for failure.
|
3759 |
|
|
*/
|
3760 |
|
|
int
|
3761 |
|
|
mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
|
3762 |
|
|
int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
|
3763 |
|
|
{
|
3764 |
|
|
MPIDefaultReply_t *mptReply;
|
3765 |
|
|
int failcnt = 0;
|
3766 |
|
|
int t;
|
3767 |
|
|
|
3768 |
|
|
/*
|
3769 |
|
|
* Get ready to cache a handshake reply
|
3770 |
|
|
*/
|
3771 |
|
|
ioc->hs_reply_idx = 0;
|
3772 |
|
|
mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
|
3773 |
|
|
mptReply->MsgLength = 0;
|
3774 |
|
|
|
3775 |
|
|
/*
|
3776 |
|
|
* Make sure there are no doorbells (WRITE 0 to IntStatus reg),
|
3777 |
|
|
* then tell IOC that we want to handshake a request of N words.
|
3778 |
|
|
* (WRITE u32val to Doorbell reg).
|
3779 |
|
|
*/
|
3780 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
|
3781 |
|
|
CHIPREG_WRITE32(&ioc->chip->Doorbell,
|
3782 |
|
|
((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
|
3783 |
|
|
((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
|
3784 |
|
|
|
3785 |
|
|
/*
|
3786 |
|
|
* Wait for IOC's doorbell handshake int
|
3787 |
|
|
*/
|
3788 |
|
|
if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
|
3789 |
|
|
failcnt++;
|
3790 |
|
|
|
3791 |
|
|
dhsprintk((MYIOC_s_INFO_FMT "HandShake request start, WaitCnt=%d%s\n",
|
3792 |
|
|
ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
|
3793 |
|
|
|
3794 |
|
|
/* Read doorbell and check for active bit */
|
3795 |
|
|
if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
|
3796 |
|
|
return -1;
|
3797 |
|
|
|
3798 |
|
|
/*
|
3799 |
|
|
* Clear doorbell int (WRITE 0 to IntStatus reg),
|
3800 |
|
|
* then wait for IOC to ACKnowledge that it's ready for
|
3801 |
|
|
* our handshake request.
|
3802 |
|
|
*/
|
3803 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
|
3804 |
|
|
if (!failcnt && (t = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0)
|
3805 |
|
|
failcnt++;
|
3806 |
|
|
|
3807 |
|
|
if (!failcnt) {
|
3808 |
|
|
int ii;
|
3809 |
|
|
u8 *req_as_bytes = (u8 *) req;
|
3810 |
|
|
|
3811 |
|
|
/*
|
3812 |
|
|
* Stuff request words via doorbell handshake,
|
3813 |
|
|
* with ACK from IOC for each.
|
3814 |
|
|
*/
|
3815 |
|
|
for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
|
3816 |
|
|
u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
|
3817 |
|
|
(req_as_bytes[(ii*4) + 1] << 8) |
|
3818 |
|
|
(req_as_bytes[(ii*4) + 2] << 16) |
|
3819 |
|
|
(req_as_bytes[(ii*4) + 3] << 24));
|
3820 |
|
|
|
3821 |
|
|
CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
|
3822 |
|
|
if ((t = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0)
|
3823 |
|
|
failcnt++;
|
3824 |
|
|
}
|
3825 |
|
|
|
3826 |
|
|
dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
|
3827 |
|
|
DBG_DUMP_REQUEST_FRAME_HDR(req)
|
3828 |
|
|
|
3829 |
|
|
dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
|
3830 |
|
|
ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
|
3831 |
|
|
|
3832 |
|
|
/*
|
3833 |
|
|
* Wait for completion of doorbell handshake reply from the IOC
|
3834 |
|
|
*/
|
3835 |
|
|
if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
|
3836 |
|
|
failcnt++;
|
3837 |
|
|
|
3838 |
|
|
/*
|
3839 |
|
|
* Copy out the cached reply...
|
3840 |
|
|
*/
|
3841 |
|
|
for (ii=0; ii < MIN(replyBytes/2,mptReply->MsgLength*2); ii++)
|
3842 |
|
|
u16reply[ii] = ioc->hs_reply[ii];
|
3843 |
|
|
} else {
|
3844 |
|
|
return -99;
|
3845 |
|
|
}
|
3846 |
|
|
|
3847 |
|
|
return -failcnt;
|
3848 |
|
|
}
|
3849 |
|
|
|
3850 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3851 |
|
|
/*
|
3852 |
|
|
* WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
|
3853 |
|
|
* in it's IntStatus register.
|
3854 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
3855 |
|
|
* @howlong: How long to wait (in seconds)
|
3856 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
3857 |
|
|
*
|
3858 |
|
|
* This routine waits (up to ~2 seconds max) for IOC doorbell
|
3859 |
|
|
* handshake ACKnowledge.
|
3860 |
|
|
*
|
3861 |
|
|
* Returns a negative value on failure, else wait loop count.
|
3862 |
|
|
*/
|
3863 |
|
|
static int
|
3864 |
|
|
WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
|
3865 |
|
|
{
|
3866 |
|
|
int cntdn;
|
3867 |
|
|
int count = 0;
|
3868 |
|
|
u32 intstat;
|
3869 |
|
|
|
3870 |
|
|
cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
|
3871 |
|
|
|
3872 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
3873 |
|
|
while (--cntdn) {
|
3874 |
|
|
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
|
3875 |
|
|
if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
|
3876 |
|
|
break;
|
3877 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
3878 |
|
|
schedule_timeout(1);
|
3879 |
|
|
count++;
|
3880 |
|
|
}
|
3881 |
|
|
} else {
|
3882 |
|
|
while (--cntdn) {
|
3883 |
|
|
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
|
3884 |
|
|
if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
|
3885 |
|
|
break;
|
3886 |
|
|
mdelay (1);
|
3887 |
|
|
count++;
|
3888 |
|
|
}
|
3889 |
|
|
}
|
3890 |
|
|
|
3891 |
|
|
if (cntdn) {
|
3892 |
|
|
dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (cnt=%d)\n",
|
3893 |
|
|
ioc->name, count));
|
3894 |
|
|
return count;
|
3895 |
|
|
}
|
3896 |
|
|
|
3897 |
|
|
printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout(%d)!\n",
|
3898 |
|
|
ioc->name, (count+5)/HZ);
|
3899 |
|
|
return -1;
|
3900 |
|
|
}
|
3901 |
|
|
|
3902 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3903 |
|
|
/*
|
3904 |
|
|
* WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
|
3905 |
|
|
* in it's IntStatus register.
|
3906 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
3907 |
|
|
* @howlong: How long to wait (in seconds)
|
3908 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
3909 |
|
|
*
|
3910 |
|
|
* This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
|
3911 |
|
|
*
|
3912 |
|
|
* Returns a negative value on failure, else wait loop count.
|
3913 |
|
|
*/
|
3914 |
|
|
static int
|
3915 |
|
|
WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
|
3916 |
|
|
{
|
3917 |
|
|
int cntdn;
|
3918 |
|
|
int count = 0;
|
3919 |
|
|
u32 intstat;
|
3920 |
|
|
|
3921 |
|
|
cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
|
3922 |
|
|
if (sleepFlag == CAN_SLEEP) {
|
3923 |
|
|
while (--cntdn) {
|
3924 |
|
|
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
|
3925 |
|
|
if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
|
3926 |
|
|
break;
|
3927 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
3928 |
|
|
schedule_timeout(1);
|
3929 |
|
|
count++;
|
3930 |
|
|
}
|
3931 |
|
|
} else {
|
3932 |
|
|
while (--cntdn) {
|
3933 |
|
|
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
|
3934 |
|
|
if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
|
3935 |
|
|
break;
|
3936 |
|
|
mdelay(1);
|
3937 |
|
|
count++;
|
3938 |
|
|
}
|
3939 |
|
|
}
|
3940 |
|
|
|
3941 |
|
|
if (cntdn) {
|
3942 |
|
|
dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d)\n",
|
3943 |
|
|
ioc->name, count));
|
3944 |
|
|
return count;
|
3945 |
|
|
}
|
3946 |
|
|
|
3947 |
|
|
printk(MYIOC_s_ERR_FMT "Doorbell INT timeout(%d)!\n",
|
3948 |
|
|
ioc->name, (count+5)/HZ);
|
3949 |
|
|
return -1;
|
3950 |
|
|
}
|
3951 |
|
|
|
3952 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3953 |
|
|
/*
|
3954 |
|
|
* WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
|
3955 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
3956 |
|
|
* @howlong: How long to wait (in seconds)
|
3957 |
|
|
* @sleepFlag: Specifies whether the process can sleep
|
3958 |
|
|
*
|
3959 |
|
|
* This routine polls the IOC for a handshake reply, 16 bits at a time.
|
3960 |
|
|
* Reply is cached to IOC private area large enough to hold a maximum
|
3961 |
|
|
* of 128 bytes of reply data.
|
3962 |
|
|
*
|
3963 |
|
|
* Returns a negative value on failure, else size of reply in WORDS.
|
3964 |
|
|
*/
|
3965 |
|
|
static int
|
3966 |
|
|
WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
|
3967 |
|
|
{
|
3968 |
|
|
int u16cnt = 0;
|
3969 |
|
|
int failcnt = 0;
|
3970 |
|
|
int t;
|
3971 |
|
|
u16 *hs_reply = ioc->hs_reply;
|
3972 |
|
|
volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
|
3973 |
|
|
u16 hword;
|
3974 |
|
|
|
3975 |
|
|
hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
|
3976 |
|
|
|
3977 |
|
|
/*
|
3978 |
|
|
* Get first two u16's so we can look at IOC's intended reply MsgLength
|
3979 |
|
|
*/
|
3980 |
|
|
u16cnt=0;
|
3981 |
|
|
if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
|
3982 |
|
|
failcnt++;
|
3983 |
|
|
} else {
|
3984 |
|
|
hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
|
3985 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
|
3986 |
|
|
if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
|
3987 |
|
|
failcnt++;
|
3988 |
|
|
else {
|
3989 |
|
|
hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
|
3990 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
|
3991 |
|
|
}
|
3992 |
|
|
}
|
3993 |
|
|
|
3994 |
|
|
dhsprintk((MYIOC_s_INFO_FMT "First handshake reply word=%08x%s\n",
|
3995 |
|
|
ioc->name, le32_to_cpu(*(u32 *)hs_reply),
|
3996 |
|
|
failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
|
3997 |
|
|
|
3998 |
|
|
/*
|
3999 |
|
|
* If no error (and IOC said MsgLength is > 0), piece together
|
4000 |
|
|
* reply 16 bits at a time.
|
4001 |
|
|
*/
|
4002 |
|
|
for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
|
4003 |
|
|
if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
|
4004 |
|
|
failcnt++;
|
4005 |
|
|
hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
|
4006 |
|
|
/* don't overflow our IOC hs_reply[] buffer! */
|
4007 |
|
|
if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
|
4008 |
|
|
hs_reply[u16cnt] = hword;
|
4009 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
|
4010 |
|
|
}
|
4011 |
|
|
|
4012 |
|
|
if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
|
4013 |
|
|
failcnt++;
|
4014 |
|
|
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
|
4015 |
|
|
|
4016 |
|
|
if (failcnt) {
|
4017 |
|
|
printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
|
4018 |
|
|
ioc->name);
|
4019 |
|
|
return -failcnt;
|
4020 |
|
|
}
|
4021 |
|
|
#if 0
|
4022 |
|
|
else if (u16cnt != (2 * mptReply->MsgLength)) {
|
4023 |
|
|
return -101;
|
4024 |
|
|
}
|
4025 |
|
|
else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
|
4026 |
|
|
return -102;
|
4027 |
|
|
}
|
4028 |
|
|
#endif
|
4029 |
|
|
|
4030 |
|
|
dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
|
4031 |
|
|
DBG_DUMP_REPLY_FRAME(mptReply)
|
4032 |
|
|
|
4033 |
|
|
dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY (sz=%d)\n",
|
4034 |
|
|
ioc->name, u16cnt/2));
|
4035 |
|
|
return u16cnt/2;
|
4036 |
|
|
}
|
4037 |
|
|
|
4038 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4039 |
|
|
/*
|
4040 |
|
|
* GetLanConfigPages - Fetch LANConfig pages.
|
4041 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
4042 |
|
|
*
|
4043 |
|
|
* Return: 0 for success
|
4044 |
|
|
* -ENOMEM if no memory available
|
4045 |
|
|
* -EPERM if not allowed due to ISR context
|
4046 |
|
|
* -EAGAIN if no msg frames currently available
|
4047 |
|
|
* -EFAULT for non-successful reply or no reply (timeout)
|
4048 |
|
|
*/
|
4049 |
|
|
static int
|
4050 |
|
|
GetLanConfigPages(MPT_ADAPTER *ioc)
|
4051 |
|
|
{
|
4052 |
|
|
ConfigPageHeader_t hdr;
|
4053 |
|
|
CONFIGPARMS cfg;
|
4054 |
|
|
LANPage0_t *ppage0_alloc;
|
4055 |
|
|
dma_addr_t page0_dma;
|
4056 |
|
|
LANPage1_t *ppage1_alloc;
|
4057 |
|
|
dma_addr_t page1_dma;
|
4058 |
|
|
int rc = 0;
|
4059 |
|
|
int data_sz;
|
4060 |
|
|
int copy_sz;
|
4061 |
|
|
|
4062 |
|
|
/* Get LAN Page 0 header */
|
4063 |
|
|
hdr.PageVersion = 0;
|
4064 |
|
|
hdr.PageLength = 0;
|
4065 |
|
|
hdr.PageNumber = 0;
|
4066 |
|
|
hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
|
4067 |
|
|
cfg.hdr = &hdr;
|
4068 |
|
|
cfg.physAddr = -1;
|
4069 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4070 |
|
|
cfg.dir = 0;
|
4071 |
|
|
cfg.pageAddr = 0;
|
4072 |
|
|
cfg.timeout = 0;
|
4073 |
|
|
|
4074 |
|
|
if ((rc = mpt_config(ioc, &cfg)) != 0)
|
4075 |
|
|
return rc;
|
4076 |
|
|
|
4077 |
|
|
if (hdr.PageLength > 0) {
|
4078 |
|
|
data_sz = hdr.PageLength * 4;
|
4079 |
|
|
ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
|
4080 |
|
|
rc = -ENOMEM;
|
4081 |
|
|
if (ppage0_alloc) {
|
4082 |
|
|
memset((u8 *)ppage0_alloc, 0, data_sz);
|
4083 |
|
|
cfg.physAddr = page0_dma;
|
4084 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
4085 |
|
|
|
4086 |
|
|
if ((rc = mpt_config(ioc, &cfg)) == 0) {
|
4087 |
|
|
/* save the data */
|
4088 |
|
|
copy_sz = MIN(sizeof(LANPage0_t), data_sz);
|
4089 |
|
|
memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
|
4090 |
|
|
|
4091 |
|
|
}
|
4092 |
|
|
|
4093 |
|
|
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
|
4094 |
|
|
|
4095 |
|
|
/* FIXME!
|
4096 |
|
|
* Normalize endianness of structure data,
|
4097 |
|
|
* by byte-swapping all > 1 byte fields!
|
4098 |
|
|
*/
|
4099 |
|
|
|
4100 |
|
|
}
|
4101 |
|
|
|
4102 |
|
|
if (rc)
|
4103 |
|
|
return rc;
|
4104 |
|
|
}
|
4105 |
|
|
|
4106 |
|
|
/* Get LAN Page 1 header */
|
4107 |
|
|
hdr.PageVersion = 0;
|
4108 |
|
|
hdr.PageLength = 0;
|
4109 |
|
|
hdr.PageNumber = 1;
|
4110 |
|
|
hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
|
4111 |
|
|
cfg.hdr = &hdr;
|
4112 |
|
|
cfg.physAddr = -1;
|
4113 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4114 |
|
|
cfg.dir = 0;
|
4115 |
|
|
cfg.pageAddr = 0;
|
4116 |
|
|
|
4117 |
|
|
if ((rc = mpt_config(ioc, &cfg)) != 0)
|
4118 |
|
|
return rc;
|
4119 |
|
|
|
4120 |
|
|
if (hdr.PageLength == 0)
|
4121 |
|
|
return 0;
|
4122 |
|
|
|
4123 |
|
|
data_sz = hdr.PageLength * 4;
|
4124 |
|
|
rc = -ENOMEM;
|
4125 |
|
|
ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
|
4126 |
|
|
if (ppage1_alloc) {
|
4127 |
|
|
memset((u8 *)ppage1_alloc, 0, data_sz);
|
4128 |
|
|
cfg.physAddr = page1_dma;
|
4129 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
4130 |
|
|
|
4131 |
|
|
if ((rc = mpt_config(ioc, &cfg)) == 0) {
|
4132 |
|
|
/* save the data */
|
4133 |
|
|
copy_sz = MIN(sizeof(LANPage1_t), data_sz);
|
4134 |
|
|
memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
|
4135 |
|
|
}
|
4136 |
|
|
|
4137 |
|
|
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
|
4138 |
|
|
|
4139 |
|
|
/* FIXME!
|
4140 |
|
|
* Normalize endianness of structure data,
|
4141 |
|
|
* by byte-swapping all > 1 byte fields!
|
4142 |
|
|
*/
|
4143 |
|
|
|
4144 |
|
|
}
|
4145 |
|
|
|
4146 |
|
|
return rc;
|
4147 |
|
|
}
|
4148 |
|
|
|
4149 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4150 |
|
|
/*
|
4151 |
|
|
* GetFcPortPage0 - Fetch FCPort config Page0.
|
4152 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
4153 |
|
|
* @portnum: IOC Port number
|
4154 |
|
|
*
|
4155 |
|
|
* Return: 0 for success
|
4156 |
|
|
* -ENOMEM if no memory available
|
4157 |
|
|
* -EPERM if not allowed due to ISR context
|
4158 |
|
|
* -EAGAIN if no msg frames currently available
|
4159 |
|
|
* -EFAULT for non-successful reply or no reply (timeout)
|
4160 |
|
|
*/
|
4161 |
|
|
static int
|
4162 |
|
|
GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
|
4163 |
|
|
{
|
4164 |
|
|
ConfigPageHeader_t hdr;
|
4165 |
|
|
CONFIGPARMS cfg;
|
4166 |
|
|
FCPortPage0_t *ppage0_alloc;
|
4167 |
|
|
FCPortPage0_t *pp0dest;
|
4168 |
|
|
dma_addr_t page0_dma;
|
4169 |
|
|
int data_sz;
|
4170 |
|
|
int copy_sz;
|
4171 |
|
|
int rc;
|
4172 |
|
|
|
4173 |
|
|
/* Get FCPort Page 0 header */
|
4174 |
|
|
hdr.PageVersion = 0;
|
4175 |
|
|
hdr.PageLength = 0;
|
4176 |
|
|
hdr.PageNumber = 0;
|
4177 |
|
|
hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
|
4178 |
|
|
cfg.hdr = &hdr;
|
4179 |
|
|
cfg.physAddr = -1;
|
4180 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4181 |
|
|
cfg.dir = 0;
|
4182 |
|
|
cfg.pageAddr = portnum;
|
4183 |
|
|
cfg.timeout = 0;
|
4184 |
|
|
|
4185 |
|
|
if ((rc = mpt_config(ioc, &cfg)) != 0)
|
4186 |
|
|
return rc;
|
4187 |
|
|
|
4188 |
|
|
if (hdr.PageLength == 0)
|
4189 |
|
|
return 0;
|
4190 |
|
|
|
4191 |
|
|
data_sz = hdr.PageLength * 4;
|
4192 |
|
|
rc = -ENOMEM;
|
4193 |
|
|
ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
|
4194 |
|
|
if (ppage0_alloc) {
|
4195 |
|
|
memset((u8 *)ppage0_alloc, 0, data_sz);
|
4196 |
|
|
cfg.physAddr = page0_dma;
|
4197 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
4198 |
|
|
|
4199 |
|
|
if ((rc = mpt_config(ioc, &cfg)) == 0) {
|
4200 |
|
|
/* save the data */
|
4201 |
|
|
pp0dest = &ioc->fc_port_page0[portnum];
|
4202 |
|
|
copy_sz = MIN(sizeof(FCPortPage0_t), data_sz);
|
4203 |
|
|
memcpy(pp0dest, ppage0_alloc, copy_sz);
|
4204 |
|
|
|
4205 |
|
|
/*
|
4206 |
|
|
* Normalize endianness of structure data,
|
4207 |
|
|
* by byte-swapping all > 1 byte fields!
|
4208 |
|
|
*/
|
4209 |
|
|
pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
|
4210 |
|
|
pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
|
4211 |
|
|
pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
|
4212 |
|
|
pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
|
4213 |
|
|
pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
|
4214 |
|
|
pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
|
4215 |
|
|
pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
|
4216 |
|
|
pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
|
4217 |
|
|
pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
|
4218 |
|
|
pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
|
4219 |
|
|
pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
|
4220 |
|
|
pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
|
4221 |
|
|
pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
|
4222 |
|
|
pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
|
4223 |
|
|
pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
|
4224 |
|
|
pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
|
4225 |
|
|
|
4226 |
|
|
}
|
4227 |
|
|
|
4228 |
|
|
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
|
4229 |
|
|
}
|
4230 |
|
|
|
4231 |
|
|
return rc;
|
4232 |
|
|
}
|
4233 |
|
|
|
4234 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4235 |
|
|
/*
|
4236 |
|
|
* GetIoUnitPage2 - Retrieve BIOS version and boot order information.
|
4237 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
4238 |
|
|
*
|
4239 |
|
|
* Returns: 0 for success
|
4240 |
|
|
* -ENOMEM if no memory available
|
4241 |
|
|
* -EPERM if not allowed due to ISR context
|
4242 |
|
|
* -EAGAIN if no msg frames currently available
|
4243 |
|
|
* -EFAULT for non-successful reply or no reply (timeout)
|
4244 |
|
|
*/
|
4245 |
|
|
static int
|
4246 |
|
|
GetIoUnitPage2(MPT_ADAPTER *ioc)
|
4247 |
|
|
{
|
4248 |
|
|
ConfigPageHeader_t hdr;
|
4249 |
|
|
CONFIGPARMS cfg;
|
4250 |
|
|
IOUnitPage2_t *ppage_alloc;
|
4251 |
|
|
dma_addr_t page_dma;
|
4252 |
|
|
int data_sz;
|
4253 |
|
|
int rc;
|
4254 |
|
|
|
4255 |
|
|
/* Get the page header */
|
4256 |
|
|
hdr.PageVersion = 0;
|
4257 |
|
|
hdr.PageLength = 0;
|
4258 |
|
|
hdr.PageNumber = 2;
|
4259 |
|
|
hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
|
4260 |
|
|
cfg.hdr = &hdr;
|
4261 |
|
|
cfg.physAddr = -1;
|
4262 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4263 |
|
|
cfg.dir = 0;
|
4264 |
|
|
cfg.pageAddr = 0;
|
4265 |
|
|
cfg.timeout = 0;
|
4266 |
|
|
|
4267 |
|
|
if ((rc = mpt_config(ioc, &cfg)) != 0)
|
4268 |
|
|
return rc;
|
4269 |
|
|
|
4270 |
|
|
if (hdr.PageLength == 0)
|
4271 |
|
|
return 0;
|
4272 |
|
|
|
4273 |
|
|
/* Read the config page */
|
4274 |
|
|
data_sz = hdr.PageLength * 4;
|
4275 |
|
|
rc = -ENOMEM;
|
4276 |
|
|
ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
|
4277 |
|
|
if (ppage_alloc) {
|
4278 |
|
|
memset((u8 *)ppage_alloc, 0, data_sz);
|
4279 |
|
|
cfg.physAddr = page_dma;
|
4280 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
4281 |
|
|
|
4282 |
|
|
/* If Good, save data */
|
4283 |
|
|
if ((rc = mpt_config(ioc, &cfg)) == 0)
|
4284 |
|
|
ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
|
4285 |
|
|
|
4286 |
|
|
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
|
4287 |
|
|
}
|
4288 |
|
|
|
4289 |
|
|
return rc;
|
4290 |
|
|
}
|
4291 |
|
|
|
4292 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4293 |
|
|
/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
|
4294 |
|
|
* @ioc: Pointer to a Adapter Strucutre
|
4295 |
|
|
* @portnum: IOC port number
|
4296 |
|
|
*
|
4297 |
|
|
* Return: -EFAULT if read of config page header fails
|
4298 |
|
|
* or if no nvram
|
4299 |
|
|
* If read of SCSI Port Page 0 fails,
|
4300 |
|
|
* NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
|
4301 |
|
|
* Adapter settings: async, narrow
|
4302 |
|
|
* Return 1
|
4303 |
|
|
* If read of SCSI Port Page 2 fails,
|
4304 |
|
|
* Adapter settings valid
|
4305 |
|
|
* NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
|
4306 |
|
|
* Return 1
|
4307 |
|
|
* Else
|
4308 |
|
|
* Both valid
|
4309 |
|
|
* Return 0
|
4310 |
|
|
* CHECK - what type of locking mechanisms should be used????
|
4311 |
|
|
*/
|
4312 |
|
|
static int
|
4313 |
|
|
mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
|
4314 |
|
|
{
|
4315 |
|
|
u8 *pbuf;
|
4316 |
|
|
dma_addr_t buf_dma;
|
4317 |
|
|
CONFIGPARMS cfg;
|
4318 |
|
|
ConfigPageHeader_t header;
|
4319 |
|
|
int ii;
|
4320 |
|
|
int data, rc = 0;
|
4321 |
|
|
|
4322 |
|
|
/* Allocate memory
|
4323 |
|
|
*/
|
4324 |
|
|
if (!ioc->spi_data.nvram) {
|
4325 |
|
|
int sz;
|
4326 |
|
|
u8 *mem;
|
4327 |
|
|
sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
|
4328 |
|
|
mem = kmalloc(sz, GFP_ATOMIC);
|
4329 |
|
|
if (mem == NULL)
|
4330 |
|
|
return -EFAULT;
|
4331 |
|
|
|
4332 |
|
|
ioc->spi_data.nvram = (int *) mem;
|
4333 |
|
|
|
4334 |
|
|
dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
|
4335 |
|
|
ioc->name, ioc->spi_data.nvram, sz));
|
4336 |
|
|
}
|
4337 |
|
|
|
4338 |
|
|
/* Invalidate NVRAM information
|
4339 |
|
|
*/
|
4340 |
|
|
for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
|
4341 |
|
|
ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
|
4342 |
|
|
}
|
4343 |
|
|
|
4344 |
|
|
/* Read SPP0 header, allocate memory, then read page.
|
4345 |
|
|
*/
|
4346 |
|
|
header.PageVersion = 0;
|
4347 |
|
|
header.PageLength = 0;
|
4348 |
|
|
header.PageNumber = 0;
|
4349 |
|
|
header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
|
4350 |
|
|
cfg.hdr = &header;
|
4351 |
|
|
cfg.physAddr = -1;
|
4352 |
|
|
cfg.pageAddr = portnum;
|
4353 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4354 |
|
|
cfg.dir = 0;
|
4355 |
|
|
cfg.timeout = 0; /* use default */
|
4356 |
|
|
if (mpt_config(ioc, &cfg) != 0)
|
4357 |
|
|
return -EFAULT;
|
4358 |
|
|
|
4359 |
|
|
if (header.PageLength > 0) {
|
4360 |
|
|
pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
|
4361 |
|
|
if (pbuf) {
|
4362 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
4363 |
|
|
cfg.physAddr = buf_dma;
|
4364 |
|
|
if (mpt_config(ioc, &cfg) != 0) {
|
4365 |
|
|
ioc->spi_data.maxBusWidth = MPT_NARROW;
|
4366 |
|
|
ioc->spi_data.maxSyncOffset = 0;
|
4367 |
|
|
ioc->spi_data.minSyncFactor = MPT_ASYNC;
|
4368 |
|
|
ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
|
4369 |
|
|
rc = 1;
|
4370 |
|
|
} else {
|
4371 |
|
|
/* Save the Port Page 0 data
|
4372 |
|
|
*/
|
4373 |
|
|
SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
|
4374 |
|
|
pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
|
4375 |
|
|
pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
|
4376 |
|
|
|
4377 |
|
|
ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
|
4378 |
|
|
data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
|
4379 |
|
|
if (data) {
|
4380 |
|
|
ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
|
4381 |
|
|
data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
|
4382 |
|
|
ioc->spi_data.minSyncFactor = (u8) (data >> 8);
|
4383 |
|
|
} else {
|
4384 |
|
|
ioc->spi_data.maxSyncOffset = 0;
|
4385 |
|
|
ioc->spi_data.minSyncFactor = MPT_ASYNC;
|
4386 |
|
|
}
|
4387 |
|
|
|
4388 |
|
|
ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
|
4389 |
|
|
|
4390 |
|
|
/* Update the minSyncFactor based on bus type.
|
4391 |
|
|
*/
|
4392 |
|
|
if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
|
4393 |
|
|
(ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
|
4394 |
|
|
|
4395 |
|
|
if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
|
4396 |
|
|
ioc->spi_data.minSyncFactor = MPT_ULTRA;
|
4397 |
|
|
}
|
4398 |
|
|
}
|
4399 |
|
|
if (pbuf) {
|
4400 |
|
|
pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
|
4401 |
|
|
}
|
4402 |
|
|
}
|
4403 |
|
|
}
|
4404 |
|
|
|
4405 |
|
|
/* SCSI Port Page 2 - Read the header then the page.
|
4406 |
|
|
*/
|
4407 |
|
|
header.PageVersion = 0;
|
4408 |
|
|
header.PageLength = 0;
|
4409 |
|
|
header.PageNumber = 2;
|
4410 |
|
|
header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
|
4411 |
|
|
cfg.hdr = &header;
|
4412 |
|
|
cfg.physAddr = -1;
|
4413 |
|
|
cfg.pageAddr = portnum;
|
4414 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4415 |
|
|
cfg.dir = 0;
|
4416 |
|
|
if (mpt_config(ioc, &cfg) != 0)
|
4417 |
|
|
return -EFAULT;
|
4418 |
|
|
|
4419 |
|
|
if (header.PageLength > 0) {
|
4420 |
|
|
/* Allocate memory and read SCSI Port Page 2
|
4421 |
|
|
*/
|
4422 |
|
|
pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
|
4423 |
|
|
if (pbuf) {
|
4424 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
|
4425 |
|
|
cfg.physAddr = buf_dma;
|
4426 |
|
|
if (mpt_config(ioc, &cfg) != 0) {
|
4427 |
|
|
/* Nvram data is left with INVALID mark
|
4428 |
|
|
*/
|
4429 |
|
|
rc = 1;
|
4430 |
|
|
} else {
|
4431 |
|
|
SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
|
4432 |
|
|
MpiDeviceInfo_t *pdevice = NULL;
|
4433 |
|
|
|
4434 |
|
|
/* Save the Port Page 2 data
|
4435 |
|
|
* (reformat into a 32bit quantity)
|
4436 |
|
|
*/
|
4437 |
|
|
data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
|
4438 |
|
|
ioc->spi_data.PortFlags = data;
|
4439 |
|
|
for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
|
4440 |
|
|
pdevice = &pPP2->DeviceSettings[ii];
|
4441 |
|
|
data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
|
4442 |
|
|
(pdevice->SyncFactor << 8) | pdevice->Timeout;
|
4443 |
|
|
ioc->spi_data.nvram[ii] = data;
|
4444 |
|
|
}
|
4445 |
|
|
}
|
4446 |
|
|
|
4447 |
|
|
pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
|
4448 |
|
|
}
|
4449 |
|
|
}
|
4450 |
|
|
|
4451 |
|
|
/* Update Adapter limits with those from NVRAM
|
4452 |
|
|
* Comment: Don't need to do this. Target performance
|
4453 |
|
|
* parameters will never exceed the adapters limits.
|
4454 |
|
|
*/
|
4455 |
|
|
|
4456 |
|
|
return rc;
|
4457 |
|
|
}
|
4458 |
|
|
|
4459 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4460 |
|
|
/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
|
4461 |
|
|
* @ioc: Pointer to a Adapter Strucutre
|
4462 |
|
|
* @portnum: IOC port number
|
4463 |
|
|
*
|
4464 |
|
|
* Return: -EFAULT if read of config page header fails
|
4465 |
|
|
* or 0 if success.
|
4466 |
|
|
*/
|
4467 |
|
|
static int
|
4468 |
|
|
mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
|
4469 |
|
|
{
|
4470 |
|
|
CONFIGPARMS cfg;
|
4471 |
|
|
ConfigPageHeader_t header;
|
4472 |
|
|
|
4473 |
|
|
/* Read the SCSI Device Page 1 header
|
4474 |
|
|
*/
|
4475 |
|
|
header.PageVersion = 0;
|
4476 |
|
|
header.PageLength = 0;
|
4477 |
|
|
header.PageNumber = 1;
|
4478 |
|
|
header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
|
4479 |
|
|
cfg.hdr = &header;
|
4480 |
|
|
cfg.physAddr = -1;
|
4481 |
|
|
cfg.pageAddr = portnum;
|
4482 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4483 |
|
|
cfg.dir = 0;
|
4484 |
|
|
cfg.timeout = 0;
|
4485 |
|
|
if (mpt_config(ioc, &cfg) != 0)
|
4486 |
|
|
return -EFAULT;
|
4487 |
|
|
|
4488 |
|
|
ioc->spi_data.sdp1version = cfg.hdr->PageVersion;
|
4489 |
|
|
ioc->spi_data.sdp1length = cfg.hdr->PageLength;
|
4490 |
|
|
|
4491 |
|
|
header.PageVersion = 0;
|
4492 |
|
|
header.PageLength = 0;
|
4493 |
|
|
header.PageNumber = 0;
|
4494 |
|
|
header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
|
4495 |
|
|
if (mpt_config(ioc, &cfg) != 0)
|
4496 |
|
|
return -EFAULT;
|
4497 |
|
|
|
4498 |
|
|
ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
|
4499 |
|
|
ioc->spi_data.sdp0length = cfg.hdr->PageLength;
|
4500 |
|
|
|
4501 |
|
|
dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
|
4502 |
|
|
ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
|
4503 |
|
|
|
4504 |
|
|
dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
|
4505 |
|
|
ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
|
4506 |
|
|
return 0;
|
4507 |
|
|
}
|
4508 |
|
|
|
4509 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4510 |
|
|
/**
|
4511 |
|
|
* mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
|
4512 |
|
|
* @ioc: Pointer to a Adapter Strucutre
|
4513 |
|
|
* @portnum: IOC port number
|
4514 |
|
|
*
|
4515 |
|
|
* Return:
|
4516 |
|
|
* 0 on success
|
4517 |
|
|
* -EFAULT if read of config page header fails or data pointer not NULL
|
4518 |
|
|
* -ENOMEM if pci_alloc failed
|
4519 |
|
|
*/
|
4520 |
|
|
static int
|
4521 |
|
|
mpt_findImVolumes(MPT_ADAPTER *ioc)
|
4522 |
|
|
{
|
4523 |
|
|
IOCPage2_t *pIoc2;
|
4524 |
|
|
ConfigPageIoc2RaidVol_t *pIocRv;
|
4525 |
|
|
dma_addr_t ioc2_dma;
|
4526 |
|
|
CONFIGPARMS cfg;
|
4527 |
|
|
ConfigPageHeader_t header;
|
4528 |
|
|
int jj;
|
4529 |
|
|
int rc = 0;
|
4530 |
|
|
int iocpage2sz;
|
4531 |
|
|
u8 nVols, nPhys;
|
4532 |
|
|
u8 vid, vbus, vioc;
|
4533 |
|
|
|
4534 |
|
|
if (ioc->spi_data.pIocPg3)
|
4535 |
|
|
return -EFAULT;
|
4536 |
|
|
|
4537 |
|
|
/* Read IOCP2 header then the page.
|
4538 |
|
|
*/
|
4539 |
|
|
header.PageVersion = 0;
|
4540 |
|
|
header.PageLength = 0;
|
4541 |
|
|
header.PageNumber = 2;
|
4542 |
|
|
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
|
4543 |
|
|
cfg.hdr = &header;
|
4544 |
|
|
cfg.physAddr = -1;
|
4545 |
|
|
cfg.pageAddr = 0;
|
4546 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4547 |
|
|
cfg.dir = 0;
|
4548 |
|
|
cfg.timeout = 0;
|
4549 |
|
|
if (mpt_config(ioc, &cfg) != 0)
|
4550 |
|
|
return -EFAULT;
|
4551 |
|
|
|
4552 |
|
|
if (header.PageLength == 0)
|
4553 |
|
|
return -EFAULT;
|
4554 |
|
|
|
4555 |
|
|
iocpage2sz = header.PageLength * 4;
|
4556 |
|
|
pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
|
4557 |
|
|
if (!pIoc2)
|
4558 |
|
|
return -ENOMEM;
|
4559 |
|
|
|
4560 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
4561 |
|
|
cfg.physAddr = ioc2_dma;
|
4562 |
|
|
if (mpt_config(ioc, &cfg) != 0)
|
4563 |
|
|
goto done_and_free;
|
4564 |
|
|
|
4565 |
|
|
/* Identify RAID Volume Id's */
|
4566 |
|
|
nVols = pIoc2->NumActiveVolumes;
|
4567 |
|
|
if ( nVols == 0) {
|
4568 |
|
|
/* No RAID Volumes. Done.
|
4569 |
|
|
*/
|
4570 |
|
|
} else {
|
4571 |
|
|
/* At least 1 RAID Volume
|
4572 |
|
|
*/
|
4573 |
|
|
pIocRv = pIoc2->RaidVolume;
|
4574 |
|
|
ioc->spi_data.isRaid = 0;
|
4575 |
|
|
for (jj = 0; jj < nVols; jj++, pIocRv++) {
|
4576 |
|
|
vid = pIocRv->VolumeID;
|
4577 |
|
|
vbus = pIocRv->VolumeBus;
|
4578 |
|
|
vioc = pIocRv->VolumeIOC;
|
4579 |
|
|
|
4580 |
|
|
/* find the match
|
4581 |
|
|
*/
|
4582 |
|
|
if (vbus == 0) {
|
4583 |
|
|
ioc->spi_data.isRaid |= (1 << vid);
|
4584 |
|
|
} else {
|
4585 |
|
|
/* Error! Always bus 0
|
4586 |
|
|
*/
|
4587 |
|
|
}
|
4588 |
|
|
}
|
4589 |
|
|
}
|
4590 |
|
|
|
4591 |
|
|
/* Identify Hidden Physical Disk Id's */
|
4592 |
|
|
nPhys = pIoc2->NumActivePhysDisks;
|
4593 |
|
|
if (nPhys == 0) {
|
4594 |
|
|
/* No physical disks. Done.
|
4595 |
|
|
*/
|
4596 |
|
|
} else {
|
4597 |
|
|
mpt_read_ioc_pg_3(ioc);
|
4598 |
|
|
}
|
4599 |
|
|
|
4600 |
|
|
done_and_free:
|
4601 |
|
|
pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
|
4602 |
|
|
|
4603 |
|
|
return rc;
|
4604 |
|
|
}
|
4605 |
|
|
|
4606 |
|
|
int
|
4607 |
|
|
mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
|
4608 |
|
|
{
|
4609 |
|
|
IOCPage3_t *pIoc3;
|
4610 |
|
|
u8 *mem;
|
4611 |
|
|
CONFIGPARMS cfg;
|
4612 |
|
|
ConfigPageHeader_t header;
|
4613 |
|
|
dma_addr_t ioc3_dma;
|
4614 |
|
|
int iocpage3sz = 0;
|
4615 |
|
|
|
4616 |
|
|
/* Free the old page
|
4617 |
|
|
*/
|
4618 |
|
|
if (ioc->spi_data.pIocPg3) {
|
4619 |
|
|
kfree(ioc->spi_data.pIocPg3);
|
4620 |
|
|
ioc->spi_data.pIocPg3 = NULL;
|
4621 |
|
|
}
|
4622 |
|
|
|
4623 |
|
|
/* There is at least one physical disk.
|
4624 |
|
|
* Read and save IOC Page 3
|
4625 |
|
|
*/
|
4626 |
|
|
header.PageVersion = 0;
|
4627 |
|
|
header.PageLength = 0;
|
4628 |
|
|
header.PageNumber = 3;
|
4629 |
|
|
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
|
4630 |
|
|
cfg.hdr = &header;
|
4631 |
|
|
cfg.physAddr = -1;
|
4632 |
|
|
cfg.pageAddr = 0;
|
4633 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4634 |
|
|
cfg.dir = 0;
|
4635 |
|
|
cfg.timeout = 0;
|
4636 |
|
|
if (mpt_config(ioc, &cfg) != 0)
|
4637 |
|
|
return 0;
|
4638 |
|
|
|
4639 |
|
|
if (header.PageLength == 0)
|
4640 |
|
|
return 0;
|
4641 |
|
|
|
4642 |
|
|
/* Read Header good, alloc memory
|
4643 |
|
|
*/
|
4644 |
|
|
iocpage3sz = header.PageLength * 4;
|
4645 |
|
|
pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
|
4646 |
|
|
if (!pIoc3)
|
4647 |
|
|
return 0;
|
4648 |
|
|
|
4649 |
|
|
/* Read the Page and save the data
|
4650 |
|
|
* into malloc'd memory.
|
4651 |
|
|
*/
|
4652 |
|
|
cfg.physAddr = ioc3_dma;
|
4653 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
4654 |
|
|
if (mpt_config(ioc, &cfg) == 0) {
|
4655 |
|
|
mem = kmalloc(iocpage3sz, GFP_ATOMIC);
|
4656 |
|
|
if (mem) {
|
4657 |
|
|
memcpy(mem, (u8 *)pIoc3, iocpage3sz);
|
4658 |
|
|
ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
|
4659 |
|
|
}
|
4660 |
|
|
}
|
4661 |
|
|
|
4662 |
|
|
pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
|
4663 |
|
|
|
4664 |
|
|
return 0;
|
4665 |
|
|
}
|
4666 |
|
|
|
4667 |
|
|
static void
|
4668 |
|
|
mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
|
4669 |
|
|
{
|
4670 |
|
|
IOCPage4_t *pIoc4;
|
4671 |
|
|
CONFIGPARMS cfg;
|
4672 |
|
|
ConfigPageHeader_t header;
|
4673 |
|
|
dma_addr_t ioc4_dma;
|
4674 |
|
|
int iocpage4sz;
|
4675 |
|
|
|
4676 |
|
|
/* Read and save IOC Page 4
|
4677 |
|
|
*/
|
4678 |
|
|
header.PageVersion = 0;
|
4679 |
|
|
header.PageLength = 0;
|
4680 |
|
|
header.PageNumber = 4;
|
4681 |
|
|
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
|
4682 |
|
|
cfg.hdr = &header;
|
4683 |
|
|
cfg.physAddr = -1;
|
4684 |
|
|
cfg.pageAddr = 0;
|
4685 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4686 |
|
|
cfg.dir = 0;
|
4687 |
|
|
cfg.timeout = 0;
|
4688 |
|
|
if (mpt_config(ioc, &cfg) != 0)
|
4689 |
|
|
return;
|
4690 |
|
|
|
4691 |
|
|
if (header.PageLength == 0)
|
4692 |
|
|
return;
|
4693 |
|
|
|
4694 |
|
|
if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
|
4695 |
|
|
iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
|
4696 |
|
|
pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
|
4697 |
|
|
if (!pIoc4)
|
4698 |
|
|
return;
|
4699 |
|
|
} else {
|
4700 |
|
|
ioc4_dma = ioc->spi_data.IocPg4_dma;
|
4701 |
|
|
iocpage4sz = ioc->spi_data.IocPg4Sz;
|
4702 |
|
|
}
|
4703 |
|
|
|
4704 |
|
|
/* Read the Page into dma memory.
|
4705 |
|
|
*/
|
4706 |
|
|
cfg.physAddr = ioc4_dma;
|
4707 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
4708 |
|
|
if (mpt_config(ioc, &cfg) == 0) {
|
4709 |
|
|
ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
|
4710 |
|
|
ioc->spi_data.IocPg4_dma = ioc4_dma;
|
4711 |
|
|
ioc->spi_data.IocPg4Sz = iocpage4sz;
|
4712 |
|
|
} else {
|
4713 |
|
|
pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
|
4714 |
|
|
ioc->spi_data.pIocPg4 = NULL;
|
4715 |
|
|
}
|
4716 |
|
|
}
|
4717 |
|
|
|
4718 |
|
|
static void
|
4719 |
|
|
mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
|
4720 |
|
|
{
|
4721 |
|
|
IOCPage1_t *pIoc1;
|
4722 |
|
|
CONFIGPARMS cfg;
|
4723 |
|
|
ConfigPageHeader_t header;
|
4724 |
|
|
dma_addr_t ioc1_dma;
|
4725 |
|
|
int iocpage1sz = 0;
|
4726 |
|
|
u32 tmp;
|
4727 |
|
|
|
4728 |
|
|
/* Check the Coalescing Timeout in IOC Page 1
|
4729 |
|
|
*/
|
4730 |
|
|
header.PageVersion = 0;
|
4731 |
|
|
header.PageLength = 0;
|
4732 |
|
|
header.PageNumber = 1;
|
4733 |
|
|
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
|
4734 |
|
|
cfg.hdr = &header;
|
4735 |
|
|
cfg.physAddr = -1;
|
4736 |
|
|
cfg.pageAddr = 0;
|
4737 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
4738 |
|
|
cfg.dir = 0;
|
4739 |
|
|
cfg.timeout = 0;
|
4740 |
|
|
if (mpt_config(ioc, &cfg) != 0)
|
4741 |
|
|
return;
|
4742 |
|
|
|
4743 |
|
|
if (header.PageLength == 0)
|
4744 |
|
|
return;
|
4745 |
|
|
|
4746 |
|
|
/* Read Header good, alloc memory
|
4747 |
|
|
*/
|
4748 |
|
|
iocpage1sz = header.PageLength * 4;
|
4749 |
|
|
pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
|
4750 |
|
|
if (!pIoc1)
|
4751 |
|
|
return;
|
4752 |
|
|
|
4753 |
|
|
/* Read the Page and check coalescing timeout
|
4754 |
|
|
*/
|
4755 |
|
|
cfg.physAddr = ioc1_dma;
|
4756 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
4757 |
|
|
if (mpt_config(ioc, &cfg) == 0) {
|
4758 |
|
|
|
4759 |
|
|
tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
|
4760 |
|
|
if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
|
4761 |
|
|
tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
|
4762 |
|
|
|
4763 |
|
|
dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
|
4764 |
|
|
ioc->name, tmp));
|
4765 |
|
|
|
4766 |
|
|
if (tmp > MPT_COALESCING_TIMEOUT) {
|
4767 |
|
|
pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
|
4768 |
|
|
|
4769 |
|
|
/* Write NVRAM and current
|
4770 |
|
|
*/
|
4771 |
|
|
cfg.dir = 1;
|
4772 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
|
4773 |
|
|
if (mpt_config(ioc, &cfg) == 0) {
|
4774 |
|
|
dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
|
4775 |
|
|
ioc->name, MPT_COALESCING_TIMEOUT));
|
4776 |
|
|
|
4777 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
|
4778 |
|
|
if (mpt_config(ioc, &cfg) == 0) {
|
4779 |
|
|
dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
|
4780 |
|
|
ioc->name, MPT_COALESCING_TIMEOUT));
|
4781 |
|
|
} else {
|
4782 |
|
|
dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
|
4783 |
|
|
ioc->name));
|
4784 |
|
|
}
|
4785 |
|
|
|
4786 |
|
|
} else {
|
4787 |
|
|
dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
|
4788 |
|
|
ioc->name));
|
4789 |
|
|
}
|
4790 |
|
|
}
|
4791 |
|
|
|
4792 |
|
|
} else {
|
4793 |
|
|
dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
|
4794 |
|
|
}
|
4795 |
|
|
}
|
4796 |
|
|
|
4797 |
|
|
pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
|
4798 |
|
|
|
4799 |
|
|
return;
|
4800 |
|
|
}
|
4801 |
|
|
|
4802 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4803 |
|
|
/*
|
4804 |
|
|
* SendEventNotification - Send EventNotification (on or off) request
|
4805 |
|
|
* to MPT adapter.
|
4806 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
4807 |
|
|
* @EvSwitch: Event switch flags
|
4808 |
|
|
*/
|
4809 |
|
|
static int
|
4810 |
|
|
SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
|
4811 |
|
|
{
|
4812 |
|
|
EventNotification_t *evnp;
|
4813 |
|
|
|
4814 |
|
|
evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id);
|
4815 |
|
|
if (evnp == NULL) {
|
4816 |
|
|
dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
|
4817 |
|
|
ioc->name));
|
4818 |
|
|
return 0;
|
4819 |
|
|
}
|
4820 |
|
|
memset(evnp, 0, sizeof(*evnp));
|
4821 |
|
|
|
4822 |
|
|
dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch));
|
4823 |
|
|
|
4824 |
|
|
evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
|
4825 |
|
|
evnp->ChainOffset = 0;
|
4826 |
|
|
evnp->MsgFlags = 0;
|
4827 |
|
|
evnp->Switch = EvSwitch;
|
4828 |
|
|
|
4829 |
|
|
mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)evnp);
|
4830 |
|
|
|
4831 |
|
|
return 0;
|
4832 |
|
|
}
|
4833 |
|
|
|
4834 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4835 |
|
|
/**
|
4836 |
|
|
* SendEventAck - Send EventAck request to MPT adapter.
|
4837 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
4838 |
|
|
* @evnp: Pointer to original EventNotification request
|
4839 |
|
|
*/
|
4840 |
|
|
static int
|
4841 |
|
|
SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
|
4842 |
|
|
{
|
4843 |
|
|
EventAck_t *pAck;
|
4844 |
|
|
|
4845 |
|
|
if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
|
4846 |
|
|
printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n",
|
4847 |
|
|
ioc->name);
|
4848 |
|
|
return -1;
|
4849 |
|
|
}
|
4850 |
|
|
memset(pAck, 0, sizeof(*pAck));
|
4851 |
|
|
|
4852 |
|
|
dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
|
4853 |
|
|
|
4854 |
|
|
pAck->Function = MPI_FUNCTION_EVENT_ACK;
|
4855 |
|
|
pAck->ChainOffset = 0;
|
4856 |
|
|
pAck->MsgFlags = 0;
|
4857 |
|
|
pAck->Event = evnp->Event;
|
4858 |
|
|
pAck->EventContext = evnp->EventContext;
|
4859 |
|
|
|
4860 |
|
|
mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)pAck);
|
4861 |
|
|
|
4862 |
|
|
return 0;
|
4863 |
|
|
}
|
4864 |
|
|
|
4865 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4866 |
|
|
/**
|
4867 |
|
|
* mpt_config - Generic function to issue config message
|
4868 |
|
|
* @ioc - Pointer to an adapter structure
|
4869 |
|
|
* @cfg - Pointer to a configuration structure. Struct contains
|
4870 |
|
|
* action, page address, direction, physical address
|
4871 |
|
|
* and pointer to a configuration page header
|
4872 |
|
|
* Page header is updated.
|
4873 |
|
|
*
|
4874 |
|
|
* Returns 0 for success
|
4875 |
|
|
* -EPERM if not allowed due to ISR context
|
4876 |
|
|
* -EAGAIN if no msg frames currently available
|
4877 |
|
|
* -EFAULT for non-successful reply or no reply (timeout)
|
4878 |
|
|
*/
|
4879 |
|
|
int
|
4880 |
|
|
mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
|
4881 |
|
|
{
|
4882 |
|
|
Config_t *pReq;
|
4883 |
|
|
MPT_FRAME_HDR *mf;
|
4884 |
|
|
unsigned long flags;
|
4885 |
|
|
int ii, rc;
|
4886 |
|
|
int flagsLength;
|
4887 |
|
|
int in_isr;
|
4888 |
|
|
|
4889 |
|
|
/* (Bugzilla:fibrebugs, #513)
|
4890 |
|
|
* Bug fix (part 1)! 20010905 -sralston
|
4891 |
|
|
* Prevent calling wait_event() (below), if caller happens
|
4892 |
|
|
* to be in ISR context, because that is fatal!
|
4893 |
|
|
*/
|
4894 |
|
|
in_isr = in_interrupt();
|
4895 |
|
|
if (in_isr) {
|
4896 |
|
|
dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
|
4897 |
|
|
ioc->name));
|
4898 |
|
|
return -EPERM;
|
4899 |
|
|
}
|
4900 |
|
|
|
4901 |
|
|
/* Get and Populate a free Frame
|
4902 |
|
|
*/
|
4903 |
|
|
if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
|
4904 |
|
|
dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
|
4905 |
|
|
ioc->name));
|
4906 |
|
|
return -EAGAIN;
|
4907 |
|
|
}
|
4908 |
|
|
pReq = (Config_t *)mf;
|
4909 |
|
|
pReq->Action = pCfg->action;
|
4910 |
|
|
pReq->Reserved = 0;
|
4911 |
|
|
pReq->ChainOffset = 0;
|
4912 |
|
|
pReq->Function = MPI_FUNCTION_CONFIG;
|
4913 |
|
|
pReq->Reserved1[0] = 0;
|
4914 |
|
|
pReq->Reserved1[1] = 0;
|
4915 |
|
|
pReq->Reserved1[2] = 0;
|
4916 |
|
|
pReq->MsgFlags = 0;
|
4917 |
|
|
for (ii=0; ii < 8; ii++)
|
4918 |
|
|
pReq->Reserved2[ii] = 0;
|
4919 |
|
|
|
4920 |
|
|
pReq->Header.PageVersion = pCfg->hdr->PageVersion;
|
4921 |
|
|
pReq->Header.PageLength = pCfg->hdr->PageLength;
|
4922 |
|
|
pReq->Header.PageNumber = pCfg->hdr->PageNumber;
|
4923 |
|
|
pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
|
4924 |
|
|
pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
|
4925 |
|
|
|
4926 |
|
|
/* Add a SGE to the config request.
|
4927 |
|
|
*/
|
4928 |
|
|
if (pCfg->dir)
|
4929 |
|
|
flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
|
4930 |
|
|
else
|
4931 |
|
|
flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
|
4932 |
|
|
|
4933 |
|
|
flagsLength |= pCfg->hdr->PageLength * 4;
|
4934 |
|
|
|
4935 |
|
|
mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
|
4936 |
|
|
|
4937 |
|
|
dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
|
4938 |
|
|
ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
|
4939 |
|
|
|
4940 |
|
|
/* Append pCfg pointer to end of mf
|
4941 |
|
|
*/
|
4942 |
|
|
*((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
|
4943 |
|
|
|
4944 |
|
|
/* Initalize the timer
|
4945 |
|
|
*/
|
4946 |
|
|
init_timer(&pCfg->timer);
|
4947 |
|
|
pCfg->timer.data = (unsigned long) ioc;
|
4948 |
|
|
pCfg->timer.function = mpt_timer_expired;
|
4949 |
|
|
pCfg->wait_done = 0;
|
4950 |
|
|
|
4951 |
|
|
/* Set the timer; ensure 10 second minimum */
|
4952 |
|
|
if (pCfg->timeout < 10)
|
4953 |
|
|
pCfg->timer.expires = jiffies + HZ*10;
|
4954 |
|
|
else
|
4955 |
|
|
pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
|
4956 |
|
|
|
4957 |
|
|
/* Add to end of Q, set timer and then issue this command */
|
4958 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
4959 |
|
|
Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM);
|
4960 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
4961 |
|
|
|
4962 |
|
|
add_timer(&pCfg->timer);
|
4963 |
|
|
mpt_put_msg_frame(mpt_base_index, ioc->id, mf);
|
4964 |
|
|
wait_event(mpt_waitq, pCfg->wait_done);
|
4965 |
|
|
|
4966 |
|
|
/* mf has been freed - do not access */
|
4967 |
|
|
|
4968 |
|
|
rc = pCfg->status;
|
4969 |
|
|
|
4970 |
|
|
return rc;
|
4971 |
|
|
}
|
4972 |
|
|
|
4973 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4974 |
|
|
/*
|
4975 |
|
|
* mpt_timer_expired - Call back for timer process.
|
4976 |
|
|
* Used only internal config functionality.
|
4977 |
|
|
* @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
|
4978 |
|
|
*/
|
4979 |
|
|
static void
|
4980 |
|
|
mpt_timer_expired(unsigned long data)
|
4981 |
|
|
{
|
4982 |
|
|
MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
|
4983 |
|
|
|
4984 |
|
|
dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
|
4985 |
|
|
|
4986 |
|
|
/* Perform a FW reload */
|
4987 |
|
|
if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
|
4988 |
|
|
printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
|
4989 |
|
|
|
4990 |
|
|
/* No more processing.
|
4991 |
|
|
* Hard reset clean-up will wake up
|
4992 |
|
|
* process and free all resources.
|
4993 |
|
|
*/
|
4994 |
|
|
dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
|
4995 |
|
|
|
4996 |
|
|
return;
|
4997 |
|
|
}
|
4998 |
|
|
|
4999 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5000 |
|
|
/*
|
5001 |
|
|
* mpt_ioc_reset - Base cleanup for hard reset
|
5002 |
|
|
* @ioc: Pointer to the adapter structure
|
5003 |
|
|
* @reset_phase: Indicates pre- or post-reset functionality
|
5004 |
|
|
*
|
5005 |
|
|
* Remark: Free's resources with internally generated commands.
|
5006 |
|
|
*/
|
5007 |
|
|
static int
|
5008 |
|
|
mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
|
5009 |
|
|
{
|
5010 |
|
|
CONFIGPARMS *pCfg;
|
5011 |
|
|
unsigned long flags;
|
5012 |
|
|
|
5013 |
|
|
dprintk((KERN_WARNING MYNAM
|
5014 |
|
|
": IOC %s_reset routed to MPT base driver!\n",
|
5015 |
|
|
reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
|
5016 |
|
|
reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
|
5017 |
|
|
|
5018 |
|
|
if (reset_phase == MPT_IOC_SETUP_RESET) {
|
5019 |
|
|
;
|
5020 |
|
|
} else if (reset_phase == MPT_IOC_PRE_RESET) {
|
5021 |
|
|
/* If the internal config Q is not empty -
|
5022 |
|
|
* delete timer. MF resources will be freed when
|
5023 |
|
|
* the FIFO's are primed.
|
5024 |
|
|
*/
|
5025 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
5026 |
|
|
if (! Q_IS_EMPTY(&ioc->configQ)){
|
5027 |
|
|
pCfg = (CONFIGPARMS *)ioc->configQ.head;
|
5028 |
|
|
do {
|
5029 |
|
|
del_timer(&pCfg->timer);
|
5030 |
|
|
pCfg = (CONFIGPARMS *) (pCfg->linkage.forw);
|
5031 |
|
|
} while (pCfg != (CONFIGPARMS *)&ioc->configQ);
|
5032 |
|
|
}
|
5033 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
5034 |
|
|
|
5035 |
|
|
} else {
|
5036 |
|
|
CONFIGPARMS *pNext;
|
5037 |
|
|
|
5038 |
|
|
/* Search the configQ for internal commands.
|
5039 |
|
|
* Flush the Q, and wake up all suspended threads.
|
5040 |
|
|
*/
|
5041 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
5042 |
|
|
if (! Q_IS_EMPTY(&ioc->configQ)){
|
5043 |
|
|
pCfg = (CONFIGPARMS *)ioc->configQ.head;
|
5044 |
|
|
do {
|
5045 |
|
|
pNext = (CONFIGPARMS *) pCfg->linkage.forw;
|
5046 |
|
|
|
5047 |
|
|
Q_DEL_ITEM(&pCfg->linkage);
|
5048 |
|
|
|
5049 |
|
|
pCfg->status = MPT_CONFIG_ERROR;
|
5050 |
|
|
pCfg->wait_done = 1;
|
5051 |
|
|
wake_up(&mpt_waitq);
|
5052 |
|
|
|
5053 |
|
|
pCfg = pNext;
|
5054 |
|
|
} while (pCfg != (CONFIGPARMS *)&ioc->configQ);
|
5055 |
|
|
}
|
5056 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
5057 |
|
|
}
|
5058 |
|
|
|
5059 |
|
|
return 1; /* currently means nothing really */
|
5060 |
|
|
}
|
5061 |
|
|
|
5062 |
|
|
|
5063 |
|
|
#ifdef CONFIG_PROC_FS /* { */
|
5064 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5065 |
|
|
/*
|
5066 |
|
|
* procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
|
5067 |
|
|
*/
|
5068 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5069 |
|
|
/*
|
5070 |
|
|
* procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
|
5071 |
|
|
*
|
5072 |
|
|
* Returns 0 for success, non-zero for failure.
|
5073 |
|
|
*/
|
5074 |
|
|
static int
|
5075 |
|
|
procmpt_create(void)
|
5076 |
|
|
{
|
5077 |
|
|
MPT_ADAPTER *ioc;
|
5078 |
|
|
struct proc_dir_entry *ent;
|
5079 |
|
|
int ii;
|
5080 |
|
|
|
5081 |
|
|
/*
|
5082 |
|
|
* BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
|
5083 |
|
|
* (single level) to multi level (e.g. "driver/message/fusion")
|
5084 |
|
|
* something here needs to change. -sralston
|
5085 |
|
|
*/
|
5086 |
|
|
mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
|
5087 |
|
|
if (mpt_proc_root_dir == NULL)
|
5088 |
|
|
return -ENOTDIR;
|
5089 |
|
|
|
5090 |
|
|
for (ii=0; ii < MPT_PROC_ENTRIES; ii++) {
|
5091 |
|
|
ent = create_proc_entry(mpt_proc_list[ii].name,
|
5092 |
|
|
S_IFREG|S_IRUGO, mpt_proc_root_dir);
|
5093 |
|
|
if (!ent) {
|
5094 |
|
|
printk(KERN_WARNING MYNAM
|
5095 |
|
|
": WARNING - Could not create /proc/mpt/%s entry\n",
|
5096 |
|
|
mpt_proc_list[ii].name);
|
5097 |
|
|
continue;
|
5098 |
|
|
}
|
5099 |
|
|
ent->read_proc = mpt_proc_list[ii].f;
|
5100 |
|
|
ent->data = NULL;
|
5101 |
|
|
}
|
5102 |
|
|
|
5103 |
|
|
ioc = mpt_adapter_find_first();
|
5104 |
|
|
while (ioc != NULL) {
|
5105 |
|
|
struct proc_dir_entry *dent;
|
5106 |
|
|
/*
|
5107 |
|
|
* Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
|
5108 |
|
|
*/
|
5109 |
|
|
if ((dent = proc_mkdir(ioc->name, mpt_proc_root_dir)) != NULL) {
|
5110 |
|
|
/*
|
5111 |
|
|
* And populate it with mpt_ioc_proc_list[] entries.
|
5112 |
|
|
*/
|
5113 |
|
|
for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
|
5114 |
|
|
ent = create_proc_entry(mpt_ioc_proc_list[ii].name,
|
5115 |
|
|
S_IFREG|S_IRUGO, dent);
|
5116 |
|
|
if (!ent) {
|
5117 |
|
|
printk(KERN_WARNING MYNAM
|
5118 |
|
|
": WARNING - Could not create /proc/mpt/%s/%s entry!\n",
|
5119 |
|
|
ioc->name,
|
5120 |
|
|
mpt_ioc_proc_list[ii].name);
|
5121 |
|
|
continue;
|
5122 |
|
|
}
|
5123 |
|
|
ent->read_proc = mpt_ioc_proc_list[ii].f;
|
5124 |
|
|
ent->data = ioc;
|
5125 |
|
|
}
|
5126 |
|
|
} else {
|
5127 |
|
|
printk(MYIOC_s_WARN_FMT "Could not create /proc/mpt/%s subdir entry!\n",
|
5128 |
|
|
ioc->name, mpt_ioc_proc_list[ii].name);
|
5129 |
|
|
}
|
5130 |
|
|
ioc = mpt_adapter_find_next(ioc);
|
5131 |
|
|
}
|
5132 |
|
|
|
5133 |
|
|
return 0;
|
5134 |
|
|
}
|
5135 |
|
|
|
5136 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5137 |
|
|
/*
|
5138 |
|
|
* procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
|
5139 |
|
|
*
|
5140 |
|
|
* Returns 0 for success, non-zero for failure.
|
5141 |
|
|
*/
|
5142 |
|
|
static int
|
5143 |
|
|
procmpt_destroy(void)
|
5144 |
|
|
{
|
5145 |
|
|
MPT_ADAPTER *ioc;
|
5146 |
|
|
int ii;
|
5147 |
|
|
|
5148 |
|
|
if (!mpt_proc_root_dir)
|
5149 |
|
|
return 0;
|
5150 |
|
|
|
5151 |
|
|
/*
|
5152 |
|
|
* BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
|
5153 |
|
|
* (single level) to multi level (e.g. "driver/message/fusion")
|
5154 |
|
|
* something here needs to change. -sralston
|
5155 |
|
|
*/
|
5156 |
|
|
|
5157 |
|
|
ioc = mpt_adapter_find_first();
|
5158 |
|
|
while (ioc != NULL) {
|
5159 |
|
|
char pname[32];
|
5160 |
|
|
int namelen;
|
5161 |
|
|
|
5162 |
|
|
namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
|
5163 |
|
|
|
5164 |
|
|
/*
|
5165 |
|
|
* Tear down each "/proc/mpt/iocN" subdirectory.
|
5166 |
|
|
*/
|
5167 |
|
|
for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
|
5168 |
|
|
(void) sprintf(pname+namelen, "/%s", mpt_ioc_proc_list[ii].name);
|
5169 |
|
|
remove_proc_entry(pname, NULL);
|
5170 |
|
|
}
|
5171 |
|
|
|
5172 |
|
|
remove_proc_entry(ioc->name, mpt_proc_root_dir);
|
5173 |
|
|
|
5174 |
|
|
ioc = mpt_adapter_find_next(ioc);
|
5175 |
|
|
}
|
5176 |
|
|
|
5177 |
|
|
for (ii=0; ii < MPT_PROC_ENTRIES; ii++)
|
5178 |
|
|
remove_proc_entry(mpt_proc_list[ii].name, mpt_proc_root_dir);
|
5179 |
|
|
|
5180 |
|
|
if (atomic_read((atomic_t *)&mpt_proc_root_dir->count) == 0) {
|
5181 |
|
|
remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
|
5182 |
|
|
mpt_proc_root_dir = NULL;
|
5183 |
|
|
return 0;
|
5184 |
|
|
}
|
5185 |
|
|
|
5186 |
|
|
return -1;
|
5187 |
|
|
}
|
5188 |
|
|
|
5189 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5190 |
|
|
/*
|
5191 |
|
|
* procmpt_summary_read - Handle read request from /proc/mpt/summary
|
5192 |
|
|
* or from /proc/mpt/iocN/summary.
|
5193 |
|
|
* @buf: Pointer to area to write information
|
5194 |
|
|
* @start: Pointer to start pointer
|
5195 |
|
|
* @offset: Offset to start writing
|
5196 |
|
|
* @request:
|
5197 |
|
|
* @eof: Pointer to EOF integer
|
5198 |
|
|
* @data: Pointer
|
5199 |
|
|
*
|
5200 |
|
|
* Returns number of characters written to process performing the read.
|
5201 |
|
|
*/
|
5202 |
|
|
static int
|
5203 |
|
|
procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
|
5204 |
|
|
{
|
5205 |
|
|
MPT_ADAPTER *ioc;
|
5206 |
|
|
char *out = buf;
|
5207 |
|
|
int len;
|
5208 |
|
|
|
5209 |
|
|
if (data == NULL)
|
5210 |
|
|
ioc = mpt_adapter_find_first();
|
5211 |
|
|
else
|
5212 |
|
|
ioc = data;
|
5213 |
|
|
|
5214 |
|
|
while (ioc) {
|
5215 |
|
|
int more = 0;
|
5216 |
|
|
|
5217 |
|
|
mpt_print_ioc_summary(ioc, out, &more, 0, 1);
|
5218 |
|
|
|
5219 |
|
|
out += more;
|
5220 |
|
|
if ((out-buf) >= request) {
|
5221 |
|
|
break;
|
5222 |
|
|
}
|
5223 |
|
|
|
5224 |
|
|
if (data == NULL)
|
5225 |
|
|
ioc = mpt_adapter_find_next(ioc);
|
5226 |
|
|
else
|
5227 |
|
|
ioc = NULL; /* force exit for iocN */
|
5228 |
|
|
}
|
5229 |
|
|
len = out - buf;
|
5230 |
|
|
|
5231 |
|
|
MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
|
5232 |
|
|
}
|
5233 |
|
|
|
5234 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5235 |
|
|
/*
|
5236 |
|
|
* procmpt_version_read - Handle read request from /proc/mpt/version.
|
5237 |
|
|
* @buf: Pointer to area to write information
|
5238 |
|
|
* @start: Pointer to start pointer
|
5239 |
|
|
* @offset: Offset to start writing
|
5240 |
|
|
* @request:
|
5241 |
|
|
* @eof: Pointer to EOF integer
|
5242 |
|
|
* @data: Pointer
|
5243 |
|
|
*
|
5244 |
|
|
* Returns number of characters written to process performing the read.
|
5245 |
|
|
*/
|
5246 |
|
|
static int
|
5247 |
|
|
procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
|
5248 |
|
|
{
|
5249 |
|
|
int ii;
|
5250 |
|
|
int scsi, lan, ctl, targ, dmp;
|
5251 |
|
|
char *drvname;
|
5252 |
|
|
int len;
|
5253 |
|
|
|
5254 |
|
|
len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
|
5255 |
|
|
len += sprintf(buf+len, " Fusion MPT base driver\n");
|
5256 |
|
|
|
5257 |
|
|
scsi = lan = ctl = targ = dmp = 0;
|
5258 |
|
|
for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
|
5259 |
|
|
drvname = NULL;
|
5260 |
|
|
if (MptCallbacks[ii]) {
|
5261 |
|
|
switch (MptDriverClass[ii]) {
|
5262 |
|
|
case MPTSCSIH_DRIVER:
|
5263 |
|
|
if (!scsi++) drvname = "SCSI host";
|
5264 |
|
|
break;
|
5265 |
|
|
case MPTLAN_DRIVER:
|
5266 |
|
|
if (!lan++) drvname = "LAN";
|
5267 |
|
|
break;
|
5268 |
|
|
case MPTSTM_DRIVER:
|
5269 |
|
|
if (!targ++) drvname = "SCSI target";
|
5270 |
|
|
break;
|
5271 |
|
|
case MPTCTL_DRIVER:
|
5272 |
|
|
if (!ctl++) drvname = "ioctl";
|
5273 |
|
|
break;
|
5274 |
|
|
case MPTDMP_DRIVER:
|
5275 |
|
|
if (!dmp++) drvname = "DMP";
|
5276 |
|
|
break;
|
5277 |
|
|
}
|
5278 |
|
|
|
5279 |
|
|
if (drvname)
|
5280 |
|
|
len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
|
5281 |
|
|
/*
|
5282 |
|
|
* Handle isense special case, because it
|
5283 |
|
|
* doesn't do a formal mpt_register call.
|
5284 |
|
|
*/
|
5285 |
|
|
if (isense_idx == ii)
|
5286 |
|
|
len += sprintf(buf+len, " Fusion MPT isense driver\n");
|
5287 |
|
|
}
|
5288 |
|
|
}
|
5289 |
|
|
|
5290 |
|
|
MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
|
5291 |
|
|
}
|
5292 |
|
|
|
5293 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5294 |
|
|
/*
|
5295 |
|
|
* procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
|
5296 |
|
|
* @buf: Pointer to area to write information
|
5297 |
|
|
* @start: Pointer to start pointer
|
5298 |
|
|
* @offset: Offset to start writing
|
5299 |
|
|
* @request:
|
5300 |
|
|
* @eof: Pointer to EOF integer
|
5301 |
|
|
* @data: Pointer
|
5302 |
|
|
*
|
5303 |
|
|
* Returns number of characters written to process performing the read.
|
5304 |
|
|
*/
|
5305 |
|
|
static int
|
5306 |
|
|
procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
|
5307 |
|
|
{
|
5308 |
|
|
MPT_ADAPTER *ioc = data;
|
5309 |
|
|
int len;
|
5310 |
|
|
char expVer[32];
|
5311 |
|
|
int sz;
|
5312 |
|
|
int p;
|
5313 |
|
|
|
5314 |
|
|
mpt_get_fw_exp_ver(expVer, ioc);
|
5315 |
|
|
|
5316 |
|
|
len = sprintf(buf, "%s:", ioc->name);
|
5317 |
|
|
if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
|
5318 |
|
|
len += sprintf(buf+len, " (f/w download boot flag set)");
|
5319 |
|
|
// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
|
5320 |
|
|
// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
|
5321 |
|
|
|
5322 |
|
|
len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
|
5323 |
|
|
ioc->facts.ProductID,
|
5324 |
|
|
ioc->prod_name);
|
5325 |
|
|
len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
|
5326 |
|
|
if (ioc->facts.FWImageSize)
|
5327 |
|
|
len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
|
5328 |
|
|
len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
|
5329 |
|
|
len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
|
5330 |
|
|
len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
|
5331 |
|
|
|
5332 |
|
|
len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
|
5333 |
|
|
ioc->facts.CurrentHostMfaHighAddr);
|
5334 |
|
|
len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
|
5335 |
|
|
ioc->facts.CurrentSenseBufferHighAddr);
|
5336 |
|
|
|
5337 |
|
|
len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
|
5338 |
|
|
len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
|
5339 |
|
|
|
5340 |
|
|
len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
|
5341 |
|
|
(void *)ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma);
|
5342 |
|
|
/*
|
5343 |
|
|
* Rounding UP to nearest 4-kB boundary here...
|
5344 |
|
|
*/
|
5345 |
|
|
sz = (ioc->req_sz * ioc->req_depth) + 128;
|
5346 |
|
|
sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
|
5347 |
|
|
len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
|
5348 |
|
|
ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
|
5349 |
|
|
len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
|
5350 |
|
|
4*ioc->facts.RequestFrameSize,
|
5351 |
|
|
ioc->facts.GlobalCredits);
|
5352 |
|
|
|
5353 |
|
|
len += sprintf(buf+len, " ReplyFrames @ 0x%p (Dma @ 0x%p)\n",
|
5354 |
|
|
(void *)ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma);
|
5355 |
|
|
sz = (ioc->reply_sz * ioc->reply_depth) + 128;
|
5356 |
|
|
len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
|
5357 |
|
|
ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
|
5358 |
|
|
len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
|
5359 |
|
|
ioc->facts.CurReplyFrameSize,
|
5360 |
|
|
ioc->facts.ReplyQueueDepth);
|
5361 |
|
|
|
5362 |
|
|
len += sprintf(buf+len, " MaxDevices = %d\n",
|
5363 |
|
|
(ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
|
5364 |
|
|
len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
|
5365 |
|
|
|
5366 |
|
|
/* per-port info */
|
5367 |
|
|
for (p=0; p < ioc->facts.NumberOfPorts; p++) {
|
5368 |
|
|
len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
|
5369 |
|
|
p+1,
|
5370 |
|
|
ioc->facts.NumberOfPorts);
|
5371 |
|
|
if ((int)ioc->chip_type <= (int)FC929) {
|
5372 |
|
|
if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
|
5373 |
|
|
u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
|
5374 |
|
|
len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
|
5375 |
|
|
a[5], a[4], a[3], a[2], a[1], a[0]);
|
5376 |
|
|
}
|
5377 |
|
|
len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
|
5378 |
|
|
ioc->fc_port_page0[p].WWNN.High,
|
5379 |
|
|
ioc->fc_port_page0[p].WWNN.Low,
|
5380 |
|
|
ioc->fc_port_page0[p].WWPN.High,
|
5381 |
|
|
ioc->fc_port_page0[p].WWPN.Low);
|
5382 |
|
|
}
|
5383 |
|
|
}
|
5384 |
|
|
|
5385 |
|
|
MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
|
5386 |
|
|
}
|
5387 |
|
|
|
5388 |
|
|
#endif /* CONFIG_PROC_FS } */
|
5389 |
|
|
|
5390 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5391 |
|
|
static void
|
5392 |
|
|
mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
|
5393 |
|
|
{
|
5394 |
|
|
buf[0] ='\0';
|
5395 |
|
|
if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
|
5396 |
|
|
sprintf(buf, " (Exp %02d%02d)",
|
5397 |
|
|
(ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
|
5398 |
|
|
(ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
|
5399 |
|
|
|
5400 |
|
|
/* insider hack! */
|
5401 |
|
|
if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
|
5402 |
|
|
strcat(buf, " [MDBG]");
|
5403 |
|
|
}
|
5404 |
|
|
}
|
5405 |
|
|
|
5406 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5407 |
|
|
/**
|
5408 |
|
|
* mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
|
5409 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
5410 |
|
|
* @buffer: Pointer to buffer where IOC summary info should be written
|
5411 |
|
|
* @size: Pointer to number of bytes we wrote (set by this routine)
|
5412 |
|
|
* @len: Offset at which to start writing in buffer
|
5413 |
|
|
* @showlan: Display LAN stuff?
|
5414 |
|
|
*
|
5415 |
|
|
* This routine writes (english readable) ASCII text, which represents
|
5416 |
|
|
* a summary of IOC information, to a buffer.
|
5417 |
|
|
*/
|
5418 |
|
|
void
|
5419 |
|
|
mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
|
5420 |
|
|
{
|
5421 |
|
|
char expVer[32];
|
5422 |
|
|
int y;
|
5423 |
|
|
|
5424 |
|
|
mpt_get_fw_exp_ver(expVer, ioc);
|
5425 |
|
|
|
5426 |
|
|
/*
|
5427 |
|
|
* Shorter summary of attached ioc's...
|
5428 |
|
|
*/
|
5429 |
|
|
y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
|
5430 |
|
|
ioc->name,
|
5431 |
|
|
ioc->prod_name,
|
5432 |
|
|
MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
|
5433 |
|
|
ioc->facts.FWVersion.Word,
|
5434 |
|
|
expVer,
|
5435 |
|
|
ioc->facts.NumberOfPorts,
|
5436 |
|
|
ioc->req_depth);
|
5437 |
|
|
|
5438 |
|
|
if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
|
5439 |
|
|
u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
|
5440 |
|
|
y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
|
5441 |
|
|
a[5], a[4], a[3], a[2], a[1], a[0]);
|
5442 |
|
|
}
|
5443 |
|
|
|
5444 |
|
|
#ifndef __sparc__
|
5445 |
|
|
y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
|
5446 |
|
|
#else
|
5447 |
|
|
y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
|
5448 |
|
|
#endif
|
5449 |
|
|
|
5450 |
|
|
if (!ioc->active)
|
5451 |
|
|
y += sprintf(buffer+len+y, " (disabled)");
|
5452 |
|
|
|
5453 |
|
|
y += sprintf(buffer+len+y, "\n");
|
5454 |
|
|
|
5455 |
|
|
*size = y;
|
5456 |
|
|
}
|
5457 |
|
|
|
5458 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5459 |
|
|
/*
|
5460 |
|
|
* Reset Handling
|
5461 |
|
|
*/
|
5462 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5463 |
|
|
/**
|
5464 |
|
|
* mpt_HardResetHandler - Generic reset handler, issue SCSI Task
|
5465 |
|
|
* Management call based on input arg values. If TaskMgmt fails,
|
5466 |
|
|
* return associated SCSI request.
|
5467 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
5468 |
|
|
* @sleepFlag: Indicates if sleep or schedule must be called.
|
5469 |
|
|
*
|
5470 |
|
|
* Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
|
5471 |
|
|
* or a non-interrupt thread. In the former, must not call schedule().
|
5472 |
|
|
*
|
5473 |
|
|
* Remark: A return of -1 is a FATAL error case, as it means a
|
5474 |
|
|
* FW reload/initialization failed.
|
5475 |
|
|
*
|
5476 |
|
|
* Returns 0 for SUCCESS or -1 if FAILED.
|
5477 |
|
|
*/
|
5478 |
|
|
int
|
5479 |
|
|
mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
|
5480 |
|
|
{
|
5481 |
|
|
int rc;
|
5482 |
|
|
unsigned long flags;
|
5483 |
|
|
|
5484 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
|
5485 |
|
|
#ifdef MFCNT
|
5486 |
|
|
printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
|
5487 |
|
|
printk("MF count 0x%x !\n", ioc->mfcnt);
|
5488 |
|
|
#endif
|
5489 |
|
|
|
5490 |
|
|
/* Reset the adapter. Prevent more than 1 call to
|
5491 |
|
|
* mpt_do_ioc_recovery at any instant in time.
|
5492 |
|
|
*/
|
5493 |
|
|
spin_lock_irqsave(&ioc->diagLock, flags);
|
5494 |
|
|
if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
|
5495 |
|
|
spin_unlock_irqrestore(&ioc->diagLock, flags);
|
5496 |
|
|
return 0;
|
5497 |
|
|
} else {
|
5498 |
|
|
ioc->diagPending = 1;
|
5499 |
|
|
}
|
5500 |
|
|
spin_unlock_irqrestore(&ioc->diagLock, flags);
|
5501 |
|
|
|
5502 |
|
|
/* FIXME: If do_ioc_recovery fails, repeat....
|
5503 |
|
|
*/
|
5504 |
|
|
|
5505 |
|
|
/* The SCSI driver needs to adjust timeouts on all current
|
5506 |
|
|
* commands prior to the diagnostic reset being issued.
|
5507 |
|
|
* Prevents timeouts occuring during a diagnostic reset...very bad.
|
5508 |
|
|
* For all other protocol drivers, this is a no-op.
|
5509 |
|
|
*/
|
5510 |
|
|
{
|
5511 |
|
|
int ii;
|
5512 |
|
|
int r = 0;
|
5513 |
|
|
|
5514 |
|
|
for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
|
5515 |
|
|
if (MptResetHandlers[ii]) {
|
5516 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
|
5517 |
|
|
ioc->name, ii));
|
5518 |
|
|
r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
|
5519 |
|
|
if (ioc->alt_ioc) {
|
5520 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
|
5521 |
|
|
ioc->name, ioc->alt_ioc->name, ii));
|
5522 |
|
|
r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
|
5523 |
|
|
}
|
5524 |
|
|
}
|
5525 |
|
|
}
|
5526 |
|
|
}
|
5527 |
|
|
|
5528 |
|
|
if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
|
5529 |
|
|
printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
|
5530 |
|
|
rc, ioc->name);
|
5531 |
|
|
}
|
5532 |
|
|
ioc->reload_fw = 0;
|
5533 |
|
|
if (ioc->alt_ioc)
|
5534 |
|
|
ioc->alt_ioc->reload_fw = 0;
|
5535 |
|
|
|
5536 |
|
|
spin_lock_irqsave(&ioc->diagLock, flags);
|
5537 |
|
|
ioc->diagPending = 0;
|
5538 |
|
|
if (ioc->alt_ioc)
|
5539 |
|
|
ioc->alt_ioc->diagPending = 0;
|
5540 |
|
|
spin_unlock_irqrestore(&ioc->diagLock, flags);
|
5541 |
|
|
|
5542 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
|
5543 |
|
|
|
5544 |
|
|
return rc;
|
5545 |
|
|
}
|
5546 |
|
|
|
5547 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5548 |
|
|
static char *
|
5549 |
|
|
EventDescriptionStr(u8 event, u32 evData0)
|
5550 |
|
|
{
|
5551 |
|
|
char *ds;
|
5552 |
|
|
|
5553 |
|
|
switch(event) {
|
5554 |
|
|
case MPI_EVENT_NONE:
|
5555 |
|
|
ds = "None";
|
5556 |
|
|
break;
|
5557 |
|
|
case MPI_EVENT_LOG_DATA:
|
5558 |
|
|
ds = "Log Data";
|
5559 |
|
|
break;
|
5560 |
|
|
case MPI_EVENT_STATE_CHANGE:
|
5561 |
|
|
ds = "State Change";
|
5562 |
|
|
break;
|
5563 |
|
|
case MPI_EVENT_UNIT_ATTENTION:
|
5564 |
|
|
ds = "Unit Attention";
|
5565 |
|
|
break;
|
5566 |
|
|
case MPI_EVENT_IOC_BUS_RESET:
|
5567 |
|
|
ds = "IOC Bus Reset";
|
5568 |
|
|
break;
|
5569 |
|
|
case MPI_EVENT_EXT_BUS_RESET:
|
5570 |
|
|
ds = "External Bus Reset";
|
5571 |
|
|
break;
|
5572 |
|
|
case MPI_EVENT_RESCAN:
|
5573 |
|
|
ds = "Bus Rescan Event";
|
5574 |
|
|
/* Ok, do we need to do anything here? As far as
|
5575 |
|
|
I can tell, this is when a new device gets added
|
5576 |
|
|
to the loop. */
|
5577 |
|
|
break;
|
5578 |
|
|
case MPI_EVENT_LINK_STATUS_CHANGE:
|
5579 |
|
|
if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
|
5580 |
|
|
ds = "Link Status(FAILURE) Change";
|
5581 |
|
|
else
|
5582 |
|
|
ds = "Link Status(ACTIVE) Change";
|
5583 |
|
|
break;
|
5584 |
|
|
case MPI_EVENT_LOOP_STATE_CHANGE:
|
5585 |
|
|
if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
|
5586 |
|
|
ds = "Loop State(LIP) Change";
|
5587 |
|
|
else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
|
5588 |
|
|
ds = "Loop State(LPE) Change"; /* ??? */
|
5589 |
|
|
else
|
5590 |
|
|
ds = "Loop State(LPB) Change"; /* ??? */
|
5591 |
|
|
break;
|
5592 |
|
|
case MPI_EVENT_LOGOUT:
|
5593 |
|
|
ds = "Logout";
|
5594 |
|
|
break;
|
5595 |
|
|
case MPI_EVENT_EVENT_CHANGE:
|
5596 |
|
|
if (evData0)
|
5597 |
|
|
ds = "Events(ON) Change";
|
5598 |
|
|
else
|
5599 |
|
|
ds = "Events(OFF) Change";
|
5600 |
|
|
break;
|
5601 |
|
|
case MPI_EVENT_INTEGRATED_RAID:
|
5602 |
|
|
ds = "Integrated Raid";
|
5603 |
|
|
break;
|
5604 |
|
|
/*
|
5605 |
|
|
* MPT base "custom" events may be added here...
|
5606 |
|
|
*/
|
5607 |
|
|
default:
|
5608 |
|
|
ds = "Unknown";
|
5609 |
|
|
break;
|
5610 |
|
|
}
|
5611 |
|
|
return ds;
|
5612 |
|
|
}
|
5613 |
|
|
|
5614 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5615 |
|
|
/*
|
5616 |
|
|
* ProcessEventNotification - Route a received EventNotificationReply to
|
5617 |
|
|
* all currently regeistered event handlers.
|
5618 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
5619 |
|
|
* @pEventReply: Pointer to EventNotification reply frame
|
5620 |
|
|
* @evHandlers: Pointer to integer, number of event handlers
|
5621 |
|
|
*
|
5622 |
|
|
* Returns sum of event handlers return values.
|
5623 |
|
|
*/
|
5624 |
|
|
static int
|
5625 |
|
|
ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
|
5626 |
|
|
{
|
5627 |
|
|
u16 evDataLen;
|
5628 |
|
|
u32 evData0 = 0;
|
5629 |
|
|
// u32 evCtx;
|
5630 |
|
|
int ii;
|
5631 |
|
|
int r = 0;
|
5632 |
|
|
int handlers = 0;
|
5633 |
|
|
char *evStr;
|
5634 |
|
|
u8 event;
|
5635 |
|
|
|
5636 |
|
|
/*
|
5637 |
|
|
* Do platform normalization of values
|
5638 |
|
|
*/
|
5639 |
|
|
event = le32_to_cpu(pEventReply->Event) & 0xFF;
|
5640 |
|
|
// evCtx = le32_to_cpu(pEventReply->EventContext);
|
5641 |
|
|
evDataLen = le16_to_cpu(pEventReply->EventDataLength);
|
5642 |
|
|
if (evDataLen) {
|
5643 |
|
|
evData0 = le32_to_cpu(pEventReply->Data[0]);
|
5644 |
|
|
}
|
5645 |
|
|
|
5646 |
|
|
evStr = EventDescriptionStr(event, evData0);
|
5647 |
|
|
dprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
|
5648 |
|
|
ioc->name,
|
5649 |
|
|
evStr,
|
5650 |
|
|
event));
|
5651 |
|
|
|
5652 |
|
|
#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
|
5653 |
|
|
printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
|
5654 |
|
|
for (ii = 0; ii < evDataLen; ii++)
|
5655 |
|
|
printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
|
5656 |
|
|
printk("\n");
|
5657 |
|
|
#endif
|
5658 |
|
|
|
5659 |
|
|
/*
|
5660 |
|
|
* Do general / base driver event processing
|
5661 |
|
|
*/
|
5662 |
|
|
switch(event) {
|
5663 |
|
|
case MPI_EVENT_NONE: /* 00 */
|
5664 |
|
|
case MPI_EVENT_LOG_DATA: /* 01 */
|
5665 |
|
|
case MPI_EVENT_STATE_CHANGE: /* 02 */
|
5666 |
|
|
case MPI_EVENT_UNIT_ATTENTION: /* 03 */
|
5667 |
|
|
case MPI_EVENT_IOC_BUS_RESET: /* 04 */
|
5668 |
|
|
case MPI_EVENT_EXT_BUS_RESET: /* 05 */
|
5669 |
|
|
case MPI_EVENT_RESCAN: /* 06 */
|
5670 |
|
|
case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
|
5671 |
|
|
case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
|
5672 |
|
|
case MPI_EVENT_LOGOUT: /* 09 */
|
5673 |
|
|
case MPI_EVENT_INTEGRATED_RAID: /* 0B */
|
5674 |
|
|
case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: /* 0C */
|
5675 |
|
|
default:
|
5676 |
|
|
break;
|
5677 |
|
|
case MPI_EVENT_EVENT_CHANGE: /* 0A */
|
5678 |
|
|
if (evDataLen) {
|
5679 |
|
|
u8 evState = evData0 & 0xFF;
|
5680 |
|
|
|
5681 |
|
|
/* CHECKME! What if evState unexpectedly says OFF (0)? */
|
5682 |
|
|
|
5683 |
|
|
/* Update EventState field in cached IocFacts */
|
5684 |
|
|
if (ioc->facts.Function) {
|
5685 |
|
|
ioc->facts.EventState = evState;
|
5686 |
|
|
}
|
5687 |
|
|
}
|
5688 |
|
|
break;
|
5689 |
|
|
}
|
5690 |
|
|
|
5691 |
|
|
/*
|
5692 |
|
|
* Should this event be logged? Events are written sequentially.
|
5693 |
|
|
* When buffer is full, start again at the top.
|
5694 |
|
|
*/
|
5695 |
|
|
if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
|
5696 |
|
|
int idx;
|
5697 |
|
|
|
5698 |
|
|
idx = ioc->eventContext % ioc->eventLogSize;
|
5699 |
|
|
|
5700 |
|
|
ioc->events[idx].event = event;
|
5701 |
|
|
ioc->events[idx].eventContext = ioc->eventContext;
|
5702 |
|
|
|
5703 |
|
|
for (ii = 0; ii < 2; ii++) {
|
5704 |
|
|
if (ii < evDataLen)
|
5705 |
|
|
ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
|
5706 |
|
|
else
|
5707 |
|
|
ioc->events[idx].data[ii] = 0;
|
5708 |
|
|
}
|
5709 |
|
|
|
5710 |
|
|
ioc->eventContext++;
|
5711 |
|
|
}
|
5712 |
|
|
|
5713 |
|
|
|
5714 |
|
|
/*
|
5715 |
|
|
* Call each currently registered protocol event handler.
|
5716 |
|
|
*/
|
5717 |
|
|
for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
|
5718 |
|
|
if (MptEvHandlers[ii]) {
|
5719 |
|
|
dprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
|
5720 |
|
|
ioc->name, ii));
|
5721 |
|
|
r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
|
5722 |
|
|
handlers++;
|
5723 |
|
|
}
|
5724 |
|
|
}
|
5725 |
|
|
/* FIXME? Examine results here? */
|
5726 |
|
|
|
5727 |
|
|
/*
|
5728 |
|
|
* If needed, send (a single) EventAck.
|
5729 |
|
|
*/
|
5730 |
|
|
if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
|
5731 |
|
|
if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
|
5732 |
|
|
printk(MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
|
5733 |
|
|
ioc->name, ii);
|
5734 |
|
|
}
|
5735 |
|
|
}
|
5736 |
|
|
|
5737 |
|
|
*evHandlers = handlers;
|
5738 |
|
|
return r;
|
5739 |
|
|
}
|
5740 |
|
|
|
5741 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5742 |
|
|
/*
|
5743 |
|
|
* mpt_fc_log_info - Log information returned from Fibre Channel IOC.
|
5744 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
5745 |
|
|
* @log_info: U32 LogInfo reply word from the IOC
|
5746 |
|
|
*
|
5747 |
|
|
* Refer to lsi/fc_log.h.
|
5748 |
|
|
*/
|
5749 |
|
|
static void
|
5750 |
|
|
mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
|
5751 |
|
|
{
|
5752 |
|
|
static char *subcl_str[8] = {
|
5753 |
|
|
"FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
|
5754 |
|
|
"FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
|
5755 |
|
|
};
|
5756 |
|
|
char *desc = "unknown";
|
5757 |
|
|
u8 subcl = (log_info >> 24) & 0x7;
|
5758 |
|
|
u32 SubCl = log_info & 0x27000000;
|
5759 |
|
|
|
5760 |
|
|
switch(log_info) {
|
5761 |
|
|
/* FCP Initiator */
|
5762 |
|
|
case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
|
5763 |
|
|
desc = "Received an out of order frame - unsupported";
|
5764 |
|
|
break;
|
5765 |
|
|
case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME:
|
5766 |
|
|
desc = "Bad start of frame primative";
|
5767 |
|
|
break;
|
5768 |
|
|
case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME:
|
5769 |
|
|
desc = "Bad end of frame primative";
|
5770 |
|
|
break;
|
5771 |
|
|
case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN:
|
5772 |
|
|
desc = "Receiver hardware detected overrun";
|
5773 |
|
|
break;
|
5774 |
|
|
case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER:
|
5775 |
|
|
desc = "Other errors caught by IOC which require retries";
|
5776 |
|
|
break;
|
5777 |
|
|
case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD:
|
5778 |
|
|
desc = "Main processor could not initialize sub-processor";
|
5779 |
|
|
break;
|
5780 |
|
|
/* FC Target */
|
5781 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC:
|
5782 |
|
|
desc = "Not sent because we are waiting for a PDISC from the initiator";
|
5783 |
|
|
break;
|
5784 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN:
|
5785 |
|
|
desc = "Not sent because we are not logged in to the remote node";
|
5786 |
|
|
break;
|
5787 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP:
|
5788 |
|
|
desc = "Data Out, Auto Response, not sent due to a LIP";
|
5789 |
|
|
break;
|
5790 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP:
|
5791 |
|
|
desc = "Data In, Auto Response, not sent due to a LIP";
|
5792 |
|
|
break;
|
5793 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA:
|
5794 |
|
|
desc = "Data In, Auto Response, missing data frames";
|
5795 |
|
|
break;
|
5796 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP:
|
5797 |
|
|
desc = "Data Out, No Response, not sent due to a LIP";
|
5798 |
|
|
break;
|
5799 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP:
|
5800 |
|
|
desc = "Auto-response after a write not sent due to a LIP";
|
5801 |
|
|
break;
|
5802 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP:
|
5803 |
|
|
desc = "Data In, No Response, not completed due to a LIP";
|
5804 |
|
|
break;
|
5805 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA:
|
5806 |
|
|
desc = "Data In, No Response, missing data frames";
|
5807 |
|
|
break;
|
5808 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP:
|
5809 |
|
|
desc = "Manual Response not sent due to a LIP";
|
5810 |
|
|
break;
|
5811 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3:
|
5812 |
|
|
desc = "Not sent because remote node does not support Class 3";
|
5813 |
|
|
break;
|
5814 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID:
|
5815 |
|
|
desc = "Not sent because login to remote node not validated";
|
5816 |
|
|
break;
|
5817 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND:
|
5818 |
|
|
desc = "Cleared from the outbound queue after a logout";
|
5819 |
|
|
break;
|
5820 |
|
|
case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN:
|
5821 |
|
|
desc = "Cleared waiting for data after a logout";
|
5822 |
|
|
break;
|
5823 |
|
|
/* LAN */
|
5824 |
|
|
case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING:
|
5825 |
|
|
desc = "Transaction Context Sgl Missing";
|
5826 |
|
|
break;
|
5827 |
|
|
case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE:
|
5828 |
|
|
desc = "Transaction Context found before an EOB";
|
5829 |
|
|
break;
|
5830 |
|
|
case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET:
|
5831 |
|
|
desc = "Transaction Context value has reserved bits set";
|
5832 |
|
|
break;
|
5833 |
|
|
case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG:
|
5834 |
|
|
desc = "Invalid SGL Flags";
|
5835 |
|
|
break;
|
5836 |
|
|
/* FC Link */
|
5837 |
|
|
case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT:
|
5838 |
|
|
desc = "Loop initialization timed out";
|
5839 |
|
|
break;
|
5840 |
|
|
case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED:
|
5841 |
|
|
desc = "Another system controller already initialized the loop";
|
5842 |
|
|
break;
|
5843 |
|
|
case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED:
|
5844 |
|
|
desc = "Not synchronized to signal or still negotiating (possible cable problem)";
|
5845 |
|
|
break;
|
5846 |
|
|
case MPI_IOCLOGINFO_FC_LINK_CRC_ERROR:
|
5847 |
|
|
desc = "CRC check detected error on received frame";
|
5848 |
|
|
break;
|
5849 |
|
|
}
|
5850 |
|
|
|
5851 |
|
|
printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}",
|
5852 |
|
|
ioc->name, log_info, subcl_str[subcl]);
|
5853 |
|
|
if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET)
|
5854 |
|
|
printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET);
|
5855 |
|
|
else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE)
|
5856 |
|
|
printk("\n"); /* StateChg in LogInfo & 0x00FFFFFF, above */
|
5857 |
|
|
else
|
5858 |
|
|
printk("\n" KERN_INFO " %s\n", desc);
|
5859 |
|
|
}
|
5860 |
|
|
|
5861 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5862 |
|
|
/*
|
5863 |
|
|
* mpt_sp_log_info - Log information returned from SCSI Parallel IOC.
|
5864 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
5865 |
|
|
* @mr: Pointer to MPT reply frame
|
5866 |
|
|
* @log_info: U32 LogInfo word from the IOC
|
5867 |
|
|
*
|
5868 |
|
|
* Refer to lsi/sp_log.h.
|
5869 |
|
|
*/
|
5870 |
|
|
static void
|
5871 |
|
|
mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
|
5872 |
|
|
{
|
5873 |
|
|
u32 info = log_info & 0x00FF0000;
|
5874 |
|
|
char *desc = "unknown";
|
5875 |
|
|
|
5876 |
|
|
switch (info) {
|
5877 |
|
|
case 0x00010000:
|
5878 |
|
|
desc = "bug! MID not found";
|
5879 |
|
|
if (ioc->reload_fw == 0)
|
5880 |
|
|
ioc->reload_fw++;
|
5881 |
|
|
break;
|
5882 |
|
|
|
5883 |
|
|
case 0x00020000:
|
5884 |
|
|
desc = "Parity Error";
|
5885 |
|
|
break;
|
5886 |
|
|
|
5887 |
|
|
case 0x00030000:
|
5888 |
|
|
desc = "ASYNC Outbound Overrun";
|
5889 |
|
|
break;
|
5890 |
|
|
|
5891 |
|
|
case 0x00040000:
|
5892 |
|
|
desc = "SYNC Offset Error";
|
5893 |
|
|
break;
|
5894 |
|
|
|
5895 |
|
|
case 0x00050000:
|
5896 |
|
|
desc = "BM Change";
|
5897 |
|
|
break;
|
5898 |
|
|
|
5899 |
|
|
case 0x00060000:
|
5900 |
|
|
desc = "Msg In Overflow";
|
5901 |
|
|
break;
|
5902 |
|
|
|
5903 |
|
|
case 0x00070000:
|
5904 |
|
|
desc = "DMA Error";
|
5905 |
|
|
break;
|
5906 |
|
|
|
5907 |
|
|
case 0x00080000:
|
5908 |
|
|
desc = "Outbound DMA Overrun";
|
5909 |
|
|
break;
|
5910 |
|
|
}
|
5911 |
|
|
|
5912 |
|
|
printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
|
5913 |
|
|
}
|
5914 |
|
|
|
5915 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5916 |
|
|
/**
|
5917 |
|
|
* mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI
|
5918 |
|
|
* OpCode strings from the (optional) isense module.
|
5919 |
|
|
* @ascqTable: Pointer to ASCQ_Table_t structure
|
5920 |
|
|
* @ascqtbl_sz: Number of entries in ASCQ_Table
|
5921 |
|
|
* @opsTable: Pointer to array of SCSI OpCode strings (char pointers)
|
5922 |
|
|
*
|
5923 |
|
|
* Specialized driver registration routine for the isense driver.
|
5924 |
|
|
*/
|
5925 |
|
|
int
|
5926 |
|
|
mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable)
|
5927 |
|
|
{
|
5928 |
|
|
int r = 0;
|
5929 |
|
|
|
5930 |
|
|
if (ascqTable && ascqtbl_sz && opsTable) {
|
5931 |
|
|
mpt_v_ASCQ_TablePtr = ascqTable;
|
5932 |
|
|
mpt_ASCQ_TableSz = ascqtbl_sz;
|
5933 |
|
|
mpt_ScsiOpcodesPtr = opsTable;
|
5934 |
|
|
printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n");
|
5935 |
|
|
isense_idx = last_drv_idx;
|
5936 |
|
|
r = 1;
|
5937 |
|
|
}
|
5938 |
|
|
mpt_inc_use_count();
|
5939 |
|
|
return r;
|
5940 |
|
|
}
|
5941 |
|
|
|
5942 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5943 |
|
|
/**
|
5944 |
|
|
* mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI
|
5945 |
|
|
* OpCode strings from the isense driver.
|
5946 |
|
|
*
|
5947 |
|
|
* Specialized driver deregistration routine for the isense driver.
|
5948 |
|
|
*/
|
5949 |
|
|
void
|
5950 |
|
|
mpt_deregister_ascqops_strings(void)
|
5951 |
|
|
{
|
5952 |
|
|
mpt_v_ASCQ_TablePtr = NULL;
|
5953 |
|
|
mpt_ASCQ_TableSz = 0;
|
5954 |
|
|
mpt_ScsiOpcodesPtr = NULL;
|
5955 |
|
|
printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
|
5956 |
|
|
isense_idx = -1;
|
5957 |
|
|
mpt_dec_use_count();
|
5958 |
|
|
}
|
5959 |
|
|
|
5960 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5961 |
|
|
|
5962 |
|
|
EXPORT_SYMBOL(mpt_adapters);
|
5963 |
|
|
EXPORT_SYMBOL(mpt_proc_root_dir);
|
5964 |
|
|
EXPORT_SYMBOL(DmpService);
|
5965 |
|
|
EXPORT_SYMBOL(mpt_register);
|
5966 |
|
|
EXPORT_SYMBOL(mpt_deregister);
|
5967 |
|
|
EXPORT_SYMBOL(mpt_event_register);
|
5968 |
|
|
EXPORT_SYMBOL(mpt_event_deregister);
|
5969 |
|
|
EXPORT_SYMBOL(mpt_reset_register);
|
5970 |
|
|
EXPORT_SYMBOL(mpt_reset_deregister);
|
5971 |
|
|
EXPORT_SYMBOL(mpt_get_msg_frame);
|
5972 |
|
|
EXPORT_SYMBOL(mpt_put_msg_frame);
|
5973 |
|
|
EXPORT_SYMBOL(mpt_free_msg_frame);
|
5974 |
|
|
EXPORT_SYMBOL(mpt_add_sge);
|
5975 |
|
|
EXPORT_SYMBOL(mpt_add_chain);
|
5976 |
|
|
EXPORT_SYMBOL(mpt_send_handshake_request);
|
5977 |
|
|
EXPORT_SYMBOL(mpt_handshake_req_reply_wait);
|
5978 |
|
|
EXPORT_SYMBOL(mpt_adapter_find_first);
|
5979 |
|
|
EXPORT_SYMBOL(mpt_adapter_find_next);
|
5980 |
|
|
EXPORT_SYMBOL(mpt_verify_adapter);
|
5981 |
|
|
EXPORT_SYMBOL(mpt_GetIocState);
|
5982 |
|
|
EXPORT_SYMBOL(mpt_print_ioc_summary);
|
5983 |
|
|
EXPORT_SYMBOL(mpt_lan_index);
|
5984 |
|
|
EXPORT_SYMBOL(mpt_stm_index);
|
5985 |
|
|
EXPORT_SYMBOL(mpt_HardResetHandler);
|
5986 |
|
|
EXPORT_SYMBOL(mpt_config);
|
5987 |
|
|
EXPORT_SYMBOL(mpt_read_ioc_pg_3);
|
5988 |
|
|
EXPORT_SYMBOL(mpt_alloc_fw_memory);
|
5989 |
|
|
EXPORT_SYMBOL(mpt_free_fw_memory);
|
5990 |
|
|
|
5991 |
|
|
EXPORT_SYMBOL(mpt_register_ascqops_strings);
|
5992 |
|
|
EXPORT_SYMBOL(mpt_deregister_ascqops_strings);
|
5993 |
|
|
EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr);
|
5994 |
|
|
EXPORT_SYMBOL(mpt_ASCQ_TableSz);
|
5995 |
|
|
EXPORT_SYMBOL(mpt_ScsiOpcodesPtr);
|
5996 |
|
|
|
5997 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5998 |
|
|
/*
|
5999 |
|
|
* fusion_init - Fusion MPT base driver initialization routine.
|
6000 |
|
|
*
|
6001 |
|
|
* Returns 0 for success, non-zero for failure.
|
6002 |
|
|
*/
|
6003 |
|
|
int __init
|
6004 |
|
|
fusion_init(void)
|
6005 |
|
|
{
|
6006 |
|
|
int i;
|
6007 |
|
|
|
6008 |
|
|
if (FusionInitCalled++) {
|
6009 |
|
|
dprintk((KERN_INFO MYNAM ": INFO - Driver late-init entry point called\n"));
|
6010 |
|
|
return 0;
|
6011 |
|
|
}
|
6012 |
|
|
|
6013 |
|
|
show_mptmod_ver(my_NAME, my_VERSION);
|
6014 |
|
|
printk(KERN_INFO COPYRIGHT "\n");
|
6015 |
|
|
|
6016 |
|
|
Q_INIT(&MptAdapters, MPT_ADAPTER); /* set to empty */
|
6017 |
|
|
for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
|
6018 |
|
|
MptCallbacks[i] = NULL;
|
6019 |
|
|
MptDriverClass[i] = MPTUNKNOWN_DRIVER;
|
6020 |
|
|
MptEvHandlers[i] = NULL;
|
6021 |
|
|
MptResetHandlers[i] = NULL;
|
6022 |
|
|
}
|
6023 |
|
|
|
6024 |
|
|
DmpService = NULL;
|
6025 |
|
|
|
6026 |
|
|
/* NEW! 20010120 -sralston
|
6027 |
|
|
* Register ourselves (mptbase) in order to facilitate
|
6028 |
|
|
* EventNotification handling.
|
6029 |
|
|
*/
|
6030 |
|
|
mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
|
6031 |
|
|
|
6032 |
|
|
/* Register for hard reset handling callbacks.
|
6033 |
|
|
*/
|
6034 |
|
|
if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
|
6035 |
|
|
dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
|
6036 |
|
|
} else {
|
6037 |
|
|
/* FIXME! */
|
6038 |
|
|
}
|
6039 |
|
|
|
6040 |
|
|
if ((i = mpt_pci_scan()) < 0)
|
6041 |
|
|
return i;
|
6042 |
|
|
|
6043 |
|
|
return 0;
|
6044 |
|
|
}
|
6045 |
|
|
|
6046 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
6047 |
|
|
/*
|
6048 |
|
|
* fusion_exit - Perform driver unload cleanup.
|
6049 |
|
|
*
|
6050 |
|
|
* This routine frees all resources associated with each MPT adapter
|
6051 |
|
|
* and removes all %MPT_PROCFS_MPTBASEDIR entries.
|
6052 |
|
|
*/
|
6053 |
|
|
static void
|
6054 |
|
|
fusion_exit(void)
|
6055 |
|
|
{
|
6056 |
|
|
MPT_ADAPTER *this;
|
6057 |
|
|
struct pci_dev *pdev;
|
6058 |
|
|
|
6059 |
|
|
dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
|
6060 |
|
|
|
6061 |
|
|
/* Whups? 20010120 -sralston
|
6062 |
|
|
* Moved this *above* removal of all MptAdapters!
|
6063 |
|
|
*/
|
6064 |
|
|
#ifdef CONFIG_PROC_FS
|
6065 |
|
|
(void) procmpt_destroy();
|
6066 |
|
|
#endif
|
6067 |
|
|
|
6068 |
|
|
while (! Q_IS_EMPTY(&MptAdapters)) {
|
6069 |
|
|
this = MptAdapters.head;
|
6070 |
|
|
|
6071 |
|
|
/* Disable interrupts! */
|
6072 |
|
|
CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
|
6073 |
|
|
|
6074 |
|
|
this->active = 0;
|
6075 |
|
|
|
6076 |
|
|
pdev = (struct pci_dev *)this->pcidev;
|
6077 |
|
|
mpt_sync_irq(pdev->irq);
|
6078 |
|
|
|
6079 |
|
|
/* Clear any lingering interrupt */
|
6080 |
|
|
CHIPREG_WRITE32(&this->chip->IntStatus, 0);
|
6081 |
|
|
|
6082 |
|
|
CHIPREG_READ32(&this->chip->IntStatus);
|
6083 |
|
|
|
6084 |
|
|
Q_DEL_ITEM(this);
|
6085 |
|
|
mpt_adapter_dispose(this);
|
6086 |
|
|
}
|
6087 |
|
|
|
6088 |
|
|
mpt_reset_deregister(mpt_base_index);
|
6089 |
|
|
}
|
6090 |
|
|
|
6091 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
6092 |
|
|
|
6093 |
|
|
module_init(fusion_init);
|
6094 |
|
|
module_exit(fusion_exit);
|