1 | /* $NetBSD: isp.c,v 1.125 2013/09/14 13:09:55 joerg Exp $ */ |
2 | /* |
3 | * Machine and OS Independent (well, as best as possible) |
4 | * code for the Qlogic ISP SCSI adapters. |
5 | * |
6 | * Copyright (C) 1997, 1998, 1999 National Aeronautics & Space Administration |
7 | * All rights reserved. |
8 | * |
9 | * Additional Copyright (C) 2000-2007 by Matthew Jacob |
10 | * All rights reserved. |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * |
16 | * 1. Redistributions of source code must retain the above copyright |
17 | * notice, this list of conditions and the following disclaimer. |
18 | * 2. Redistributions in binary form must reproduce the above copyright |
19 | * notice, this list of conditions and the following disclaimer in the |
20 | * documentation and/or other materials provided with the distribution. |
21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. |
33 | */ |
34 | |
35 | /* |
36 | * Inspiration and ideas about this driver are from Erik Moe's Linux driver |
37 | * (qlogicisp.c) and Dave Miller's SBus version of same (qlogicisp.c). Some |
38 | * ideas dredged from the Solaris driver. |
39 | */ |
40 | |
41 | /* |
42 | * Include header file appropriate for platform we're building on. |
43 | */ |
44 | #ifdef __NetBSD__ |
45 | #include <sys/cdefs.h> |
46 | __KERNEL_RCSID(0, "$NetBSD: isp.c,v 1.125 2013/09/14 13:09:55 joerg Exp $" ); |
47 | #include <dev/ic/isp_netbsd.h> |
48 | #endif |
49 | #ifdef __FreeBSD__ |
50 | #include <sys/cdefs.h> |
51 | __FBSDID("$FreeBSD$" ); |
52 | #include <dev/isp/isp_freebsd.h> |
53 | #endif |
54 | #ifdef __OpenBSD__ |
55 | #include <dev/ic/isp_openbsd.h> |
56 | #endif |
57 | #ifdef __linux__ |
58 | #include "isp_linux.h" |
59 | #endif |
60 | #ifdef __svr4__ |
61 | #include "isp_solaris.h" |
62 | #endif |
63 | |
64 | /* |
65 | * General defines |
66 | */ |
67 | #define MBOX_DELAY_COUNT 1000000 / 100 |
68 | #define ISP_MARK_PORTDB(a, b, c) \ |
69 | isp_prt(isp, ISP_LOGSANCFG, \ |
70 | "Chan %d ISP_MARK_PORTDB@LINE %d", b, __LINE__); \ |
71 | isp_mark_portdb(a, b, c) |
72 | |
73 | /* |
74 | * Local static data |
75 | */ |
76 | static const char fconf[] = "Chan %d PortDB[%d] changed:\n current =(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)\n database=(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)" ; |
77 | static const char notresp[] = "Not RESPONSE in RESPONSE Queue (type 0x%x) @ idx %d (next %d) nlooked %d" ; |
78 | static const char topology[] = "Chan %d WWPN 0x%08x%08x PortID 0x%06x N-Port Handle %d, Connection '%s'" ; |
79 | static const char bun[] = "bad underrun (count %d, resid %d, status %s)" ; |
80 | static const char lipd[] = "Chan %d LIP destroyed %d active commands" ; |
81 | static const char sacq[] = "unable to acquire scratch area" ; |
82 | |
83 | static const uint8_t alpa_map[] = { |
84 | 0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, |
85 | 0xd9, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, |
86 | 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc7, 0xc6, 0xc5, |
87 | 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5, 0xb4, 0xb3, |
88 | 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, |
89 | 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, |
90 | 0x98, 0x97, 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, |
91 | 0x80, 0x7c, 0x7a, 0x79, 0x76, 0x75, 0x74, 0x73, |
92 | 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, |
93 | 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56, |
94 | 0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, |
95 | 0x4b, 0x4a, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, |
96 | 0x3a, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, |
97 | 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x27, 0x26, |
98 | 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17, |
99 | 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00 |
100 | }; |
101 | |
102 | /* |
103 | * Local function prototypes. |
104 | */ |
105 | static void isp_prt_endcmd(ispsoftc_t *, XS_T *); |
106 | static int isp_parse_async(ispsoftc_t *, uint16_t); |
107 | static int isp_parse_async_fc(ispsoftc_t *, uint16_t); |
108 | static int isp_handle_other_response(ispsoftc_t *, int, isphdr_t *, uint32_t *); |
109 | static void isp_parse_status(ispsoftc_t *, ispstatusreq_t *, XS_T *, long *); static void |
110 | isp_parse_status_24xx(ispsoftc_t *, isp24xx_statusreq_t *, XS_T *, long *); |
111 | static void isp_fastpost_complete(ispsoftc_t *, uint32_t); |
112 | static int isp_mbox_continue(ispsoftc_t *); |
113 | static void isp_scsi_init(ispsoftc_t *); |
114 | static void isp_scsi_channel_init(ispsoftc_t *, int); |
115 | static void isp_fibre_init(ispsoftc_t *); |
116 | static void isp_fibre_init_2400(ispsoftc_t *); |
117 | static void isp_mark_portdb(ispsoftc_t *, int, int); |
118 | static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int, int); |
119 | static int isp_port_login(ispsoftc_t *, uint16_t, uint32_t); |
120 | static int isp_port_logout(ispsoftc_t *, uint16_t, uint32_t); |
121 | static int isp_getpdb(ispsoftc_t *, int, uint16_t, isp_pdb_t *, int); |
122 | static void isp_dump_chip_portdb(ispsoftc_t *, int, int); |
123 | static uint64_t isp_get_wwn(ispsoftc_t *, int, int, int); |
124 | static int isp_fclink_test(ispsoftc_t *, int, int); |
125 | static int isp_pdb_sync(ispsoftc_t *, int); |
126 | static int isp_scan_loop(ispsoftc_t *, int); |
127 | static int isp_gid_ft_sns(ispsoftc_t *, int); |
128 | static int isp_gid_ft_ct_passthru(ispsoftc_t *, int); |
129 | static int isp_scan_fabric(ispsoftc_t *, int); |
130 | static int isp_login_device(ispsoftc_t *, int, uint32_t, isp_pdb_t *, uint16_t *); |
131 | static int isp_register_fc4_type(ispsoftc_t *, int); |
132 | static int isp_register_fc4_type_24xx(ispsoftc_t *, int); |
133 | static uint16_t isp_nxt_handle(ispsoftc_t *, int, uint16_t); |
134 | static void isp_fw_state(ispsoftc_t *, int); |
135 | static void isp_mboxcmd_qnw(ispsoftc_t *, mbreg_t *, int); |
136 | static void isp_mboxcmd(ispsoftc_t *, mbreg_t *); |
137 | |
138 | static void isp_spi_update(ispsoftc_t *, int); |
139 | static void isp_setdfltsdparm(ispsoftc_t *); |
140 | static void isp_setdfltfcparm(ispsoftc_t *, int); |
141 | static int isp_read_nvram(ispsoftc_t *, int); |
142 | static int isp_read_nvram_2400(ispsoftc_t *, uint8_t *); |
143 | static void isp_rdnvram_word(ispsoftc_t *, int, uint16_t *); |
144 | static void isp_rd_2400_nvram(ispsoftc_t *, uint32_t, uint32_t *); |
145 | static void isp_parse_nvram_1020(ispsoftc_t *, uint8_t *); |
146 | static void isp_parse_nvram_1080(ispsoftc_t *, int, uint8_t *); |
147 | static void isp_parse_nvram_12160(ispsoftc_t *, int, uint8_t *); |
148 | static void isp_parse_nvram_2100(ispsoftc_t *, uint8_t *); |
149 | static void isp_parse_nvram_2400(ispsoftc_t *, uint8_t *); |
150 | |
151 | /* |
152 | * Reset Hardware. |
153 | * |
154 | * Hit the chip over the head, download new f/w if available and set it running. |
155 | * |
156 | * Locking done elsewhere. |
157 | */ |
158 | |
159 | void |
160 | isp_reset(ispsoftc_t *isp, int do_load_defaults) |
161 | { |
162 | mbreg_t mbs; |
163 | uint32_t code_org, val; |
164 | int loops, i, dodnld = 1; |
165 | const char *btype = "????" ; |
166 | static const char dcrc[] = "Downloaded RISC Code Checksum Failure" ; |
167 | |
168 | isp->isp_state = ISP_NILSTATE; |
169 | if (isp->isp_dead) { |
170 | isp_shutdown(isp); |
171 | ISP_DISABLE_INTS(isp); |
172 | return; |
173 | } |
174 | |
175 | /* |
176 | * Basic types (SCSI, FibreChannel and PCI or SBus) |
177 | * have been set in the MD code. We figure out more |
178 | * here. Possibly more refined types based upon PCI |
179 | * identification. Chip revision has been gathered. |
180 | * |
181 | * After we've fired this chip up, zero out the conf1 register |
182 | * for SCSI adapters and do other settings for the 2100. |
183 | */ |
184 | |
185 | ISP_DISABLE_INTS(isp); |
186 | |
187 | /* |
188 | * Pick an initial maxcmds value which will be used |
189 | * to allocate xflist pointer space. It may be changed |
190 | * later by the firmware. |
191 | */ |
192 | if (IS_24XX(isp)) { |
193 | isp->isp_maxcmds = 4096; |
194 | } else if (IS_2322(isp)) { |
195 | isp->isp_maxcmds = 2048; |
196 | } else if (IS_23XX(isp) || IS_2200(isp)) { |
197 | isp->isp_maxcmds = 1024; |
198 | } else { |
199 | isp->isp_maxcmds = 512; |
200 | } |
201 | |
202 | /* |
203 | * Set up DMA for the request and response queues. |
204 | * |
205 | * We do this now so we can use the request queue |
206 | * for dma to load firmware from. |
207 | */ |
208 | if (ISP_MBOXDMASETUP(isp) != 0) { |
209 | isp_prt(isp, ISP_LOGERR, "Cannot setup DMA" ); |
210 | return; |
211 | } |
212 | |
213 | /* |
214 | * Set up default request/response queue in-pointer/out-pointer |
215 | * register indices. |
216 | */ |
217 | if (IS_24XX(isp)) { |
218 | isp->isp_rqstinrp = BIU2400_REQINP; |
219 | isp->isp_rqstoutrp = BIU2400_REQOUTP; |
220 | isp->isp_respinrp = BIU2400_RSPINP; |
221 | isp->isp_respoutrp = BIU2400_RSPOUTP; |
222 | } else if (IS_23XX(isp)) { |
223 | isp->isp_rqstinrp = BIU_REQINP; |
224 | isp->isp_rqstoutrp = BIU_REQOUTP; |
225 | isp->isp_respinrp = BIU_RSPINP; |
226 | isp->isp_respoutrp = BIU_RSPOUTP; |
227 | } else { |
228 | isp->isp_rqstinrp = INMAILBOX4; |
229 | isp->isp_rqstoutrp = OUTMAILBOX4; |
230 | isp->isp_respinrp = OUTMAILBOX5; |
231 | isp->isp_respoutrp = INMAILBOX5; |
232 | } |
233 | |
234 | /* |
235 | * Put the board into PAUSE mode (so we can read the SXP registers |
236 | * or write FPM/FBM registers). |
237 | */ |
238 | if (IS_24XX(isp)) { |
239 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_HOST_INT); |
240 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT); |
241 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_PAUSE); |
242 | } else { |
243 | ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); |
244 | } |
245 | |
246 | if (IS_FC(isp)) { |
247 | switch (isp->isp_type) { |
248 | case ISP_HA_FC_2100: |
249 | btype = "2100" ; |
250 | break; |
251 | case ISP_HA_FC_2200: |
252 | btype = "2200" ; |
253 | break; |
254 | case ISP_HA_FC_2300: |
255 | btype = "2300" ; |
256 | break; |
257 | case ISP_HA_FC_2312: |
258 | btype = "2312" ; |
259 | break; |
260 | case ISP_HA_FC_2322: |
261 | btype = "2322" ; |
262 | break; |
263 | case ISP_HA_FC_2400: |
264 | btype = "2422" ; |
265 | break; |
266 | case ISP_HA_FC_2500: |
267 | btype = "2532" ; |
268 | break; |
269 | default: |
270 | break; |
271 | } |
272 | |
273 | if (!IS_24XX(isp)) { |
274 | /* |
275 | * While we're paused, reset the FPM module and FBM |
276 | * fifos. |
277 | */ |
278 | ISP_WRITE(isp, BIU2100_CSR, BIU2100_FPM0_REGS); |
279 | ISP_WRITE(isp, FPM_DIAG_CONFIG, FPM_SOFT_RESET); |
280 | ISP_WRITE(isp, BIU2100_CSR, BIU2100_FB_REGS); |
281 | ISP_WRITE(isp, FBM_CMD, FBMCMD_FIFO_RESET_ALL); |
282 | ISP_WRITE(isp, BIU2100_CSR, BIU2100_RISC_REGS); |
283 | } |
284 | } else if (IS_1240(isp)) { |
285 | sdparam *sdp; |
286 | |
287 | btype = "1240" ; |
288 | isp->isp_clock = 60; |
289 | sdp = SDPARAM(isp, 0); |
290 | sdp->isp_ultramode = 1; |
291 | sdp = SDPARAM(isp, 1); |
292 | sdp->isp_ultramode = 1; |
293 | /* |
294 | * XXX: Should probably do some bus sensing. |
295 | */ |
296 | } else if (IS_ULTRA3(isp)) { |
297 | sdparam *sdp = isp->isp_param; |
298 | |
299 | isp->isp_clock = 100; |
300 | |
301 | if (IS_10160(isp)) |
302 | btype = "10160" ; |
303 | else if (IS_12160(isp)) |
304 | btype = "12160" ; |
305 | else |
306 | btype = "<UNKLVD>" ; |
307 | sdp->isp_lvdmode = 1; |
308 | |
309 | if (IS_DUALBUS(isp)) { |
310 | sdp++; |
311 | sdp->isp_lvdmode = 1; |
312 | } |
313 | } else if (IS_ULTRA2(isp)) { |
314 | static const char m[] = "bus %d is in %s Mode" ; |
315 | uint16_t l; |
316 | sdparam *sdp = SDPARAM(isp, 0); |
317 | |
318 | isp->isp_clock = 100; |
319 | |
320 | if (IS_1280(isp)) |
321 | btype = "1280" ; |
322 | else if (IS_1080(isp)) |
323 | btype = "1080" ; |
324 | else |
325 | btype = "<UNKLVD>" ; |
326 | |
327 | l = ISP_READ(isp, SXP_PINS_DIFF) & ISP1080_MODE_MASK; |
328 | switch (l) { |
329 | case ISP1080_LVD_MODE: |
330 | sdp->isp_lvdmode = 1; |
331 | isp_prt(isp, ISP_LOGCONFIG, m, 0, "LVD" ); |
332 | break; |
333 | case ISP1080_HVD_MODE: |
334 | sdp->isp_diffmode = 1; |
335 | isp_prt(isp, ISP_LOGCONFIG, m, 0, "Differential" ); |
336 | break; |
337 | case ISP1080_SE_MODE: |
338 | sdp->isp_ultramode = 1; |
339 | isp_prt(isp, ISP_LOGCONFIG, m, 0, "Single-Ended" ); |
340 | break; |
341 | default: |
342 | isp_prt(isp, ISP_LOGERR, |
343 | "unknown mode on bus %d (0x%x)" , 0, l); |
344 | break; |
345 | } |
346 | |
347 | if (IS_DUALBUS(isp)) { |
348 | sdp = SDPARAM(isp, 1); |
349 | l = ISP_READ(isp, SXP_PINS_DIFF|SXP_BANK1_SELECT); |
350 | l &= ISP1080_MODE_MASK; |
351 | switch (l) { |
352 | case ISP1080_LVD_MODE: |
353 | sdp->isp_lvdmode = 1; |
354 | isp_prt(isp, ISP_LOGCONFIG, m, 1, "LVD" ); |
355 | break; |
356 | case ISP1080_HVD_MODE: |
357 | sdp->isp_diffmode = 1; |
358 | isp_prt(isp, ISP_LOGCONFIG, |
359 | m, 1, "Differential" ); |
360 | break; |
361 | case ISP1080_SE_MODE: |
362 | sdp->isp_ultramode = 1; |
363 | isp_prt(isp, ISP_LOGCONFIG, |
364 | m, 1, "Single-Ended" ); |
365 | break; |
366 | default: |
367 | isp_prt(isp, ISP_LOGERR, |
368 | "unknown mode on bus %d (0x%x)" , 1, l); |
369 | break; |
370 | } |
371 | } |
372 | } else { |
373 | sdparam *sdp = SDPARAM(isp, 0); |
374 | i = ISP_READ(isp, BIU_CONF0) & BIU_CONF0_HW_MASK; |
375 | switch (i) { |
376 | default: |
377 | isp_prt(isp, ISP_LOGALL, "Unknown Chip Type 0x%x" , i); |
378 | /* FALLTHROUGH */ |
379 | case 1: |
380 | btype = "1020" ; |
381 | isp->isp_type = ISP_HA_SCSI_1020; |
382 | isp->isp_clock = 40; |
383 | break; |
384 | case 2: |
385 | /* |
386 | * Some 1020A chips are Ultra Capable, but don't |
387 | * run the clock rate up for that unless told to |
388 | * do so by the Ultra Capable bits being set. |
389 | */ |
390 | btype = "1020A" ; |
391 | isp->isp_type = ISP_HA_SCSI_1020A; |
392 | isp->isp_clock = 40; |
393 | break; |
394 | case 3: |
395 | btype = "1040" ; |
396 | isp->isp_type = ISP_HA_SCSI_1040; |
397 | isp->isp_clock = 60; |
398 | break; |
399 | case 4: |
400 | btype = "1040A" ; |
401 | isp->isp_type = ISP_HA_SCSI_1040A; |
402 | isp->isp_clock = 60; |
403 | break; |
404 | case 5: |
405 | btype = "1040B" ; |
406 | isp->isp_type = ISP_HA_SCSI_1040B; |
407 | isp->isp_clock = 60; |
408 | break; |
409 | case 6: |
410 | btype = "1040C" ; |
411 | isp->isp_type = ISP_HA_SCSI_1040C; |
412 | isp->isp_clock = 60; |
413 | break; |
414 | } |
415 | /* |
416 | * Now, while we're at it, gather info about ultra |
417 | * and/or differential mode. |
418 | */ |
419 | if (ISP_READ(isp, SXP_PINS_DIFF) & SXP_PINS_DIFF_MODE) { |
420 | isp_prt(isp, ISP_LOGCONFIG, "Differential Mode" ); |
421 | sdp->isp_diffmode = 1; |
422 | } else { |
423 | sdp->isp_diffmode = 0; |
424 | } |
425 | i = ISP_READ(isp, RISC_PSR); |
426 | if (isp->isp_bustype == ISP_BT_SBUS) { |
427 | i &= RISC_PSR_SBUS_ULTRA; |
428 | } else { |
429 | i &= RISC_PSR_PCI_ULTRA; |
430 | } |
431 | if (i != 0) { |
432 | isp_prt(isp, ISP_LOGCONFIG, "Ultra Mode Capable" ); |
433 | sdp->isp_ultramode = 1; |
434 | /* |
435 | * If we're in Ultra Mode, we have to be 60MHz clock- |
436 | * even for the SBus version. |
437 | */ |
438 | isp->isp_clock = 60; |
439 | } else { |
440 | sdp->isp_ultramode = 0; |
441 | /* |
442 | * Clock is known. Gronk. |
443 | */ |
444 | } |
445 | |
446 | /* |
447 | * Machine dependent clock (if set) overrides |
448 | * our generic determinations. |
449 | */ |
450 | if (isp->isp_mdvec->dv_clock) { |
451 | if (isp->isp_mdvec->dv_clock < isp->isp_clock) { |
452 | isp->isp_clock = isp->isp_mdvec->dv_clock; |
453 | } |
454 | } |
455 | |
456 | } |
457 | |
458 | /* |
459 | * Clear instrumentation |
460 | */ |
461 | isp->isp_intcnt = isp->isp_intbogus = 0; |
462 | |
463 | /* |
464 | * Do MD specific pre initialization |
465 | */ |
466 | ISP_RESET0(isp); |
467 | |
468 | /* |
469 | * Hit the chip over the head with hammer, |
470 | * and give it a chance to recover. |
471 | */ |
472 | |
473 | if (IS_SCSI(isp)) { |
474 | ISP_WRITE(isp, BIU_ICR, BIU_ICR_SOFT_RESET); |
475 | /* |
476 | * A slight delay... |
477 | */ |
478 | ISP_DELAY(100); |
479 | |
480 | /* |
481 | * Clear data && control DMA engines. |
482 | */ |
483 | ISP_WRITE(isp, CDMA_CONTROL, DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT); |
484 | ISP_WRITE(isp, DDMA_CONTROL, DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT); |
485 | |
486 | |
487 | } else if (IS_24XX(isp)) { |
488 | /* |
489 | * Stop DMA and wait for it to stop. |
490 | */ |
491 | ISP_WRITE(isp, BIU2400_CSR, BIU2400_DMA_STOP|(3 << 4)); |
492 | for (val = loops = 0; loops < 30000; loops++) { |
493 | ISP_DELAY(10); |
494 | val = ISP_READ(isp, BIU2400_CSR); |
495 | if ((val & BIU2400_DMA_ACTIVE) == 0) { |
496 | break; |
497 | } |
498 | } |
499 | if (val & BIU2400_DMA_ACTIVE) { |
500 | ISP_RESET0(isp); |
501 | isp_prt(isp, ISP_LOGERR, "DMA Failed to Stop on Reset" ); |
502 | return; |
503 | } |
504 | /* |
505 | * Hold it in SOFT_RESET and STOP state for 100us. |
506 | */ |
507 | ISP_WRITE(isp, BIU2400_CSR, BIU2400_SOFT_RESET|BIU2400_DMA_STOP|(3 << 4)); |
508 | ISP_DELAY(100); |
509 | for (loops = 0; loops < 10000; loops++) { |
510 | ISP_DELAY(5); |
511 | val = ISP_READ(isp, OUTMAILBOX0); |
512 | } |
513 | for (val = loops = 0; loops < 500000; loops ++) { |
514 | val = ISP_READ(isp, BIU2400_CSR); |
515 | if ((val & BIU2400_SOFT_RESET) == 0) { |
516 | break; |
517 | } |
518 | } |
519 | if (val & BIU2400_SOFT_RESET) { |
520 | ISP_RESET0(isp); |
521 | isp_prt(isp, ISP_LOGERR, "Failed to come out of reset" ); |
522 | return; |
523 | } |
524 | } else { |
525 | ISP_WRITE(isp, BIU2100_CSR, BIU2100_SOFT_RESET); |
526 | /* |
527 | * A slight delay... |
528 | */ |
529 | ISP_DELAY(100); |
530 | |
531 | /* |
532 | * Clear data && control DMA engines. |
533 | */ |
534 | ISP_WRITE(isp, CDMA2100_CONTROL, DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT); |
535 | ISP_WRITE(isp, TDMA2100_CONTROL, DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT); |
536 | ISP_WRITE(isp, RDMA2100_CONTROL, DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT); |
537 | } |
538 | |
539 | /* |
540 | * Wait for ISP to be ready to go... |
541 | */ |
542 | loops = MBOX_DELAY_COUNT; |
543 | for (;;) { |
544 | if (IS_SCSI(isp)) { |
545 | if (!(ISP_READ(isp, BIU_ICR) & BIU_ICR_SOFT_RESET)) { |
546 | break; |
547 | } |
548 | } else if (IS_24XX(isp)) { |
549 | if (ISP_READ(isp, OUTMAILBOX0) == 0) { |
550 | break; |
551 | } |
552 | } else { |
553 | if (!(ISP_READ(isp, BIU2100_CSR) & BIU2100_SOFT_RESET)) |
554 | break; |
555 | } |
556 | ISP_DELAY(100); |
557 | if (--loops < 0) { |
558 | ISP_DUMPREGS(isp, "chip reset timed out" ); |
559 | ISP_RESET0(isp); |
560 | return; |
561 | } |
562 | } |
563 | |
564 | /* |
565 | * After we've fired this chip up, zero out the conf1 register |
566 | * for SCSI adapters and other settings for the 2100. |
567 | */ |
568 | |
569 | if (IS_SCSI(isp)) { |
570 | ISP_WRITE(isp, BIU_CONF1, 0); |
571 | } else if (!IS_24XX(isp)) { |
572 | ISP_WRITE(isp, BIU2100_CSR, 0); |
573 | } |
574 | |
575 | /* |
576 | * Reset RISC Processor |
577 | */ |
578 | if (IS_24XX(isp)) { |
579 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET); |
580 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RELEASE); |
581 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RESET); |
582 | } else { |
583 | ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); |
584 | ISP_DELAY(100); |
585 | ISP_WRITE(isp, BIU_SEMA, 0); |
586 | } |
587 | |
588 | /* |
589 | * Post-RISC Reset stuff. |
590 | */ |
591 | if (IS_24XX(isp)) { |
592 | for (val = loops = 0; loops < 5000000; loops++) { |
593 | ISP_DELAY(5); |
594 | val = ISP_READ(isp, OUTMAILBOX0); |
595 | if (val == 0) { |
596 | break; |
597 | } |
598 | } |
599 | if (val != 0) { |
600 | ISP_RESET0(isp); |
601 | isp_prt(isp, ISP_LOGERR, "reset didn't clear" ); |
602 | return; |
603 | } |
604 | } else if (IS_SCSI(isp)) { |
605 | uint16_t tmp = isp->isp_mdvec->dv_conf1; |
606 | /* |
607 | * Busted FIFO. Turn off all but burst enables. |
608 | */ |
609 | if (isp->isp_type == ISP_HA_SCSI_1040A) { |
610 | tmp &= BIU_BURST_ENABLE; |
611 | } |
612 | ISP_SETBITS(isp, BIU_CONF1, tmp); |
613 | if (tmp & BIU_BURST_ENABLE) { |
614 | ISP_SETBITS(isp, CDMA_CONF, DMA_ENABLE_BURST); |
615 | ISP_SETBITS(isp, DDMA_CONF, DMA_ENABLE_BURST); |
616 | } |
617 | if (SDPARAM(isp, 0)->isp_ptisp) { |
618 | if (SDPARAM(isp, 0)->isp_ultramode) { |
619 | while (ISP_READ(isp, RISC_MTR) != 0x1313) { |
620 | ISP_WRITE(isp, RISC_MTR, 0x1313); |
621 | ISP_WRITE(isp, HCCR, HCCR_CMD_STEP); |
622 | } |
623 | } else { |
624 | ISP_WRITE(isp, RISC_MTR, 0x1212); |
625 | } |
626 | /* |
627 | * PTI specific register |
628 | */ |
629 | ISP_WRITE(isp, RISC_EMB, DUAL_BANK); |
630 | } else { |
631 | ISP_WRITE(isp, RISC_MTR, 0x1212); |
632 | } |
633 | ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); |
634 | } else { |
635 | ISP_WRITE(isp, RISC_MTR2100, 0x1212); |
636 | if (IS_2200(isp) || IS_23XX(isp)) { |
637 | ISP_WRITE(isp, HCCR, HCCR_2X00_DISABLE_PARITY_PAUSE); |
638 | } |
639 | ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); |
640 | } |
641 | |
642 | ISP_WRITE(isp, isp->isp_rqstinrp, 0); |
643 | ISP_WRITE(isp, isp->isp_rqstoutrp, 0); |
644 | ISP_WRITE(isp, isp->isp_respinrp, 0); |
645 | ISP_WRITE(isp, isp->isp_respoutrp, 0); |
646 | if (IS_24XX(isp)) { |
647 | ISP_WRITE(isp, BIU2400_PRI_REQINP, 0); |
648 | ISP_WRITE(isp, BIU2400_PRI_REQOUTP, 0); |
649 | ISP_WRITE(isp, BIU2400_ATIO_RSPINP, 0); |
650 | ISP_WRITE(isp, BIU2400_ATIO_RSPOUTP, 0); |
651 | } |
652 | |
653 | /* |
654 | * Do MD specific post initialization |
655 | */ |
656 | ISP_RESET1(isp); |
657 | |
658 | /* |
659 | * Wait for everything to finish firing up. |
660 | * |
661 | * Avoid doing this on early 2312s because you can generate a PCI |
662 | * parity error (chip breakage). |
663 | */ |
664 | if (IS_2312(isp) && isp->isp_revision < 2) { |
665 | ISP_DELAY(100); |
666 | } else { |
667 | loops = MBOX_DELAY_COUNT; |
668 | while (ISP_READ(isp, OUTMAILBOX0) == MBOX_BUSY) { |
669 | ISP_DELAY(100); |
670 | if (--loops < 0) { |
671 | ISP_RESET0(isp); |
672 | isp_prt(isp, ISP_LOGERR, |
673 | "MBOX_BUSY never cleared on reset" ); |
674 | return; |
675 | } |
676 | } |
677 | } |
678 | |
679 | /* |
680 | * Up until this point we've done everything by just reading or |
681 | * setting registers. From this point on we rely on at least *some* |
682 | * kind of firmware running in the card. |
683 | */ |
684 | |
685 | /* |
686 | * Do some sanity checking by running a NOP command. |
687 | * If it succeeds, the ROM firmware is now running. |
688 | */ |
689 | ISP_MEMZERO(&mbs, sizeof (mbs)); |
690 | mbs.param[0] = MBOX_NO_OP; |
691 | mbs.logval = MBLOGALL; |
692 | isp_mboxcmd(isp, &mbs); |
693 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
694 | isp_prt(isp, ISP_LOGERR, "NOP command failed (%x)" , mbs.param[0]); |
695 | ISP_RESET0(isp); |
696 | return; |
697 | } |
698 | |
699 | /* |
700 | * Do some operational tests |
701 | */ |
702 | |
703 | if (IS_SCSI(isp) || IS_24XX(isp)) { |
704 | ISP_MEMZERO(&mbs, sizeof (mbs)); |
705 | mbs.param[0] = MBOX_MAILBOX_REG_TEST; |
706 | mbs.param[1] = 0xdead; |
707 | mbs.param[2] = 0xbeef; |
708 | mbs.param[3] = 0xffff; |
709 | mbs.param[4] = 0x1111; |
710 | mbs.param[5] = 0xa5a5; |
711 | mbs.param[6] = 0x0000; |
712 | mbs.param[7] = 0x0000; |
713 | mbs.logval = MBLOGALL; |
714 | isp_mboxcmd(isp, &mbs); |
715 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
716 | ISP_RESET0(isp); |
717 | return; |
718 | } |
719 | if (mbs.param[1] != 0xdead || mbs.param[2] != 0xbeef || |
720 | mbs.param[3] != 0xffff || mbs.param[4] != 0x1111 || |
721 | mbs.param[5] != 0xa5a5) { |
722 | ISP_RESET0(isp); |
723 | isp_prt(isp, ISP_LOGERR, "Register Test Failed (0x%x 0x%x 0x%x 0x%x 0x%x)" , mbs.param[1], mbs.param[2], mbs.param[3], mbs.param[4], mbs.param[5]); |
724 | return; |
725 | } |
726 | |
727 | } |
728 | |
729 | /* |
730 | * Download new Firmware, unless requested not to do so. |
731 | * This is made slightly trickier in some cases where the |
732 | * firmware of the ROM revision is newer than the revision |
733 | * compiled into the driver. So, where we used to compare |
734 | * versions of our f/w and the ROM f/w, now we just see |
735 | * whether we have f/w at all and whether a config flag |
736 | * has disabled our download. |
737 | */ |
738 | if ((isp->isp_mdvec->dv_ispfw == NULL) || (isp->isp_confopts & ISP_CFG_NORELOAD)) { |
739 | dodnld = 0; |
740 | } |
741 | |
742 | if (IS_24XX(isp)) { |
743 | code_org = ISP_CODE_ORG_2400; |
744 | } else if (IS_23XX(isp)) { |
745 | code_org = ISP_CODE_ORG_2300; |
746 | } else { |
747 | code_org = ISP_CODE_ORG; |
748 | } |
749 | |
750 | if (dodnld && IS_24XX(isp)) { |
751 | const uint32_t *ptr = isp->isp_mdvec->dv_ispfw; |
752 | |
753 | /* |
754 | * Keep loading until we run out of f/w. |
755 | */ |
756 | code_org = ptr[2]; /* 1st load address is our start addr */ |
757 | |
758 | for (;;) { |
759 | uint32_t la, wi, wl; |
760 | |
761 | isp_prt(isp, ISP_LOGDEBUG0, "load 0x%x words of code at load address 0x%x" , ptr[3], ptr[2]); |
762 | |
763 | wi = 0; |
764 | la = ptr[2]; |
765 | wl = ptr[3]; |
766 | |
767 | while (wi < ptr[3]) { |
768 | uint32_t *cp; |
769 | uint32_t nw; |
770 | |
771 | nw = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) >> 2; |
772 | if (nw > wl) { |
773 | nw = wl; |
774 | } |
775 | cp = isp->isp_rquest; |
776 | for (i = 0; i < nw; i++) { |
777 | ISP_IOXPUT_32(isp, ptr[wi++], &cp[i]); |
778 | wl--; |
779 | } |
780 | MEMORYBARRIER(isp, SYNC_REQUEST, 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), -1); |
781 | ISP_MEMZERO(&mbs, sizeof (mbs)); |
782 | if (la < 0x10000 && nw < 0x10000) { |
783 | mbs.param[0] = MBOX_LOAD_RISC_RAM_2100; |
784 | mbs.param[1] = la; |
785 | mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); |
786 | mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); |
787 | mbs.param[4] = nw; |
788 | mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); |
789 | mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); |
790 | } else { |
791 | mbs.param[0] = MBOX_LOAD_RISC_RAM; |
792 | mbs.param[1] = la; |
793 | mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); |
794 | mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); |
795 | mbs.param[4] = nw >> 16; |
796 | mbs.param[5] = nw; |
797 | mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); |
798 | mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); |
799 | mbs.param[8] = la >> 16; |
800 | } |
801 | mbs.logval = MBLOGALL; |
802 | isp_mboxcmd(isp, &mbs); |
803 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
804 | isp_prt(isp, ISP_LOGERR, "F/W Risc Ram Load Failed" ); |
805 | ISP_RESET0(isp); |
806 | return; |
807 | } |
808 | la += nw; |
809 | } |
810 | |
811 | if (ptr[1] == 0) { |
812 | break; |
813 | } |
814 | ptr += ptr[3]; |
815 | } |
816 | isp->isp_loaded_fw = 1; |
817 | } else if (dodnld && IS_23XX(isp)) { |
818 | const uint16_t *ptr = isp->isp_mdvec->dv_ispfw; |
819 | uint16_t wi, wl, segno; |
820 | uint32_t la; |
821 | |
822 | la = code_org; |
823 | segno = 0; |
824 | |
825 | for (;;) { |
826 | uint32_t nxtaddr; |
827 | |
828 | isp_prt(isp, ISP_LOGDEBUG0, "load 0x%x words of code at load address 0x%x" , ptr[3], la); |
829 | |
830 | wi = 0; |
831 | wl = ptr[3]; |
832 | |
833 | while (wi < ptr[3]) { |
834 | uint16_t *cp; |
835 | uint16_t nw; |
836 | |
837 | nw = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) >> 1; |
838 | if (nw > wl) { |
839 | nw = wl; |
840 | } |
841 | if (nw > (1 << 15)) { |
842 | nw = 1 << 15; |
843 | } |
844 | cp = isp->isp_rquest; |
845 | for (i = 0; i < nw; i++) { |
846 | ISP_IOXPUT_16(isp, ptr[wi++], &cp[i]); |
847 | wl--; |
848 | } |
849 | MEMORYBARRIER(isp, SYNC_REQUEST, 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), -1); |
850 | ISP_MEMZERO(&mbs, sizeof (mbs)); |
851 | if (la < 0x10000) { |
852 | mbs.param[0] = MBOX_LOAD_RISC_RAM_2100; |
853 | mbs.param[1] = la; |
854 | mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); |
855 | mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); |
856 | mbs.param[4] = nw; |
857 | mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); |
858 | mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); |
859 | } else { |
860 | mbs.param[0] = MBOX_LOAD_RISC_RAM; |
861 | mbs.param[1] = la; |
862 | mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); |
863 | mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); |
864 | mbs.param[4] = nw; |
865 | mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); |
866 | mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); |
867 | mbs.param[8] = la >> 16; |
868 | } |
869 | mbs.logval = MBLOGALL; |
870 | isp_mboxcmd(isp, &mbs); |
871 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
872 | isp_prt(isp, ISP_LOGERR, "F/W Risc Ram Load Failed" ); |
873 | ISP_RESET0(isp); |
874 | return; |
875 | } |
876 | la += nw; |
877 | } |
878 | |
879 | if (!IS_2322(isp)) { |
880 | break; |
881 | } |
882 | |
883 | if (++segno == 3) { |
884 | break; |
885 | } |
886 | |
887 | /* |
888 | * If we're a 2322, the firmware actually comes in |
889 | * three chunks. We loaded the first at the code_org |
890 | * address. The other two chunks, which follow right |
891 | * after each other in memory here, get loaded at |
892 | * addresses specfied at offset 0x9..0xB. |
893 | */ |
894 | |
895 | nxtaddr = ptr[3]; |
896 | ptr = &ptr[nxtaddr]; |
897 | la = ptr[5] | ((ptr[4] & 0x3f) << 16); |
898 | } |
899 | isp->isp_loaded_fw = 1; |
900 | } else if (dodnld) { |
901 | union { |
902 | const uint16_t *cp; |
903 | uint16_t *np; |
904 | } ucd; |
905 | ucd.cp = isp->isp_mdvec->dv_ispfw; |
906 | isp->isp_mbxworkp = &ucd.np[1]; |
907 | isp->isp_mbxwrk0 = ucd.np[3] - 1; |
908 | isp->isp_mbxwrk1 = code_org + 1; |
909 | ISP_MEMZERO(&mbs, sizeof (mbs)); |
910 | mbs.param[0] = MBOX_WRITE_RAM_WORD; |
911 | mbs.param[1] = code_org; |
912 | mbs.param[2] = ucd.np[0]; |
913 | mbs.logval = MBLOGNONE; |
914 | isp_mboxcmd(isp, &mbs); |
915 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
916 | isp_prt(isp, ISP_LOGERR, "F/W download failed at word %d" , isp->isp_mbxwrk1 - code_org); |
917 | ISP_RESET0(isp); |
918 | return; |
919 | } |
920 | } else { |
921 | isp->isp_loaded_fw = 0; |
922 | isp_prt(isp, ISP_LOGDEBUG2, "skipping f/w download" ); |
923 | } |
924 | |
925 | /* |
926 | * If we loaded firmware, verify its checksum |
927 | */ |
928 | if (isp->isp_loaded_fw) { |
929 | ISP_MEMZERO(&mbs, sizeof (mbs)); |
930 | mbs.param[0] = MBOX_VERIFY_CHECKSUM; |
931 | if (IS_24XX(isp)) { |
932 | mbs.param[1] = code_org >> 16; |
933 | mbs.param[2] = code_org; |
934 | } else { |
935 | mbs.param[1] = code_org; |
936 | } |
937 | isp_mboxcmd(isp, &mbs); |
938 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
939 | isp_prt(isp, ISP_LOGERR, dcrc); |
940 | ISP_RESET0(isp); |
941 | return; |
942 | } |
943 | } |
944 | |
945 | /* |
946 | * Now start it rolling. |
947 | * |
948 | * If we didn't actually download f/w, |
949 | * we still need to (re)start it. |
950 | */ |
951 | |
952 | |
953 | MBSINIT(&mbs, MBOX_EXEC_FIRMWARE, MBLOGALL, 1000000); |
954 | if (IS_24XX(isp)) { |
955 | mbs.param[1] = code_org >> 16; |
956 | mbs.param[2] = code_org; |
957 | if (isp->isp_loaded_fw) { |
958 | mbs.param[3] = 0; |
959 | } else { |
960 | mbs.param[3] = 1; |
961 | } |
962 | if (IS_25XX(isp)) { |
963 | mbs.ibits |= 0x10; |
964 | } |
965 | } else if (IS_2322(isp)) { |
966 | mbs.param[1] = code_org; |
967 | if (isp->isp_loaded_fw) { |
968 | mbs.param[2] = 0; |
969 | } else { |
970 | mbs.param[2] = 1; |
971 | } |
972 | } else { |
973 | mbs.param[1] = code_org; |
974 | } |
975 | isp_mboxcmd(isp, &mbs); |
976 | if (IS_2322(isp) || IS_24XX(isp)) { |
977 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
978 | ISP_RESET0(isp); |
979 | return; |
980 | } |
981 | } |
982 | |
983 | /* |
984 | * Give it a chance to finish starting up. |
985 | * Give the 24XX more time. |
986 | */ |
987 | if (IS_24XX(isp)) { |
988 | ISP_DELAY(500000); |
989 | /* |
990 | * Check to see if the 24XX firmware really started. |
991 | */ |
992 | if (mbs.param[1] == 0xdead) { |
993 | isp_prt(isp, ISP_LOGERR, "f/w didn't *really* start" ); |
994 | ISP_RESET0(isp); |
995 | return; |
996 | } |
997 | } else { |
998 | ISP_DELAY(250000); |
999 | if (IS_SCSI(isp)) { |
1000 | /* |
1001 | * Set CLOCK RATE, but only if asked to. |
1002 | */ |
1003 | if (isp->isp_clock) { |
1004 | mbs.param[0] = MBOX_SET_CLOCK_RATE; |
1005 | mbs.param[1] = isp->isp_clock; |
1006 | mbs.logval = MBLOGNONE; |
1007 | isp_mboxcmd(isp, &mbs); |
1008 | /* we will try not to care if this fails */ |
1009 | } |
1010 | } |
1011 | } |
1012 | |
1013 | /* |
1014 | * Ask the chip for the current firmware version. |
1015 | * This should prove that the new firmware is working. |
1016 | */ |
1017 | MBSINIT(&mbs, MBOX_ABOUT_FIRMWARE, MBLOGALL, 0); |
1018 | isp_mboxcmd(isp, &mbs); |
1019 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1020 | ISP_RESET0(isp); |
1021 | return; |
1022 | } |
1023 | |
1024 | /* |
1025 | * The SBus firmware that we are using apparently does not return |
1026 | * major, minor, micro revisions in the mailbox registers, which |
1027 | * is really, really, annoying. |
1028 | */ |
1029 | if (ISP_SBUS_SUPPORTED && isp->isp_bustype == ISP_BT_SBUS) { |
1030 | if (dodnld) { |
1031 | #ifdef ISP_TARGET_MODE |
1032 | isp->isp_fwrev[0] = 7; |
1033 | isp->isp_fwrev[1] = 55; |
1034 | #else |
1035 | isp->isp_fwrev[0] = 1; |
1036 | isp->isp_fwrev[1] = 37; |
1037 | #endif |
1038 | isp->isp_fwrev[2] = 0; |
1039 | } |
1040 | } else { |
1041 | isp->isp_fwrev[0] = mbs.param[1]; |
1042 | isp->isp_fwrev[1] = mbs.param[2]; |
1043 | isp->isp_fwrev[2] = mbs.param[3]; |
1044 | } |
1045 | |
1046 | isp_prt(isp, ISP_LOGCONFIG, "Board Type %s, Chip Revision 0x%x, %s F/W Revision %d.%d.%d" , |
1047 | btype, isp->isp_revision, dodnld? "loaded" : "resident" , isp->isp_fwrev[0], isp->isp_fwrev[1], isp->isp_fwrev[2]); |
1048 | |
1049 | if (IS_FC(isp)) { |
1050 | /* |
1051 | * We do not believe firmware attributes for 2100 code less |
1052 | * than 1.17.0, unless it's the firmware we specifically |
1053 | * are loading. |
1054 | * |
1055 | * Note that all 22XX and later f/w is greater than 1.X.0. |
1056 | */ |
1057 | if ((ISP_FW_OLDER_THAN(isp, 1, 17, 1))) { |
1058 | #ifdef USE_SMALLER_2100_FIRMWARE |
1059 | isp->isp_fwattr = ISP_FW_ATTR_SCCLUN; |
1060 | #else |
1061 | isp->isp_fwattr = 0; |
1062 | #endif |
1063 | } else { |
1064 | isp->isp_fwattr = mbs.param[6]; |
1065 | isp_prt(isp, ISP_LOGDEBUG0, "Firmware Attributes = 0x%x" , mbs.param[6]); |
1066 | } |
1067 | } else { |
1068 | #ifndef ISP_TARGET_MODE |
1069 | isp->isp_fwattr = ISP_FW_ATTR_TMODE; |
1070 | #else |
1071 | isp->isp_fwattr = 0; |
1072 | #endif |
1073 | } |
1074 | |
1075 | if (!IS_24XX(isp)) { |
1076 | MBSINIT(&mbs, MBOX_GET_FIRMWARE_STATUS, MBLOGALL, 0); |
1077 | isp_mboxcmd(isp, &mbs); |
1078 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1079 | ISP_RESET0(isp); |
1080 | return; |
1081 | } |
1082 | if (isp->isp_maxcmds >= mbs.param[2]) { |
1083 | isp->isp_maxcmds = mbs.param[2]; |
1084 | } |
1085 | } |
1086 | isp_prt(isp, ISP_LOGCONFIG, "%d max I/O command limit set" , isp->isp_maxcmds); |
1087 | |
1088 | /* |
1089 | * If we don't have Multi-ID f/w loaded, we need to restrict channels to one. |
1090 | * Only make this check for non-SCSI cards (I'm not sure firmware attributes |
1091 | * work for them). |
1092 | */ |
1093 | if (IS_FC(isp) && ISP_CAP_MULTI_ID(isp) == 0 && isp->isp_nchan > 1) { |
1094 | isp_prt(isp, ISP_LOGWARN, "non-MULTIID f/w loaded, only can enable 1 of %d channels" , isp->isp_nchan); |
1095 | isp->isp_nchan = 1; |
1096 | } |
1097 | |
1098 | for (i = 0; i < isp->isp_nchan; i++) { |
1099 | isp_fw_state(isp, i); |
1100 | } |
1101 | if (isp->isp_dead) { |
1102 | isp_shutdown(isp); |
1103 | ISP_DISABLE_INTS(isp); |
1104 | return; |
1105 | } |
1106 | |
1107 | isp->isp_state = ISP_RESETSTATE; |
1108 | |
1109 | /* |
1110 | * Okay- now that we have new firmware running, we now (re)set our |
1111 | * notion of how many luns we support. This is somewhat tricky because |
1112 | * if we haven't loaded firmware, we sometimes do not have an easy way |
1113 | * of knowing how many luns we support. |
1114 | * |
1115 | * Expanded lun firmware gives you 32 luns for SCSI cards and |
1116 | * 16384 luns for Fibre Channel cards. |
1117 | * |
1118 | * It turns out that even for QLogic 2100s with ROM 1.10 and above |
1119 | * we do get a firmware attributes word returned in mailbox register 6. |
1120 | * |
1121 | * Because the lun is in a different position in the Request Queue |
1122 | * Entry structure for Fibre Channel with expanded lun firmware, we |
1123 | * can only support one lun (lun zero) when we don't know what kind |
1124 | * of firmware we're running. |
1125 | */ |
1126 | if (IS_SCSI(isp)) { |
1127 | if (dodnld) { |
1128 | if (IS_ULTRA2(isp) || IS_ULTRA3(isp)) { |
1129 | isp->isp_maxluns = 32; |
1130 | } else { |
1131 | isp->isp_maxluns = 8; |
1132 | } |
1133 | } else { |
1134 | isp->isp_maxluns = 8; |
1135 | } |
1136 | } else { |
1137 | if (ISP_CAP_SCCFW(isp)) { |
1138 | isp->isp_maxluns = 16384; |
1139 | } else { |
1140 | isp->isp_maxluns = 16; |
1141 | } |
1142 | } |
1143 | |
1144 | /* |
1145 | * We get some default values established. As a side |
1146 | * effect, NVRAM is read here (unless overriden by |
1147 | * a configuration flag). |
1148 | */ |
1149 | if (do_load_defaults) { |
1150 | if (IS_SCSI(isp)) { |
1151 | isp_setdfltsdparm(isp); |
1152 | } else { |
1153 | for (i = 0; i < isp->isp_nchan; i++) { |
1154 | isp_setdfltfcparm(isp, i); |
1155 | } |
1156 | } |
1157 | } |
1158 | } |
1159 | |
1160 | /* |
1161 | * Initialize Parameters of Hardware to a known state. |
1162 | * |
1163 | * Locks are held before coming here. |
1164 | */ |
1165 | |
1166 | void |
1167 | isp_init(ispsoftc_t *isp) |
1168 | { |
1169 | if (IS_FC(isp)) { |
1170 | if (IS_24XX(isp)) { |
1171 | isp_fibre_init_2400(isp); |
1172 | } else { |
1173 | isp_fibre_init(isp); |
1174 | } |
1175 | } else { |
1176 | isp_scsi_init(isp); |
1177 | } |
1178 | GET_NANOTIME(&isp->isp_init_time); |
1179 | } |
1180 | |
1181 | static void |
1182 | isp_scsi_init(ispsoftc_t *isp) |
1183 | { |
1184 | sdparam *sdp_chan0, *sdp_chan1; |
1185 | mbreg_t mbs; |
1186 | |
1187 | sdp_chan0 = SDPARAM(isp, 0); |
1188 | sdp_chan1 = sdp_chan0; |
1189 | if (IS_DUALBUS(isp)) { |
1190 | sdp_chan1 = SDPARAM(isp, 1); |
1191 | } |
1192 | |
1193 | /* First do overall per-card settings. */ |
1194 | |
1195 | /* |
1196 | * If we have fast memory timing enabled, turn it on. |
1197 | */ |
1198 | if (sdp_chan0->isp_fast_mttr) { |
1199 | ISP_WRITE(isp, RISC_MTR, 0x1313); |
1200 | } |
1201 | |
1202 | /* |
1203 | * Set Retry Delay and Count. |
1204 | * You set both channels at the same time. |
1205 | */ |
1206 | MBSINIT(&mbs, MBOX_SET_RETRY_COUNT, MBLOGALL, 0); |
1207 | mbs.param[1] = sdp_chan0->isp_retry_count; |
1208 | mbs.param[2] = sdp_chan0->isp_retry_delay; |
1209 | mbs.param[6] = sdp_chan1->isp_retry_count; |
1210 | mbs.param[7] = sdp_chan1->isp_retry_delay; |
1211 | isp_mboxcmd(isp, &mbs); |
1212 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1213 | return; |
1214 | } |
1215 | |
1216 | /* |
1217 | * Set ASYNC DATA SETUP time. This is very important. |
1218 | */ |
1219 | MBSINIT(&mbs, MBOX_SET_ASYNC_DATA_SETUP_TIME, MBLOGALL, 0); |
1220 | mbs.param[1] = sdp_chan0->isp_async_data_setup; |
1221 | mbs.param[2] = sdp_chan1->isp_async_data_setup; |
1222 | isp_mboxcmd(isp, &mbs); |
1223 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1224 | return; |
1225 | } |
1226 | |
1227 | /* |
1228 | * Set ACTIVE Negation State. |
1229 | */ |
1230 | MBSINIT(&mbs, MBOX_SET_ACT_NEG_STATE, MBLOGNONE, 0); |
1231 | mbs.param[1] = |
1232 | (sdp_chan0->isp_req_ack_active_neg << 4) | |
1233 | (sdp_chan0->isp_data_line_active_neg << 5); |
1234 | mbs.param[2] = |
1235 | (sdp_chan1->isp_req_ack_active_neg << 4) | |
1236 | (sdp_chan1->isp_data_line_active_neg << 5); |
1237 | isp_mboxcmd(isp, &mbs); |
1238 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1239 | isp_prt(isp, ISP_LOGERR, |
1240 | "failed to set active negation state (%d,%d), (%d,%d)" , |
1241 | sdp_chan0->isp_req_ack_active_neg, |
1242 | sdp_chan0->isp_data_line_active_neg, |
1243 | sdp_chan1->isp_req_ack_active_neg, |
1244 | sdp_chan1->isp_data_line_active_neg); |
1245 | /* |
1246 | * But don't return. |
1247 | */ |
1248 | } |
1249 | |
1250 | /* |
1251 | * Set the Tag Aging limit |
1252 | */ |
1253 | MBSINIT(&mbs, MBOX_SET_TAG_AGE_LIMIT, MBLOGALL, 0); |
1254 | mbs.param[1] = sdp_chan0->isp_tag_aging; |
1255 | mbs.param[2] = sdp_chan1->isp_tag_aging; |
1256 | isp_mboxcmd(isp, &mbs); |
1257 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1258 | isp_prt(isp, ISP_LOGERR, "failed to set tag age limit (%d,%d)" , |
1259 | sdp_chan0->isp_tag_aging, sdp_chan1->isp_tag_aging); |
1260 | return; |
1261 | } |
1262 | |
1263 | /* |
1264 | * Set selection timeout. |
1265 | */ |
1266 | MBSINIT(&mbs, MBOX_SET_SELECT_TIMEOUT, MBLOGALL, 0); |
1267 | mbs.param[1] = sdp_chan0->isp_selection_timeout; |
1268 | mbs.param[2] = sdp_chan1->isp_selection_timeout; |
1269 | isp_mboxcmd(isp, &mbs); |
1270 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1271 | return; |
1272 | } |
1273 | |
1274 | /* now do per-channel settings */ |
1275 | isp_scsi_channel_init(isp, 0); |
1276 | if (IS_DUALBUS(isp)) |
1277 | isp_scsi_channel_init(isp, 1); |
1278 | |
1279 | /* |
1280 | * Now enable request/response queues |
1281 | */ |
1282 | |
1283 | if (IS_ULTRA2(isp) || IS_1240(isp)) { |
1284 | MBSINIT(&mbs, MBOX_INIT_RES_QUEUE_A64, MBLOGALL, 0); |
1285 | mbs.param[1] = RESULT_QUEUE_LEN(isp); |
1286 | mbs.param[2] = DMA_WD1(isp->isp_result_dma); |
1287 | mbs.param[3] = DMA_WD0(isp->isp_result_dma); |
1288 | mbs.param[4] = 0; |
1289 | mbs.param[6] = DMA_WD3(isp->isp_result_dma); |
1290 | mbs.param[7] = DMA_WD2(isp->isp_result_dma); |
1291 | isp_mboxcmd(isp, &mbs); |
1292 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1293 | return; |
1294 | } |
1295 | isp->isp_residx = mbs.param[5]; |
1296 | |
1297 | MBSINIT(&mbs, MBOX_INIT_REQ_QUEUE_A64, MBLOGALL, 0); |
1298 | mbs.param[1] = RQUEST_QUEUE_LEN(isp); |
1299 | mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); |
1300 | mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); |
1301 | mbs.param[5] = 0; |
1302 | mbs.param[6] = DMA_WD3(isp->isp_result_dma); |
1303 | mbs.param[7] = DMA_WD2(isp->isp_result_dma); |
1304 | isp_mboxcmd(isp, &mbs); |
1305 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1306 | return; |
1307 | } |
1308 | isp->isp_reqidx = isp->isp_reqodx = mbs.param[4]; |
1309 | } else { |
1310 | MBSINIT(&mbs, MBOX_INIT_RES_QUEUE, MBLOGALL, 0); |
1311 | mbs.param[1] = RESULT_QUEUE_LEN(isp); |
1312 | mbs.param[2] = DMA_WD1(isp->isp_result_dma); |
1313 | mbs.param[3] = DMA_WD0(isp->isp_result_dma); |
1314 | mbs.param[4] = 0; |
1315 | isp_mboxcmd(isp, &mbs); |
1316 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1317 | return; |
1318 | } |
1319 | isp->isp_residx = mbs.param[5]; |
1320 | |
1321 | MBSINIT(&mbs, MBOX_INIT_REQ_QUEUE, MBLOGALL, 0); |
1322 | mbs.param[1] = RQUEST_QUEUE_LEN(isp); |
1323 | mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); |
1324 | mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); |
1325 | mbs.param[5] = 0; |
1326 | isp_mboxcmd(isp, &mbs); |
1327 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1328 | return; |
1329 | } |
1330 | isp->isp_reqidx = isp->isp_reqodx = mbs.param[4]; |
1331 | } |
1332 | |
1333 | /* |
1334 | * Turn on LVD transitions for ULTRA2 or better and other features |
1335 | * |
1336 | * Now that we have 32 bit handles, don't do any fast posting |
1337 | * any more. For Ultra2/Ultra3 cards, we can turn on 32 bit RIO |
1338 | * operation or use fast posting. To be conservative, we'll only |
1339 | * do this for Ultra3 cards now because the other cards are so |
1340 | * rare for this author to find and test with. |
1341 | */ |
1342 | |
1343 | MBSINIT(&mbs, MBOX_SET_FW_FEATURES, MBLOGALL, 0); |
1344 | if (IS_ULTRA2(isp)) |
1345 | mbs.param[1] |= FW_FEATURE_LVD_NOTIFY; |
1346 | #ifdef ISP_NO_RIO |
1347 | if (IS_ULTRA3(isp)) |
1348 | mbs.param[1] |= FW_FEATURE_FAST_POST; |
1349 | #else |
1350 | if (IS_ULTRA3(isp)) |
1351 | mbs.param[1] |= FW_FEATURE_RIO_32BIT; |
1352 | #endif |
1353 | if (mbs.param[1] != 0) { |
1354 | uint16_t sfeat = mbs.param[1]; |
1355 | isp_mboxcmd(isp, &mbs); |
1356 | if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { |
1357 | isp_prt(isp, ISP_LOGINFO, |
1358 | "Enabled FW features (0x%x)" , sfeat); |
1359 | } |
1360 | } |
1361 | |
1362 | isp->isp_state = ISP_INITSTATE; |
1363 | } |
1364 | |
1365 | static void |
1366 | isp_scsi_channel_init(ispsoftc_t *isp, int chan) |
1367 | { |
1368 | sdparam *sdp; |
1369 | mbreg_t mbs; |
1370 | int tgt; |
1371 | |
1372 | sdp = SDPARAM(isp, chan); |
1373 | |
1374 | /* |
1375 | * Set (possibly new) Initiator ID. |
1376 | */ |
1377 | MBSINIT(&mbs, MBOX_SET_INIT_SCSI_ID, MBLOGALL, 0); |
1378 | mbs.param[1] = (chan << 7) | sdp->isp_initiator_id; |
1379 | isp_mboxcmd(isp, &mbs); |
1380 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1381 | return; |
1382 | } |
1383 | isp_prt(isp, ISP_LOGINFO, "Chan %d Initiator ID is %d" , |
1384 | chan, sdp->isp_initiator_id); |
1385 | |
1386 | |
1387 | /* |
1388 | * Set current per-target parameters to an initial safe minimum. |
1389 | */ |
1390 | for (tgt = 0; tgt < MAX_TARGETS; tgt++) { |
1391 | int lun; |
1392 | uint16_t sdf; |
1393 | |
1394 | if (sdp->isp_devparam[tgt].dev_enable == 0) { |
1395 | continue; |
1396 | } |
1397 | #ifndef ISP_TARGET_MODE |
1398 | sdf = sdp->isp_devparam[tgt].goal_flags; |
1399 | sdf &= DPARM_SAFE_DFLT; |
1400 | /* |
1401 | * It is not quite clear when this changed over so that |
1402 | * we could force narrow and async for 1000/1020 cards, |
1403 | * but assume that this is only the case for loaded |
1404 | * firmware. |
1405 | */ |
1406 | if (isp->isp_loaded_fw) { |
1407 | sdf |= DPARM_NARROW | DPARM_ASYNC; |
1408 | } |
1409 | #else |
1410 | /* |
1411 | * The !$*!)$!$)* f/w uses the same index into some |
1412 | * internal table to decide how to respond to negotiations, |
1413 | * so if we've said "let's be safe" for ID X, and ID X |
1414 | * selects *us*, the negotiations will back to 'safe' |
1415 | * (as in narrow/async). What the f/w *should* do is |
1416 | * use the initiator id settings to decide how to respond. |
1417 | */ |
1418 | sdp->isp_devparam[tgt].goal_flags = sdf = DPARM_DEFAULT; |
1419 | #endif |
1420 | MBSINIT(&mbs, MBOX_SET_TARGET_PARAMS, MBLOGNONE, 0); |
1421 | mbs.param[1] = (chan << 15) | (tgt << 8); |
1422 | mbs.param[2] = sdf; |
1423 | if ((sdf & DPARM_SYNC) == 0) { |
1424 | mbs.param[3] = 0; |
1425 | } else { |
1426 | mbs.param[3] = |
1427 | (sdp->isp_devparam[tgt].goal_offset << 8) | |
1428 | (sdp->isp_devparam[tgt].goal_period); |
1429 | } |
1430 | isp_prt(isp, ISP_LOGDEBUG0, "Initial Settings bus%d tgt%d flags 0x%x off 0x%x per 0x%x" , |
1431 | chan, tgt, mbs.param[2], mbs.param[3] >> 8, mbs.param[3] & 0xff); |
1432 | isp_mboxcmd(isp, &mbs); |
1433 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1434 | sdf = DPARM_SAFE_DFLT; |
1435 | MBSINIT(&mbs, MBOX_SET_TARGET_PARAMS, MBLOGALL, 0); |
1436 | mbs.param[1] = (tgt << 8) | (chan << 15); |
1437 | mbs.param[2] = sdf; |
1438 | mbs.param[3] = 0; |
1439 | isp_mboxcmd(isp, &mbs); |
1440 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1441 | continue; |
1442 | } |
1443 | } |
1444 | |
1445 | /* |
1446 | * We don't update any information directly from the f/w |
1447 | * because we need to run at least one command to cause a |
1448 | * new state to be latched up. So, we just assume that we |
1449 | * converge to the values we just had set. |
1450 | * |
1451 | * Ensure that we don't believe tagged queuing is enabled yet. |
1452 | * It turns out that sometimes the ISP just ignores our |
1453 | * attempts to set parameters for devices that it hasn't |
1454 | * seen yet. |
1455 | */ |
1456 | sdp->isp_devparam[tgt].actv_flags = sdf & ~DPARM_TQING; |
1457 | for (lun = 0; lun < (int) isp->isp_maxluns; lun++) { |
1458 | MBSINIT(&mbs, MBOX_SET_DEV_QUEUE_PARAMS, MBLOGALL, 0); |
1459 | mbs.param[1] = (chan << 15) | (tgt << 8) | lun; |
1460 | mbs.param[2] = sdp->isp_max_queue_depth; |
1461 | mbs.param[3] = sdp->isp_devparam[tgt].exc_throttle; |
1462 | isp_mboxcmd(isp, &mbs); |
1463 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1464 | break; |
1465 | } |
1466 | } |
1467 | } |
1468 | for (tgt = 0; tgt < MAX_TARGETS; tgt++) { |
1469 | if (sdp->isp_devparam[tgt].dev_refresh) { |
1470 | sdp->sendmarker = 1; |
1471 | sdp->update = 1; |
1472 | break; |
1473 | } |
1474 | } |
1475 | } |
1476 | |
1477 | /* |
1478 | * Fibre Channel specific initialization. |
1479 | */ |
1480 | static void |
1481 | isp_fibre_init(ispsoftc_t *isp) |
1482 | { |
1483 | fcparam *fcp; |
1484 | isp_icb_t local, *icbp = &local; |
1485 | mbreg_t mbs; |
1486 | int ownloopid; |
1487 | |
1488 | /* |
1489 | * We only support one channel on non-24XX cards |
1490 | */ |
1491 | fcp = FCPARAM(isp, 0); |
1492 | if (fcp->role == ISP_ROLE_NONE) { |
1493 | isp->isp_state = ISP_INITSTATE; |
1494 | return; |
1495 | } |
1496 | |
1497 | ISP_MEMZERO(icbp, sizeof (*icbp)); |
1498 | icbp->icb_version = ICB_VERSION1; |
1499 | icbp->icb_fwoptions = fcp->isp_fwoptions; |
1500 | |
1501 | /* |
1502 | * Firmware Options are either retrieved from NVRAM or |
1503 | * are patched elsewhere. We check them for sanity here |
1504 | * and make changes based on board revision, but otherwise |
1505 | * let others decide policy. |
1506 | */ |
1507 | |
1508 | /* |
1509 | * If this is a 2100 < revision 5, we have to turn off FAIRNESS. |
1510 | */ |
1511 | if (IS_2100(isp) && isp->isp_revision < 5) { |
1512 | icbp->icb_fwoptions &= ~ICBOPT_FAIRNESS; |
1513 | } |
1514 | |
1515 | /* |
1516 | * We have to use FULL LOGIN even though it resets the loop too much |
1517 | * because otherwise port database entries don't get updated after |
1518 | * a LIP- this is a known f/w bug for 2100 f/w less than 1.17.0. |
1519 | */ |
1520 | if (!ISP_FW_NEWER_THAN(isp, 1, 17, 0)) { |
1521 | icbp->icb_fwoptions |= ICBOPT_FULL_LOGIN; |
1522 | } |
1523 | |
1524 | /* |
1525 | * Insist on Port Database Update Async notifications |
1526 | */ |
1527 | icbp->icb_fwoptions |= ICBOPT_PDBCHANGE_AE; |
1528 | |
1529 | /* |
1530 | * Make sure that target role reflects into fwoptions. |
1531 | */ |
1532 | if (fcp->role & ISP_ROLE_TARGET) { |
1533 | icbp->icb_fwoptions |= ICBOPT_TGT_ENABLE; |
1534 | } else { |
1535 | icbp->icb_fwoptions &= ~ICBOPT_TGT_ENABLE; |
1536 | } |
1537 | |
1538 | if (fcp->role & ISP_ROLE_INITIATOR) { |
1539 | icbp->icb_fwoptions &= ~ICBOPT_INI_DISABLE; |
1540 | } else { |
1541 | icbp->icb_fwoptions |= ICBOPT_INI_DISABLE; |
1542 | } |
1543 | |
1544 | icbp->icb_maxfrmlen = DEFAULT_FRAMESIZE(isp); |
1545 | if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) { |
1546 | isp_prt(isp, ISP_LOGERR, "bad frame length (%d) from NVRAM- using %d" , DEFAULT_FRAMESIZE(isp), ICB_DFLT_FRMLEN); |
1547 | icbp->icb_maxfrmlen = ICB_DFLT_FRMLEN; |
1548 | } |
1549 | icbp->icb_maxalloc = fcp->isp_maxalloc; |
1550 | if (icbp->icb_maxalloc < 1) { |
1551 | isp_prt(isp, ISP_LOGERR, "bad maximum allocation (%d)- using 16" , fcp->isp_maxalloc); |
1552 | icbp->icb_maxalloc = 16; |
1553 | } |
1554 | icbp->icb_execthrottle = DEFAULT_EXEC_THROTTLE(isp); |
1555 | if (icbp->icb_execthrottle < 1) { |
1556 | isp_prt(isp, ISP_LOGERR, "bad execution throttle of %d- using %d" , DEFAULT_EXEC_THROTTLE(isp), ICB_DFLT_THROTTLE); |
1557 | icbp->icb_execthrottle = ICB_DFLT_THROTTLE; |
1558 | } |
1559 | icbp->icb_retry_delay = fcp->isp_retry_delay; |
1560 | icbp->icb_retry_count = fcp->isp_retry_count; |
1561 | icbp->icb_hardaddr = fcp->isp_loopid; |
1562 | ownloopid = (isp->isp_confopts & ISP_CFG_OWNLOOPID) != 0; |
1563 | if (icbp->icb_hardaddr >= LOCAL_LOOP_LIM) { |
1564 | icbp->icb_hardaddr = 0; |
1565 | ownloopid = 0; |
1566 | } |
1567 | |
1568 | /* |
1569 | * Our life seems so much better with 2200s and later with |
1570 | * the latest f/w if we set Hard Address. |
1571 | */ |
1572 | if (ownloopid || ISP_FW_NEWER_THAN(isp, 2, 2, 5)) { |
1573 | icbp->icb_fwoptions |= ICBOPT_HARD_ADDRESS; |
1574 | } |
1575 | |
1576 | /* |
1577 | * Right now we just set extended options to prefer point-to-point |
1578 | * over loop based upon some soft config options. |
1579 | * |
1580 | * NB: for the 2300, ICBOPT_EXTENDED is required. |
1581 | */ |
1582 | if (IS_2100(isp)) { |
1583 | /* |
1584 | * We can't have Fast Posting any more- we now |
1585 | * have 32 bit handles. |
1586 | */ |
1587 | icbp->icb_fwoptions &= ~ICBOPT_FAST_POST; |
1588 | } else if (IS_2200(isp) || IS_23XX(isp)) { |
1589 | icbp->icb_fwoptions |= ICBOPT_EXTENDED; |
1590 | /* |
1591 | * Prefer or force Point-To-Point instead Loop? |
1592 | */ |
1593 | switch (isp->isp_confopts & ISP_CFG_PORT_PREF) { |
1594 | case ISP_CFG_NPORT: |
1595 | icbp->icb_xfwoptions |= ICBXOPT_PTP_2_LOOP; |
1596 | break; |
1597 | case ISP_CFG_NPORT_ONLY: |
1598 | icbp->icb_xfwoptions |= ICBXOPT_PTP_ONLY; |
1599 | break; |
1600 | case ISP_CFG_LPORT_ONLY: |
1601 | icbp->icb_xfwoptions |= ICBXOPT_LOOP_ONLY; |
1602 | break; |
1603 | default: |
1604 | icbp->icb_xfwoptions |= ICBXOPT_LOOP_2_PTP; |
1605 | break; |
1606 | } |
1607 | if (IS_2200(isp)) { |
1608 | /* |
1609 | * We can't have Fast Posting any more- we now |
1610 | * have 32 bit handles. |
1611 | * |
1612 | * RIO seemed to have to much breakage. |
1613 | * |
1614 | * Just opt for safety. |
1615 | */ |
1616 | icbp->icb_xfwoptions &= ~ICBXOPT_RIO_16BIT; |
1617 | icbp->icb_fwoptions &= ~ICBOPT_FAST_POST; |
1618 | } else { |
1619 | /* |
1620 | * QLogic recommends that FAST Posting be turned |
1621 | * off for 23XX cards and instead allow the HBA |
1622 | * to write response queue entries and interrupt |
1623 | * after a delay (ZIO). |
1624 | */ |
1625 | icbp->icb_fwoptions &= ~ICBOPT_FAST_POST; |
1626 | if ((fcp->isp_xfwoptions & ICBXOPT_TIMER_MASK) == ICBXOPT_ZIO) { |
1627 | icbp->icb_xfwoptions |= ICBXOPT_ZIO; |
1628 | icbp->icb_idelaytimer = 10; |
1629 | } |
1630 | if (isp->isp_confopts & ISP_CFG_ONEGB) { |
1631 | icbp->icb_zfwoptions |= ICBZOPT_RATE_ONEGB; |
1632 | } else if (isp->isp_confopts & ISP_CFG_TWOGB) { |
1633 | icbp->icb_zfwoptions |= ICBZOPT_RATE_TWOGB; |
1634 | } else { |
1635 | icbp->icb_zfwoptions |= ICBZOPT_RATE_AUTO; |
1636 | } |
1637 | if (fcp->isp_zfwoptions & ICBZOPT_50_OHM) { |
1638 | icbp->icb_zfwoptions |= ICBZOPT_50_OHM; |
1639 | } |
1640 | } |
1641 | } |
1642 | |
1643 | |
1644 | /* |
1645 | * For 22XX > 2.1.26 && 23XX, set some options. |
1646 | */ |
1647 | if (ISP_FW_NEWER_THAN(isp, 2, 26, 0)) { |
1648 | MBSINIT(&mbs, MBOX_SET_FIRMWARE_OPTIONS, MBLOGALL, 0); |
1649 | mbs.param[1] = IFCOPT1_DISF7SWTCH|IFCOPT1_LIPASYNC|IFCOPT1_LIPF8; |
1650 | mbs.param[2] = 0; |
1651 | mbs.param[3] = 0; |
1652 | if (ISP_FW_NEWER_THAN(isp, 3, 16, 0)) { |
1653 | mbs.param[1] |= IFCOPT1_EQFQASYNC|IFCOPT1_CTIO_RETRY; |
1654 | if (fcp->role & ISP_ROLE_TARGET) { |
1655 | mbs.param[3] = IFCOPT3_NOPRLI; |
1656 | } |
1657 | } |
1658 | isp_mboxcmd(isp, &mbs); |
1659 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1660 | return; |
1661 | } |
1662 | } |
1663 | icbp->icb_logintime = ICB_LOGIN_TOV; |
1664 | icbp->icb_lunetimeout = ICB_LUN_ENABLE_TOV; |
1665 | |
1666 | if (fcp->isp_wwnn && fcp->isp_wwpn && (fcp->isp_wwnn >> 60) != 2) { |
1667 | icbp->icb_fwoptions |= ICBOPT_BOTH_WWNS; |
1668 | MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, fcp->isp_wwnn); |
1669 | MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, fcp->isp_wwpn); |
1670 | isp_prt(isp, ISP_LOGDEBUG1, |
1671 | "Setting ICB Node 0x%08x%08x Port 0x%08x%08x" , |
1672 | ((uint32_t) (fcp->isp_wwnn >> 32)), |
1673 | ((uint32_t) (fcp->isp_wwnn)), |
1674 | ((uint32_t) (fcp->isp_wwpn >> 32)), |
1675 | ((uint32_t) (fcp->isp_wwpn))); |
1676 | } else if (fcp->isp_wwpn) { |
1677 | icbp->icb_fwoptions &= ~ICBOPT_BOTH_WWNS; |
1678 | MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, fcp->isp_wwpn); |
1679 | isp_prt(isp, ISP_LOGDEBUG1, |
1680 | "Setting ICB Port 0x%08x%08x" , |
1681 | ((uint32_t) (fcp->isp_wwpn >> 32)), |
1682 | ((uint32_t) (fcp->isp_wwpn))); |
1683 | } else { |
1684 | isp_prt(isp, ISP_LOGERR, "No valid WWNs to use" ); |
1685 | return; |
1686 | } |
1687 | icbp->icb_rqstqlen = RQUEST_QUEUE_LEN(isp); |
1688 | if (icbp->icb_rqstqlen < 1) { |
1689 | isp_prt(isp, ISP_LOGERR, "bad request queue length" ); |
1690 | } |
1691 | icbp->icb_rsltqlen = RESULT_QUEUE_LEN(isp); |
1692 | if (icbp->icb_rsltqlen < 1) { |
1693 | isp_prt(isp, ISP_LOGERR, "bad result queue length" ); |
1694 | } |
1695 | icbp->icb_rqstaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_rquest_dma); |
1696 | icbp->icb_rqstaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_rquest_dma); |
1697 | icbp->icb_rqstaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_rquest_dma); |
1698 | icbp->icb_rqstaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_rquest_dma); |
1699 | icbp->icb_respaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_result_dma); |
1700 | icbp->icb_respaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_result_dma); |
1701 | icbp->icb_respaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_result_dma); |
1702 | icbp->icb_respaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_result_dma); |
1703 | |
1704 | if (FC_SCRATCH_ACQUIRE(isp, 0)) { |
1705 | isp_prt(isp, ISP_LOGERR, sacq); |
1706 | return; |
1707 | } |
1708 | isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init: fwopt 0x%x xfwopt 0x%x zfwopt 0x%x" , |
1709 | icbp->icb_fwoptions, icbp->icb_xfwoptions, icbp->icb_zfwoptions); |
1710 | |
1711 | isp_put_icb(isp, icbp, (isp_icb_t *)fcp->isp_scratch); |
1712 | |
1713 | /* |
1714 | * Init the firmware |
1715 | */ |
1716 | MBSINIT(&mbs, MBOX_INIT_FIRMWARE, MBLOGALL, 30000000); |
1717 | mbs.param[2] = DMA_WD1(fcp->isp_scdma); |
1718 | mbs.param[3] = DMA_WD0(fcp->isp_scdma); |
1719 | mbs.param[6] = DMA_WD3(fcp->isp_scdma); |
1720 | mbs.param[7] = DMA_WD2(fcp->isp_scdma); |
1721 | mbs.logval = MBLOGALL; |
1722 | isp_prt(isp, ISP_LOGDEBUG0, "INIT F/W from %p (%08x%08x)" , |
1723 | fcp->isp_scratch, (uint32_t) ((uint64_t)fcp->isp_scdma >> 32), |
1724 | (uint32_t) fcp->isp_scdma); |
1725 | MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (*icbp), 0); |
1726 | isp_mboxcmd(isp, &mbs); |
1727 | FC_SCRATCH_RELEASE(isp, 0); |
1728 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1729 | isp_print_bytes(isp, "isp_fibre_init" , sizeof (*icbp), icbp); |
1730 | return; |
1731 | } |
1732 | isp->isp_reqidx = 0; |
1733 | isp->isp_reqodx = 0; |
1734 | isp->isp_residx = 0; |
1735 | |
1736 | /* |
1737 | * Whatever happens, we're now committed to being here. |
1738 | */ |
1739 | isp->isp_state = ISP_INITSTATE; |
1740 | } |
1741 | |
1742 | static void |
1743 | isp_fibre_init_2400(ispsoftc_t *isp) |
1744 | { |
1745 | fcparam *fcp; |
1746 | isp_icb_2400_t local, *icbp = &local; |
1747 | mbreg_t mbs; |
1748 | int chan; |
1749 | |
1750 | /* |
1751 | * Check to see whether all channels have *some* kind of role |
1752 | */ |
1753 | for (chan = 0; chan < isp->isp_nchan; chan++) { |
1754 | fcp = FCPARAM(isp, chan); |
1755 | if (fcp->role != ISP_ROLE_NONE) { |
1756 | break; |
1757 | } |
1758 | } |
1759 | if (chan == isp->isp_nchan) { |
1760 | isp_prt(isp, ISP_LOGDEBUG0, "all %d channels with role 'none'" , chan); |
1761 | isp->isp_state = ISP_INITSTATE; |
1762 | return; |
1763 | } |
1764 | |
1765 | /* |
1766 | * Start with channel 0. |
1767 | */ |
1768 | fcp = FCPARAM(isp, 0); |
1769 | |
1770 | /* |
1771 | * Turn on LIP F8 async event (1) |
1772 | */ |
1773 | MBSINIT(&mbs, MBOX_SET_FIRMWARE_OPTIONS, MBLOGALL, 0); |
1774 | mbs.param[1] = 1; |
1775 | isp_mboxcmd(isp, &mbs); |
1776 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1777 | return; |
1778 | } |
1779 | |
1780 | ISP_MEMZERO(icbp, sizeof (*icbp)); |
1781 | icbp->icb_fwoptions1 = fcp->isp_fwoptions; |
1782 | if (fcp->role & ISP_ROLE_TARGET) { |
1783 | icbp->icb_fwoptions1 |= ICB2400_OPT1_TGT_ENABLE; |
1784 | } else { |
1785 | icbp->icb_fwoptions1 &= ~ICB2400_OPT1_TGT_ENABLE; |
1786 | } |
1787 | |
1788 | if (fcp->role & ISP_ROLE_INITIATOR) { |
1789 | icbp->icb_fwoptions1 &= ~ICB2400_OPT1_INI_DISABLE; |
1790 | } else { |
1791 | icbp->icb_fwoptions1 |= ICB2400_OPT1_INI_DISABLE; |
1792 | } |
1793 | |
1794 | icbp->icb_version = ICB_VERSION1; |
1795 | icbp->icb_maxfrmlen = DEFAULT_FRAMESIZE(isp); |
1796 | if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) { |
1797 | isp_prt(isp, ISP_LOGERR, "bad frame length (%d) from NVRAM- using %d" , DEFAULT_FRAMESIZE(isp), ICB_DFLT_FRMLEN); |
1798 | icbp->icb_maxfrmlen = ICB_DFLT_FRMLEN; |
1799 | } |
1800 | |
1801 | icbp->icb_execthrottle = DEFAULT_EXEC_THROTTLE(isp); |
1802 | if (icbp->icb_execthrottle < 1) { |
1803 | isp_prt(isp, ISP_LOGERR, "bad execution throttle of %d- using %d" , DEFAULT_EXEC_THROTTLE(isp), ICB_DFLT_THROTTLE); |
1804 | icbp->icb_execthrottle = ICB_DFLT_THROTTLE; |
1805 | } |
1806 | |
1807 | if (icbp->icb_fwoptions1 & ICB2400_OPT1_TGT_ENABLE) { |
1808 | /* |
1809 | * Get current resource count |
1810 | */ |
1811 | MBSINIT(&mbs, MBOX_GET_RESOURCE_COUNT, MBLOGALL, 0); |
1812 | mbs.obits = 0x4cf; |
1813 | isp_mboxcmd(isp, &mbs); |
1814 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
1815 | return; |
1816 | } |
1817 | icbp->icb_xchgcnt = mbs.param[3]; |
1818 | } |
1819 | |
1820 | |
1821 | icbp->icb_hardaddr = fcp->isp_loopid; |
1822 | if (icbp->icb_hardaddr >= LOCAL_LOOP_LIM) { |
1823 | icbp->icb_hardaddr = 0; |
1824 | } |
1825 | |
1826 | /* |
1827 | * Force this on. |
1828 | */ |
1829 | icbp->icb_fwoptions1 |= ICB2400_OPT1_HARD_ADDRESS; |
1830 | |
1831 | icbp->icb_fwoptions2 = fcp->isp_xfwoptions; |
1832 | switch (isp->isp_confopts & ISP_CFG_PORT_PREF) { |
1833 | #if 0 |
1834 | case ISP_CFG_NPORT: |
1835 | /* |
1836 | * XXX: This causes the f/w to crash. |
1837 | */ |
1838 | icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; |
1839 | icbp->icb_fwoptions2 |= ICB2400_OPT2_PTP_2_LOOP; |
1840 | break; |
1841 | #endif |
1842 | case ISP_CFG_NPORT_ONLY: |
1843 | icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; |
1844 | icbp->icb_fwoptions2 |= ICB2400_OPT2_PTP_ONLY; |
1845 | break; |
1846 | case ISP_CFG_LPORT_ONLY: |
1847 | icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; |
1848 | icbp->icb_fwoptions2 |= ICB2400_OPT2_LOOP_ONLY; |
1849 | break; |
1850 | default: |
1851 | icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; |
1852 | icbp->icb_fwoptions2 |= ICB2400_OPT2_LOOP_2_PTP; |
1853 | break; |
1854 | } |
1855 | |
1856 | /* force this on for now */ |
1857 | icbp->icb_fwoptions2 |= ICB2400_OPT2_ZIO; |
1858 | |
1859 | switch (icbp->icb_fwoptions2 & ICB2400_OPT2_TIMER_MASK) { |
1860 | case ICB2400_OPT2_ZIO: |
1861 | case ICB2400_OPT2_ZIO1: |
1862 | icbp->icb_idelaytimer = 0; |
1863 | break; |
1864 | case 0: |
1865 | break; |
1866 | default: |
1867 | isp_prt(isp, ISP_LOGWARN, "bad value %x in fwopt2 timer field" , icbp->icb_fwoptions2 & ICB2400_OPT2_TIMER_MASK); |
1868 | icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TIMER_MASK; |
1869 | break; |
1870 | } |
1871 | |
1872 | /* |
1873 | * We don't support FCTAPE, so clear it. |
1874 | */ |
1875 | icbp->icb_fwoptions2 &= ~ICB2400_OPT2_FCTAPE; |
1876 | |
1877 | icbp->icb_fwoptions3 = fcp->isp_zfwoptions; |
1878 | icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_AUTO; |
1879 | if (isp->isp_confopts & ISP_CFG_ONEGB) { |
1880 | icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_ONEGB; |
1881 | } else if (isp->isp_confopts & ISP_CFG_TWOGB) { |
1882 | icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_TWOGB; |
1883 | } else if (isp->isp_confopts & ISP_CFG_FOURGB) { |
1884 | icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_FOURGB; |
1885 | } else { |
1886 | icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_AUTO; |
1887 | } |
1888 | |
1889 | if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) { |
1890 | icbp->icb_fwoptions3 |= ICB2400_OPT3_SOFTID; |
1891 | } |
1892 | icbp->icb_logintime = ICB_LOGIN_TOV; |
1893 | |
1894 | if (fcp->isp_wwnn && fcp->isp_wwpn && (fcp->isp_wwnn >> 60) != 2) { |
1895 | icbp->icb_fwoptions1 |= ICB2400_OPT1_BOTH_WWNS; |
1896 | MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, fcp->isp_wwpn); |
1897 | MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, fcp->isp_wwnn); |
1898 | isp_prt(isp, ISP_LOGDEBUG1, "Setting ICB Node 0x%08x%08x Port 0x%08x%08x" , ((uint32_t) (fcp->isp_wwnn >> 32)), ((uint32_t) (fcp->isp_wwnn)), |
1899 | ((uint32_t) (fcp->isp_wwpn >> 32)), ((uint32_t) (fcp->isp_wwpn))); |
1900 | } else if (fcp->isp_wwpn) { |
1901 | icbp->icb_fwoptions1 &= ~ICB2400_OPT1_BOTH_WWNS; |
1902 | MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, fcp->isp_wwpn); |
1903 | isp_prt(isp, ISP_LOGDEBUG1, "Setting ICB Node to be same as Port 0x%08x%08x" , ((uint32_t) (fcp->isp_wwpn >> 32)), ((uint32_t) (fcp->isp_wwpn))); |
1904 | } else { |
1905 | isp_prt(isp, ISP_LOGERR, "No valid WWNs to use" ); |
1906 | return; |
1907 | } |
1908 | icbp->icb_retry_count = fcp->isp_retry_count; |
1909 | |
1910 | icbp->icb_rqstqlen = RQUEST_QUEUE_LEN(isp); |
1911 | if (icbp->icb_rqstqlen < 8) { |
1912 | isp_prt(isp, ISP_LOGERR, "bad request queue length %d" , icbp->icb_rqstqlen); |
1913 | return; |
1914 | } |
1915 | icbp->icb_rsltqlen = RESULT_QUEUE_LEN(isp); |
1916 | if (icbp->icb_rsltqlen < 8) { |
1917 | isp_prt(isp, ISP_LOGERR, "bad result queue length %d" , |
1918 | icbp->icb_rsltqlen); |
1919 | return; |
1920 | } |
1921 | icbp->icb_rqstaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_rquest_dma); |
1922 | icbp->icb_rqstaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_rquest_dma); |
1923 | icbp->icb_rqstaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_rquest_dma); |
1924 | icbp->icb_rqstaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_rquest_dma); |
1925 | |
1926 | icbp->icb_respaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_result_dma); |
1927 | icbp->icb_respaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_result_dma); |
1928 | icbp->icb_respaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_result_dma); |
1929 | icbp->icb_respaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_result_dma); |
1930 | |
1931 | #ifdef ISP_TARGET_MODE |
1932 | /* unconditionally set up the ATIO queue if we support target mode */ |
1933 | icbp->icb_atioqlen = RESULT_QUEUE_LEN(isp); |
1934 | if (icbp->icb_atioqlen < 8) { |
1935 | isp_prt(isp, ISP_LOGERR, "bad ATIO queue length %d" , icbp->icb_atioqlen); |
1936 | return; |
1937 | } |
1938 | icbp->icb_atioqaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_atioq_dma); |
1939 | icbp->icb_atioqaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_atioq_dma); |
1940 | icbp->icb_atioqaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_atioq_dma); |
1941 | icbp->icb_atioqaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_atioq_dma); |
1942 | isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init_2400: atioq %04x%04x%04x%04x" , DMA_WD3(isp->isp_atioq_dma), DMA_WD2(isp->isp_atioq_dma), |
1943 | DMA_WD1(isp->isp_atioq_dma), DMA_WD0(isp->isp_atioq_dma)); |
1944 | #endif |
1945 | |
1946 | isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init_2400: fwopt1 0x%x fwopt2 0x%x fwopt3 0x%x" , icbp->icb_fwoptions1, icbp->icb_fwoptions2, icbp->icb_fwoptions3); |
1947 | |
1948 | isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init_2400: rqst %04x%04x%04x%04x rsp %04x%04x%04x%04x" , DMA_WD3(isp->isp_rquest_dma), DMA_WD2(isp->isp_rquest_dma), |
1949 | DMA_WD1(isp->isp_rquest_dma), DMA_WD0(isp->isp_rquest_dma), DMA_WD3(isp->isp_result_dma), DMA_WD2(isp->isp_result_dma), |
1950 | DMA_WD1(isp->isp_result_dma), DMA_WD0(isp->isp_result_dma)); |
1951 | |
1952 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
1953 | isp_print_bytes(isp, "isp_fibre_init_2400" , sizeof (*icbp), icbp); |
1954 | } |
1955 | |
1956 | if (FC_SCRATCH_ACQUIRE(isp, 0)) { |
1957 | isp_prt(isp, ISP_LOGERR, sacq); |
1958 | return; |
1959 | } |
1960 | ISP_MEMZERO(fcp->isp_scratch, ISP_FC_SCRLEN); |
1961 | isp_put_icb_2400(isp, icbp, fcp->isp_scratch); |
1962 | |
1963 | /* |
1964 | * Now fill in information about any additional channels |
1965 | */ |
1966 | if (isp->isp_nchan > 1) { |
1967 | isp_icb_2400_vpinfo_t vpinfo, *vdst; |
1968 | vp_port_info_t pi, *pdst; |
1969 | size_t amt = 0; |
1970 | uint8_t *off; |
1971 | |
1972 | vpinfo.vp_count = isp->isp_nchan - 1; |
1973 | vpinfo.vp_global_options = 0; |
1974 | off = fcp->isp_scratch; |
1975 | off += ICB2400_VPINFO_OFF; |
1976 | vdst = (isp_icb_2400_vpinfo_t *) off; |
1977 | isp_put_icb_2400_vpinfo(isp, &vpinfo, vdst); |
1978 | amt = ICB2400_VPINFO_OFF + sizeof (isp_icb_2400_vpinfo_t); |
1979 | for (chan = 1; chan < isp->isp_nchan; chan++) { |
1980 | fcparam *fcp2; |
1981 | |
1982 | ISP_MEMZERO(&pi, sizeof (pi)); |
1983 | fcp2 = FCPARAM(isp, chan); |
1984 | if (fcp2->role != ISP_ROLE_NONE) { |
1985 | pi.vp_port_options = ICB2400_VPOPT_ENABLED; |
1986 | if (fcp2->role & ISP_ROLE_INITIATOR) { |
1987 | pi.vp_port_options |= ICB2400_VPOPT_INI_ENABLE; |
1988 | } |
1989 | if ((fcp2->role & ISP_ROLE_TARGET) == 0) { |
1990 | pi.vp_port_options |= ICB2400_VPOPT_TGT_DISABLE; |
1991 | } |
1992 | MAKE_NODE_NAME_FROM_WWN(pi.vp_port_portname, fcp2->isp_wwpn); |
1993 | MAKE_NODE_NAME_FROM_WWN(pi.vp_port_nodename, fcp2->isp_wwnn); |
1994 | } |
1995 | off = fcp->isp_scratch; |
1996 | off += ICB2400_VPINFO_PORT_OFF(chan); |
1997 | pdst = (vp_port_info_t *) off; |
1998 | isp_put_vp_port_info(isp, &pi, pdst); |
1999 | amt += ICB2400_VPOPT_WRITE_SIZE; |
2000 | } |
2001 | } |
2002 | |
2003 | /* |
2004 | * Init the firmware |
2005 | */ |
2006 | MBSINIT(&mbs, 0, MBLOGALL, 30000000); |
2007 | if (isp->isp_nchan > 1) { |
2008 | mbs.param[0] = MBOX_INIT_FIRMWARE_MULTI_ID; |
2009 | } else { |
2010 | mbs.param[0] = MBOX_INIT_FIRMWARE; |
2011 | } |
2012 | mbs.param[2] = DMA_WD1(fcp->isp_scdma); |
2013 | mbs.param[3] = DMA_WD0(fcp->isp_scdma); |
2014 | mbs.param[6] = DMA_WD3(fcp->isp_scdma); |
2015 | mbs.param[7] = DMA_WD2(fcp->isp_scdma); |
2016 | isp_prt(isp, ISP_LOGDEBUG0, "INIT F/W from %04x%04x%04x%04x" , DMA_WD3(fcp->isp_scdma), DMA_WD2(fcp->isp_scdma), DMA_WD1(fcp->isp_scdma), DMA_WD0(fcp->isp_scdma)); |
2017 | MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (*icbp), 0); |
2018 | isp_mboxcmd(isp, &mbs); |
2019 | FC_SCRATCH_RELEASE(isp, 0); |
2020 | |
2021 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
2022 | return; |
2023 | } |
2024 | isp->isp_reqidx = 0; |
2025 | isp->isp_reqodx = 0; |
2026 | isp->isp_residx = 0; |
2027 | |
2028 | /* |
2029 | * Whatever happens, we're now committed to being here. |
2030 | */ |
2031 | isp->isp_state = ISP_INITSTATE; |
2032 | } |
2033 | |
2034 | static void |
2035 | isp_mark_portdb(ispsoftc_t *isp, int chan, int disposition) |
2036 | { |
2037 | fcparam *fcp = FCPARAM(isp, chan); |
2038 | int i; |
2039 | |
2040 | if (chan < 0 || chan >= isp->isp_nchan) { |
2041 | isp_prt(isp, ISP_LOGWARN, "isp_mark_portdb: bad channel %d" , chan); |
2042 | return; |
2043 | } |
2044 | for (i = 0; i < MAX_FC_TARG; i++) { |
2045 | if (fcp->portdb[i].target_mode) { |
2046 | if (disposition < 0) { |
2047 | isp_prt(isp, ISP_LOGTINFO, "isp_mark_portdb: Chan %d zeroing handle 0x" "%04x port 0x%06x" , chan, |
2048 | fcp->portdb[i].handle, fcp->portdb[i].portid); |
2049 | ISP_MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); |
2050 | } |
2051 | continue; |
2052 | } |
2053 | if (disposition == 0) { |
2054 | ISP_MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); |
2055 | } else { |
2056 | switch (fcp->portdb[i].state) { |
2057 | case FC_PORTDB_STATE_CHANGED: |
2058 | case FC_PORTDB_STATE_PENDING_VALID: |
2059 | case FC_PORTDB_STATE_VALID: |
2060 | case FC_PORTDB_STATE_PROBATIONAL: |
2061 | fcp->portdb[i].state = FC_PORTDB_STATE_PROBATIONAL; |
2062 | break; |
2063 | case FC_PORTDB_STATE_ZOMBIE: |
2064 | break; |
2065 | case FC_PORTDB_STATE_NIL: |
2066 | default: |
2067 | ISP_MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); |
2068 | fcp->portdb[i].state = FC_PORTDB_STATE_NIL; |
2069 | break; |
2070 | } |
2071 | } |
2072 | } |
2073 | } |
2074 | |
2075 | /* |
2076 | * Perform an IOCB PLOGI or LOGO via EXECUTE IOCB A64 for 24XX cards |
2077 | * or via FABRIC LOGIN/FABRIC LOGOUT for other cards. |
2078 | */ |
2079 | static int |
2080 | isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags, int gs) |
2081 | { |
2082 | mbreg_t mbs; |
2083 | uint8_t q[QENTRY_LEN]; |
2084 | isp_plogx_t *plp; |
2085 | fcparam *fcp; |
2086 | uint8_t *scp; |
2087 | uint32_t sst, parm1; |
2088 | int rval; |
2089 | const char *msg; |
2090 | char buf[64]; |
2091 | |
2092 | if (!IS_24XX(isp)) { |
2093 | int action = flags & PLOGX_FLG_CMD_MASK; |
2094 | if (action == PLOGX_FLG_CMD_PLOGI) { |
2095 | return (isp_port_login(isp, handle, portid)); |
2096 | } else if (action == PLOGX_FLG_CMD_LOGO) { |
2097 | return (isp_port_logout(isp, handle, portid)); |
2098 | } else { |
2099 | return (MBOX_INVALID_COMMAND); |
2100 | } |
2101 | } |
2102 | |
2103 | ISP_MEMZERO(q, QENTRY_LEN); |
2104 | plp = (isp_plogx_t *) q; |
2105 | plp->plogx_header.rqs_entry_count = 1; |
2106 | plp->plogx_header.rqs_entry_type = RQSTYPE_LOGIN; |
2107 | plp->plogx_handle = 0xffffffff; |
2108 | plp->plogx_nphdl = handle; |
2109 | plp->plogx_vphdl = chan; |
2110 | plp->plogx_portlo = portid; |
2111 | plp->plogx_rspsz_porthi = (portid >> 16) & 0xff; |
2112 | plp->plogx_flags = flags; |
2113 | |
2114 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
2115 | isp_print_bytes(isp, "IOCB LOGX" , QENTRY_LEN, plp); |
2116 | } |
2117 | |
2118 | if (gs == 0) { |
2119 | if (FC_SCRATCH_ACQUIRE(isp, chan)) { |
2120 | isp_prt(isp, ISP_LOGERR, sacq); |
2121 | return (-1); |
2122 | } |
2123 | } |
2124 | fcp = FCPARAM(isp, chan); |
2125 | scp = fcp->isp_scratch; |
2126 | isp_put_plogx(isp, plp, (isp_plogx_t *) scp); |
2127 | |
2128 | MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 500000); |
2129 | mbs.param[1] = QENTRY_LEN; |
2130 | mbs.param[2] = DMA_WD1(fcp->isp_scdma); |
2131 | mbs.param[3] = DMA_WD0(fcp->isp_scdma); |
2132 | mbs.param[6] = DMA_WD3(fcp->isp_scdma); |
2133 | mbs.param[7] = DMA_WD2(fcp->isp_scdma); |
2134 | MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN, chan); |
2135 | isp_mboxcmd(isp, &mbs); |
2136 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
2137 | rval = mbs.param[0]; |
2138 | goto out; |
2139 | } |
2140 | MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan); |
2141 | scp += QENTRY_LEN; |
2142 | isp_get_plogx(isp, (isp_plogx_t *) scp, plp); |
2143 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
2144 | isp_print_bytes(isp, "IOCB LOGX response" , QENTRY_LEN, plp); |
2145 | } |
2146 | |
2147 | if (plp->plogx_status == PLOGX_STATUS_OK) { |
2148 | rval = 0; |
2149 | goto out; |
2150 | } else if (plp->plogx_status != PLOGX_STATUS_IOCBERR) { |
2151 | isp_prt(isp, ISP_LOGWARN, |
2152 | "status 0x%x on port login IOCB chanel %d" , |
2153 | plp->plogx_status, chan); |
2154 | rval = -1; |
2155 | goto out; |
2156 | } |
2157 | |
2158 | sst = plp->plogx_ioparm[0].lo16 | (plp->plogx_ioparm[0].hi16 << 16); |
2159 | parm1 = plp->plogx_ioparm[1].lo16 | (plp->plogx_ioparm[1].hi16 << 16); |
2160 | |
2161 | rval = -1; |
2162 | msg = NULL; |
2163 | |
2164 | switch (sst) { |
2165 | case PLOGX_IOCBERR_NOLINK: |
2166 | msg = "no link" ; |
2167 | break; |
2168 | case PLOGX_IOCBERR_NOIOCB: |
2169 | msg = "no IOCB buffer" ; |
2170 | break; |
2171 | case PLOGX_IOCBERR_NOXGHG: |
2172 | msg = "no Exchange Control Block" ; |
2173 | break; |
2174 | case PLOGX_IOCBERR_FAILED: |
2175 | ISP_SNPRINTF(buf, sizeof (buf), "reason 0x%x (last LOGIN state 0x%x)" , parm1 & 0xff, (parm1 >> 8) & 0xff); |
2176 | msg = buf; |
2177 | break; |
2178 | case PLOGX_IOCBERR_NOFABRIC: |
2179 | msg = "no fabric" ; |
2180 | break; |
2181 | case PLOGX_IOCBERR_NOTREADY: |
2182 | msg = "firmware not ready" ; |
2183 | break; |
2184 | case PLOGX_IOCBERR_NOLOGIN: |
2185 | ISP_SNPRINTF(buf, sizeof (buf), "not logged in (last state 0x%x)" , parm1); |
2186 | msg = buf; |
2187 | rval = MBOX_NOT_LOGGED_IN; |
2188 | break; |
2189 | case PLOGX_IOCBERR_REJECT: |
2190 | ISP_SNPRINTF(buf, sizeof (buf), "LS_RJT = 0x%x" , parm1); |
2191 | msg = buf; |
2192 | break; |
2193 | case PLOGX_IOCBERR_NOPCB: |
2194 | msg = "no PCB allocated" ; |
2195 | break; |
2196 | case PLOGX_IOCBERR_EINVAL: |
2197 | ISP_SNPRINTF(buf, sizeof (buf), "invalid parameter at offset 0x%x" , parm1); |
2198 | msg = buf; |
2199 | break; |
2200 | case PLOGX_IOCBERR_PORTUSED: |
2201 | ISP_SNPRINTF(buf, sizeof (buf), "already logged in with N-Port handle 0x%x" , parm1); |
2202 | msg = buf; |
2203 | rval = MBOX_PORT_ID_USED | (parm1 << 16); |
2204 | break; |
2205 | case PLOGX_IOCBERR_HNDLUSED: |
2206 | ISP_SNPRINTF(buf, sizeof (buf), "handle already used for PortID 0x%06x" , parm1); |
2207 | msg = buf; |
2208 | rval = MBOX_LOOP_ID_USED; |
2209 | break; |
2210 | case PLOGX_IOCBERR_NOHANDLE: |
2211 | msg = "no handle allocated" ; |
2212 | break; |
2213 | case PLOGX_IOCBERR_NOFLOGI: |
2214 | msg = "no FLOGI_ACC" ; |
2215 | break; |
2216 | default: |
2217 | ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x" , plp->plogx_status, flags); |
2218 | msg = buf; |
2219 | break; |
2220 | } |
2221 | if (msg) { |
2222 | isp_prt(isp, ISP_LOGERR, "Chan %d PLOGX PortID 0x%06x to N-Port handle 0x%x: %s" , chan, portid, handle, msg); |
2223 | } |
2224 | out: |
2225 | if (gs == 0) { |
2226 | FC_SCRATCH_RELEASE(isp, chan); |
2227 | } |
2228 | return (rval); |
2229 | } |
2230 | |
2231 | static int |
2232 | isp_port_login(ispsoftc_t *isp, uint16_t handle, uint32_t portid) |
2233 | { |
2234 | mbreg_t mbs; |
2235 | |
2236 | MBSINIT(&mbs, MBOX_FABRIC_LOGIN, MBLOGNONE, 500000); |
2237 | if (ISP_CAP_2KLOGIN(isp)) { |
2238 | mbs.param[1] = handle; |
2239 | mbs.ibits = (1 << 10); |
2240 | } else { |
2241 | mbs.param[1] = handle << 8; |
2242 | } |
2243 | mbs.param[2] = portid >> 16; |
2244 | mbs.param[3] = portid; |
2245 | mbs.logval = MBLOGNONE; |
2246 | mbs.timeout = 500000; |
2247 | isp_mboxcmd(isp, &mbs); |
2248 | |
2249 | switch (mbs.param[0]) { |
2250 | case MBOX_PORT_ID_USED: |
2251 | isp_prt(isp, ISP_LOGDEBUG0, |
2252 | "isp_port_login: portid 0x%06x already logged in as %u" , |
2253 | portid, mbs.param[1]); |
2254 | return (MBOX_PORT_ID_USED | (mbs.param[1] << 16)); |
2255 | |
2256 | case MBOX_LOOP_ID_USED: |
2257 | isp_prt(isp, ISP_LOGDEBUG0, |
2258 | "isp_port_login: handle 0x%04x in use for port id 0x%02xXXXX" , |
2259 | handle, mbs.param[1] & 0xff); |
2260 | return (MBOX_LOOP_ID_USED); |
2261 | |
2262 | case MBOX_COMMAND_COMPLETE: |
2263 | return (0); |
2264 | |
2265 | case MBOX_COMMAND_ERROR: |
2266 | isp_prt(isp, ISP_LOGINFO, |
2267 | "isp_port_login: error 0x%x in PLOGI to port 0x%06x" , |
2268 | mbs.param[1], portid); |
2269 | return (MBOX_COMMAND_ERROR); |
2270 | |
2271 | case MBOX_ALL_IDS_USED: |
2272 | isp_prt(isp, ISP_LOGINFO, |
2273 | "isp_port_login: all IDs used for fabric login" ); |
2274 | return (MBOX_ALL_IDS_USED); |
2275 | |
2276 | default: |
2277 | isp_prt(isp, ISP_LOGINFO, |
2278 | "isp_port_login: error 0x%x on port login of 0x%06x@0x%0x" , |
2279 | mbs.param[0], portid, handle); |
2280 | return (mbs.param[0]); |
2281 | } |
2282 | } |
2283 | |
2284 | static int |
2285 | isp_port_logout(ispsoftc_t *isp, uint16_t handle, uint32_t portid) |
2286 | { |
2287 | mbreg_t mbs; |
2288 | |
2289 | MBSINIT(&mbs, MBOX_FABRIC_LOGOUT, MBLOGNONE, 500000); |
2290 | if (ISP_CAP_2KLOGIN(isp)) { |
2291 | mbs.param[1] = handle; |
2292 | mbs.ibits = (1 << 10); |
2293 | } else { |
2294 | mbs.param[1] = handle << 8; |
2295 | } |
2296 | isp_mboxcmd(isp, &mbs); |
2297 | return (mbs.param[0] == MBOX_COMMAND_COMPLETE? 0 : mbs.param[0]); |
2298 | } |
2299 | |
2300 | static int |
2301 | isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock) |
2302 | { |
2303 | fcparam *fcp = FCPARAM(isp, chan); |
2304 | mbreg_t mbs; |
2305 | union { |
2306 | isp_pdb_21xx_t fred; |
2307 | isp_pdb_24xx_t bill; |
2308 | } un; |
2309 | |
2310 | MBSINIT(&mbs, MBOX_GET_PORT_DB, MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR, 250000); |
2311 | if (IS_24XX(isp)) { |
2312 | mbs.ibits = (1 << 9)|(1 << 10); |
2313 | mbs.param[1] = id; |
2314 | mbs.param[9] = chan; |
2315 | } else if (ISP_CAP_2KLOGIN(isp)) { |
2316 | mbs.param[1] = id; |
2317 | } else { |
2318 | mbs.param[1] = id << 8; |
2319 | } |
2320 | mbs.param[2] = DMA_WD1(fcp->isp_scdma); |
2321 | mbs.param[3] = DMA_WD0(fcp->isp_scdma); |
2322 | mbs.param[6] = DMA_WD3(fcp->isp_scdma); |
2323 | mbs.param[7] = DMA_WD2(fcp->isp_scdma); |
2324 | if (dolock) { |
2325 | if (FC_SCRATCH_ACQUIRE(isp, chan)) { |
2326 | isp_prt(isp, ISP_LOGERR, sacq); |
2327 | return (-1); |
2328 | } |
2329 | } |
2330 | MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (un), chan); |
2331 | isp_mboxcmd(isp, &mbs); |
2332 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
2333 | if (dolock) { |
2334 | FC_SCRATCH_RELEASE(isp, chan); |
2335 | } |
2336 | return (mbs.param[0]); |
2337 | } |
2338 | if (IS_24XX(isp)) { |
2339 | isp_get_pdb_24xx(isp, fcp->isp_scratch, &un.bill); |
2340 | pdb->handle = un.bill.pdb_handle; |
2341 | pdb->s3_role = un.bill.pdb_prli_svc3; |
2342 | pdb->portid = BITS2WORD_24XX(un.bill.pdb_portid_bits); |
2343 | ISP_MEMCPY(pdb->portname, un.bill.pdb_portname, 8); |
2344 | ISP_MEMCPY(pdb->nodename, un.bill.pdb_nodename, 8); |
2345 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
2346 | "Chan %d Port 0x%06x flags 0x%x curstate %x" , |
2347 | chan, pdb->portid, un.bill.pdb_flags, |
2348 | un.bill.pdb_curstate); |
2349 | if (un.bill.pdb_curstate < PDB2400_STATE_PLOGI_DONE || |
2350 | un.bill.pdb_curstate > PDB2400_STATE_LOGGED_IN) { |
2351 | mbs.param[0] = MBOX_NOT_LOGGED_IN; |
2352 | if (dolock) { |
2353 | FC_SCRATCH_RELEASE(isp, chan); |
2354 | } |
2355 | return (mbs.param[0]); |
2356 | } |
2357 | } else { |
2358 | isp_get_pdb_21xx(isp, fcp->isp_scratch, &un.fred); |
2359 | pdb->handle = un.fred.pdb_loopid; |
2360 | pdb->s3_role = un.fred.pdb_prli_svc3; |
2361 | pdb->portid = BITS2WORD(un.fred.pdb_portid_bits); |
2362 | ISP_MEMCPY(pdb->portname, un.fred.pdb_portname, 8); |
2363 | ISP_MEMCPY(pdb->nodename, un.fred.pdb_nodename, 8); |
2364 | } |
2365 | if (dolock) { |
2366 | FC_SCRATCH_RELEASE(isp, chan); |
2367 | } |
2368 | return (0); |
2369 | } |
2370 | |
2371 | static void |
2372 | isp_dump_chip_portdb(ispsoftc_t *isp, int chan, int dolock) |
2373 | { |
2374 | isp_pdb_t pdb; |
2375 | int lim, loopid; |
2376 | |
2377 | if (ISP_CAP_2KLOGIN(isp)) { |
2378 | lim = NPH_MAX_2K; |
2379 | } else { |
2380 | lim = NPH_MAX; |
2381 | } |
2382 | for (loopid = 0; loopid != lim; loopid++) { |
2383 | if (isp_getpdb(isp, chan, loopid, &pdb, dolock)) { |
2384 | continue; |
2385 | } |
2386 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGINFO, "Chan %d Loopid 0x%04x " |
2387 | "PortID 0x%06x WWPN 0x%02x%02x%02x%02x%02x%02x%02x%02x" , |
2388 | chan, loopid, pdb.portid, pdb.portname[0], pdb.portname[1], |
2389 | pdb.portname[2], pdb.portname[3], pdb.portname[4], |
2390 | pdb.portname[5], pdb.portname[6], pdb.portname[7]); |
2391 | } |
2392 | } |
2393 | |
2394 | static uint64_t |
2395 | isp_get_wwn(ispsoftc_t *isp, int chan, int loopid, int nodename) |
2396 | { |
2397 | uint64_t wwn = INI_NONE; |
2398 | fcparam *fcp = FCPARAM(isp, chan); |
2399 | mbreg_t mbs; |
2400 | |
2401 | if (fcp->isp_fwstate < FW_READY || |
2402 | fcp->isp_loopstate < LOOP_PDB_RCVD) { |
2403 | return (wwn); |
2404 | } |
2405 | MBSINIT(&mbs, MBOX_GET_PORT_NAME, MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR, 500000); |
2406 | if (ISP_CAP_2KLOGIN(isp)) { |
2407 | mbs.param[1] = loopid; |
2408 | mbs.ibits = (1 << 10); |
2409 | if (nodename) { |
2410 | mbs.param[10] = 1; |
2411 | } |
2412 | if (ISP_CAP_MULTI_ID(isp)) { |
2413 | mbs.ibits |= (1 << 9); |
2414 | mbs.param[9] = chan; |
2415 | } |
2416 | } else { |
2417 | mbs.param[1] = loopid << 8; |
2418 | if (nodename) { |
2419 | mbs.param[1] |= 1; |
2420 | } |
2421 | } |
2422 | isp_mboxcmd(isp, &mbs); |
2423 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
2424 | return (wwn); |
2425 | } |
2426 | if (IS_24XX(isp)) { |
2427 | wwn = |
2428 | (((uint64_t)(mbs.param[2] >> 8)) << 56) | |
2429 | (((uint64_t)(mbs.param[2] & 0xff)) << 48) | |
2430 | (((uint64_t)(mbs.param[3] >> 8)) << 40) | |
2431 | (((uint64_t)(mbs.param[3] & 0xff)) << 32) | |
2432 | (((uint64_t)(mbs.param[6] >> 8)) << 24) | |
2433 | (((uint64_t)(mbs.param[6] & 0xff)) << 16) | |
2434 | (((uint64_t)(mbs.param[7] >> 8)) << 8) | |
2435 | (((uint64_t)(mbs.param[7] & 0xff))); |
2436 | } else { |
2437 | wwn = |
2438 | (((uint64_t)(mbs.param[2] & 0xff)) << 56) | |
2439 | (((uint64_t)(mbs.param[2] >> 8)) << 48) | |
2440 | (((uint64_t)(mbs.param[3] & 0xff)) << 40) | |
2441 | (((uint64_t)(mbs.param[3] >> 8)) << 32) | |
2442 | (((uint64_t)(mbs.param[6] & 0xff)) << 24) | |
2443 | (((uint64_t)(mbs.param[6] >> 8)) << 16) | |
2444 | (((uint64_t)(mbs.param[7] & 0xff)) << 8) | |
2445 | (((uint64_t)(mbs.param[7] >> 8))); |
2446 | } |
2447 | return (wwn); |
2448 | } |
2449 | |
2450 | /* |
2451 | * Make sure we have good FC link. |
2452 | */ |
2453 | |
2454 | static int |
2455 | isp_fclink_test(ispsoftc_t *isp, int chan, int usdelay) |
2456 | { |
2457 | mbreg_t mbs; |
2458 | int count, check_for_fabric, r; |
2459 | uint8_t lwfs; |
2460 | int loopid; |
2461 | fcparam *fcp; |
2462 | fcportdb_t *lp; |
2463 | isp_pdb_t pdb; |
2464 | |
2465 | fcp = FCPARAM(isp, chan); |
2466 | |
2467 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d FC Link Test Entry" , chan); |
2468 | ISP_MARK_PORTDB(isp, chan, 1); |
2469 | |
2470 | /* |
2471 | * Wait up to N microseconds for F/W to go to a ready state. |
2472 | */ |
2473 | lwfs = FW_CONFIG_WAIT; |
2474 | count = 0; |
2475 | while (count < usdelay) { |
2476 | uint64_t enano; |
2477 | uint32_t wrk; |
2478 | NANOTIME_T hra, hrb; |
2479 | |
2480 | GET_NANOTIME(&hra); |
2481 | isp_fw_state(isp, chan); |
2482 | if (lwfs != fcp->isp_fwstate) { |
2483 | isp_prt(isp, ISP_LOGCONFIG|ISP_LOGSANCFG, "Chan %d Firmware State <%s->%s>" , chan, isp_fc_fw_statename((int)lwfs), isp_fc_fw_statename((int)fcp->isp_fwstate)); |
2484 | lwfs = fcp->isp_fwstate; |
2485 | } |
2486 | if (fcp->isp_fwstate == FW_READY) { |
2487 | break; |
2488 | } |
2489 | GET_NANOTIME(&hrb); |
2490 | |
2491 | /* |
2492 | * Get the elapsed time in nanoseconds. |
2493 | * Always guaranteed to be non-zero. |
2494 | */ |
2495 | enano = NANOTIME_SUB(&hrb, &hra); |
2496 | |
2497 | isp_prt(isp, ISP_LOGDEBUG1, "usec%d: 0x%lx->0x%lx enano 0x%x%08x" , count, (long) GET_NANOSEC(&hra), (long) GET_NANOSEC(&hrb), (uint32_t)(enano >> 32), (uint32_t)(enano)); |
2498 | |
2499 | /* |
2500 | * If the elapsed time is less than 1 millisecond, |
2501 | * delay a period of time up to that millisecond of |
2502 | * waiting. |
2503 | * |
2504 | * This peculiar code is an attempt to try and avoid |
2505 | * invoking uint64_t math support functions for some |
2506 | * platforms where linkage is a problem. |
2507 | */ |
2508 | if (enano < (1000 * 1000)) { |
2509 | count += 1000; |
2510 | enano = (1000 * 1000) - enano; |
2511 | while (enano > (uint64_t) 4000000000U) { |
2512 | ISP_SLEEP(isp, 4000000); |
2513 | enano -= (uint64_t) 4000000000U; |
2514 | } |
2515 | wrk = enano; |
2516 | wrk /= 1000; |
2517 | ISP_SLEEP(isp, wrk); |
2518 | } else { |
2519 | while (enano > (uint64_t) 4000000000U) { |
2520 | count += 4000000; |
2521 | enano -= (uint64_t) 4000000000U; |
2522 | } |
2523 | wrk = enano; |
2524 | count += (wrk / 1000); |
2525 | } |
2526 | } |
2527 | |
2528 | |
2529 | |
2530 | /* |
2531 | * If we haven't gone to 'ready' state, return. |
2532 | */ |
2533 | if (fcp->isp_fwstate != FW_READY) { |
2534 | isp_prt(isp, ISP_LOGSANCFG, "%s: chan %d not at FW_READY state" , __func__, chan); |
2535 | return (-1); |
2536 | } |
2537 | |
2538 | /* |
2539 | * Get our Loop ID and Port ID. |
2540 | */ |
2541 | MBSINIT(&mbs, MBOX_GET_LOOP_ID, MBLOGALL, 0); |
2542 | if (ISP_CAP_MULTI_ID(isp)) { |
2543 | mbs.param[9] = chan; |
2544 | mbs.ibits = (1 << 9); |
2545 | mbs.obits = (1 << 7); |
2546 | } |
2547 | isp_mboxcmd(isp, &mbs); |
2548 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
2549 | return (-1); |
2550 | } |
2551 | |
2552 | if (ISP_CAP_2KLOGIN(isp)) { |
2553 | fcp->isp_loopid = mbs.param[1]; |
2554 | } else { |
2555 | fcp->isp_loopid = mbs.param[1] & 0xff; |
2556 | } |
2557 | |
2558 | if (IS_2100(isp)) { |
2559 | fcp->isp_topo = TOPO_NL_PORT; |
2560 | } else { |
2561 | int topo = (int) mbs.param[6]; |
2562 | if (topo < TOPO_NL_PORT || topo > TOPO_PTP_STUB) { |
2563 | topo = TOPO_PTP_STUB; |
2564 | } |
2565 | fcp->isp_topo = topo; |
2566 | } |
2567 | fcp->isp_portid = mbs.param[2] | (mbs.param[3] << 16); |
2568 | |
2569 | if (IS_2100(isp)) { |
2570 | /* |
2571 | * Don't bother with fabric if we are using really old |
2572 | * 2100 firmware. It's just not worth it. |
2573 | */ |
2574 | if (ISP_FW_NEWER_THAN(isp, 1, 15, 37)) { |
2575 | check_for_fabric = 1; |
2576 | } else { |
2577 | check_for_fabric = 0; |
2578 | } |
2579 | } else if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_F_PORT) { |
2580 | check_for_fabric = 1; |
2581 | } else { |
2582 | check_for_fabric = 0; |
2583 | } |
2584 | |
2585 | /* |
2586 | * Check to make sure we got a valid loopid |
2587 | * The 24XX seems to mess this up for multiple channels. |
2588 | */ |
2589 | if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_NL_PORT) { |
2590 | uint8_t alpa = fcp->isp_portid; |
2591 | |
2592 | if (alpa == 0) { |
2593 | /* "Cannot Happen" */ |
2594 | isp_prt(isp, ISP_LOGWARN, "Zero AL_PA for Loop Topology?" ); |
2595 | } else { |
2596 | int i; |
2597 | for (i = 0; alpa_map[i]; i++) { |
2598 | if (alpa_map[i] == alpa) { |
2599 | break; |
2600 | } |
2601 | } |
2602 | if (alpa_map[i] && fcp->isp_loopid != i) { |
2603 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d deriving loopid %d from AL_PA map (AL_PA 0x%x) and ignoring returned value %d (AL_PA 0x%x)" , chan, i, alpa_map[i], fcp->isp_loopid, alpa); |
2604 | fcp->isp_loopid = i; |
2605 | } |
2606 | } |
2607 | } |
2608 | |
2609 | |
2610 | if (IS_24XX(isp)) { /* XXX SHOULDN'T THIS BE FOR 2K F/W? XXX */ |
2611 | loopid = NPH_FL_ID; |
2612 | } else { |
2613 | loopid = FL_ID; |
2614 | } |
2615 | if (check_for_fabric) { |
2616 | r = isp_getpdb(isp, chan, loopid, &pdb, 1); |
2617 | if (r && (fcp->isp_topo == TOPO_F_PORT || fcp->isp_topo == TOPO_FL_PORT)) { |
2618 | isp_prt(isp, ISP_LOGWARN, "fabric topology but cannot get info about fabric controller (0x%x)" , r); |
2619 | fcp->isp_topo = TOPO_PTP_STUB; |
2620 | } |
2621 | } else { |
2622 | r = -1; |
2623 | } |
2624 | if (r == 0) { |
2625 | if (IS_2100(isp)) { |
2626 | fcp->isp_topo = TOPO_FL_PORT; |
2627 | } |
2628 | if (pdb.portid == 0) { |
2629 | /* |
2630 | * Crock. |
2631 | */ |
2632 | fcp->isp_topo = TOPO_NL_PORT; |
2633 | goto not_on_fabric; |
2634 | } |
2635 | |
2636 | /* |
2637 | * Save the Fabric controller's port database entry. |
2638 | */ |
2639 | lp = &fcp->portdb[FL_ID]; |
2640 | lp->state = FC_PORTDB_STATE_PENDING_VALID; |
2641 | MAKE_WWN_FROM_NODE_NAME(lp->node_wwn, pdb.nodename); |
2642 | MAKE_WWN_FROM_NODE_NAME(lp->port_wwn, pdb.portname); |
2643 | lp->roles = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; |
2644 | lp->portid = pdb.portid; |
2645 | lp->handle = pdb.handle; |
2646 | lp->new_portid = lp->portid; |
2647 | lp->new_roles = lp->roles; |
2648 | if (IS_24XX(isp)) { |
2649 | fcp->inorder = (mbs.param[7] & ISP24XX_INORDER) != 0; |
2650 | if (ISP_FW_NEWER_THAN(isp, 4, 0, 27)) { |
2651 | fcp->npiv_fabric = (mbs.param[7] & ISP24XX_NPIV_SAN) != 0; |
2652 | if (fcp->npiv_fabric) { |
2653 | isp_prt(isp, ISP_LOGCONFIG, "fabric supports NP-IV" ); |
2654 | } |
2655 | } |
2656 | if (chan) { |
2657 | fcp->isp_sns_hdl = NPH_SNS_HDLBASE + chan; |
2658 | r = isp_plogx(isp, chan, fcp->isp_sns_hdl, SNS_PORT_ID, PLOGX_FLG_CMD_PLOGI | PLOGX_FLG_COND_PLOGI | PLOGX_FLG_SKIP_PRLI, 0); |
2659 | if (r) { |
2660 | isp_prt(isp, ISP_LOGWARN, "%s: Chan %d cannot log into SNS" , __func__, chan); |
2661 | return (-1); |
2662 | } |
2663 | } else { |
2664 | fcp->isp_sns_hdl = NPH_SNS_ID; |
2665 | } |
2666 | r = isp_register_fc4_type_24xx(isp, chan); |
2667 | } else { |
2668 | fcp->isp_sns_hdl = SNS_ID; |
2669 | r = isp_register_fc4_type(isp, chan); |
2670 | } |
2671 | if (r) { |
2672 | isp_prt(isp, ISP_LOGWARN|ISP_LOGSANCFG, "%s: register fc4 type failed" , __func__); |
2673 | return (-1); |
2674 | } |
2675 | } else { |
2676 | not_on_fabric: |
2677 | fcp->portdb[FL_ID].state = FC_PORTDB_STATE_NIL; |
2678 | } |
2679 | |
2680 | fcp->isp_gbspeed = 1; |
2681 | if (IS_23XX(isp) || IS_24XX(isp)) { |
2682 | MBSINIT(&mbs, MBOX_GET_SET_DATA_RATE, MBLOGALL, 3000000); |
2683 | mbs.param[1] = MBGSD_GET_RATE; |
2684 | /* mbs.param[2] undefined if we're just getting rate */ |
2685 | isp_mboxcmd(isp, &mbs); |
2686 | if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { |
2687 | if (mbs.param[1] == MBGSD_EIGHTGB) { |
2688 | isp_prt(isp, ISP_LOGINFO, "Chan %d 8Gb link speed" , chan); |
2689 | fcp->isp_gbspeed = 8; |
2690 | } else if (mbs.param[1] == MBGSD_FOURGB) { |
2691 | isp_prt(isp, ISP_LOGINFO, "Chan %d 4Gb link speed" , chan); |
2692 | fcp->isp_gbspeed = 4; |
2693 | } else if (mbs.param[1] == MBGSD_TWOGB) { |
2694 | isp_prt(isp, ISP_LOGINFO, "Chan %d 2Gb link speed" , chan); |
2695 | fcp->isp_gbspeed = 2; |
2696 | } else if (mbs.param[1] == MBGSD_ONEGB) { |
2697 | isp_prt(isp, ISP_LOGINFO, "Chan %d 1Gb link speed" , chan); |
2698 | fcp->isp_gbspeed = 1; |
2699 | } |
2700 | } |
2701 | } |
2702 | |
2703 | /* |
2704 | * Announce ourselves, too. |
2705 | */ |
2706 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGCONFIG, topology, chan, (uint32_t) (fcp->isp_wwpn >> 32), (uint32_t) fcp->isp_wwpn, fcp->isp_portid, fcp->isp_loopid, isp_fc_toponame(fcp)); |
2707 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d FC Link Test Complete" , chan); |
2708 | return (0); |
2709 | } |
2710 | |
2711 | /* |
2712 | * Complete the synchronization of our Port Database. |
2713 | * |
2714 | * At this point, we've scanned the local loop (if any) and the fabric |
2715 | * and performed fabric logins on all new devices. |
2716 | * |
2717 | * Our task here is to go through our port database and remove any entities |
2718 | * that are still marked probational (issuing PLOGO for ones which we had |
2719 | * PLOGI'd into) or are dead. |
2720 | * |
2721 | * Our task here is to also check policy to decide whether devices which |
2722 | * have *changed* in some way should still be kept active. For example, |
2723 | * if a device has just changed PortID, we can either elect to treat it |
2724 | * as an old device or as a newly arrived device (and notify the outer |
2725 | * layer appropriately). |
2726 | * |
2727 | * We also do initiator map target id assignment here for new initiator |
2728 | * devices and refresh old ones ot make sure that they point to the corret |
2729 | * entities. |
2730 | */ |
2731 | static int |
2732 | isp_pdb_sync(ispsoftc_t *isp, int chan) |
2733 | { |
2734 | fcparam *fcp = FCPARAM(isp, chan); |
2735 | fcportdb_t *lp; |
2736 | uint16_t dbidx; |
2737 | |
2738 | if (fcp->isp_loopstate == LOOP_READY) { |
2739 | return (0); |
2740 | } |
2741 | |
2742 | /* |
2743 | * Make sure we're okay for doing this right now. |
2744 | */ |
2745 | if (fcp->isp_loopstate != LOOP_PDB_RCVD && |
2746 | fcp->isp_loopstate != LOOP_FSCAN_DONE && |
2747 | fcp->isp_loopstate != LOOP_LSCAN_DONE) { |
2748 | isp_prt(isp, ISP_LOGWARN, "isp_pdb_sync: bad loopstate %d" , |
2749 | fcp->isp_loopstate); |
2750 | return (-1); |
2751 | } |
2752 | |
2753 | if (fcp->isp_topo == TOPO_FL_PORT || |
2754 | fcp->isp_topo == TOPO_NL_PORT || |
2755 | fcp->isp_topo == TOPO_N_PORT) { |
2756 | if (fcp->isp_loopstate < LOOP_LSCAN_DONE) { |
2757 | if (isp_scan_loop(isp, chan) != 0) { |
2758 | isp_prt(isp, ISP_LOGWARN, |
2759 | "isp_pdb_sync: isp_scan_loop failed" ); |
2760 | return (-1); |
2761 | } |
2762 | } |
2763 | } |
2764 | |
2765 | if (fcp->isp_topo == TOPO_F_PORT || fcp->isp_topo == TOPO_FL_PORT) { |
2766 | if (fcp->isp_loopstate < LOOP_FSCAN_DONE) { |
2767 | if (isp_scan_fabric(isp, chan) != 0) { |
2768 | isp_prt(isp, ISP_LOGWARN, |
2769 | "isp_pdb_sync: isp_scan_fabric failed" ); |
2770 | return (-1); |
2771 | } |
2772 | } |
2773 | } |
2774 | |
2775 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
2776 | "Chan %d Synchronizing PDBs" , chan); |
2777 | |
2778 | fcp->isp_loopstate = LOOP_SYNCING_PDB; |
2779 | |
2780 | for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { |
2781 | lp = &fcp->portdb[dbidx]; |
2782 | |
2783 | if (lp->state == FC_PORTDB_STATE_NIL || lp->target_mode) { |
2784 | continue; |
2785 | } |
2786 | |
2787 | if (lp->state == FC_PORTDB_STATE_VALID) { |
2788 | if (dbidx != FL_ID) { |
2789 | isp_prt(isp, |
2790 | ISP_LOGERR, "portdb idx %d already valid" , |
2791 | dbidx); |
2792 | } |
2793 | continue; |
2794 | } |
2795 | |
2796 | switch (lp->state) { |
2797 | case FC_PORTDB_STATE_PROBATIONAL: |
2798 | case FC_PORTDB_STATE_DEAD: |
2799 | /* |
2800 | * It's up to the outer layers to clear isp_dev_map. |
2801 | */ |
2802 | lp->state = FC_PORTDB_STATE_NIL; |
2803 | isp_async(isp, ISPASYNC_DEV_GONE, chan, lp); |
2804 | if (lp->autologin == 0) { |
2805 | (void) isp_plogx(isp, chan, lp->handle, |
2806 | lp->portid, |
2807 | PLOGX_FLG_CMD_LOGO | |
2808 | PLOGX_FLG_IMPLICIT | |
2809 | PLOGX_FLG_FREE_NPHDL, 0); |
2810 | } else { |
2811 | lp->autologin = 0; |
2812 | } |
2813 | lp->new_roles = 0; |
2814 | lp->new_portid = 0; |
2815 | /* |
2816 | * Note that we might come out of this with our state |
2817 | * set to FC_PORTDB_STATE_ZOMBIE. |
2818 | */ |
2819 | break; |
2820 | case FC_PORTDB_STATE_NEW: |
2821 | /* |
2822 | * It's up to the outer layers to assign a virtual |
2823 | * target id in isp_dev_map (if any). |
2824 | */ |
2825 | lp->portid = lp->new_portid; |
2826 | lp->roles = lp->new_roles; |
2827 | lp->state = FC_PORTDB_STATE_VALID; |
2828 | isp_async(isp, ISPASYNC_DEV_ARRIVED, chan, lp); |
2829 | lp->new_roles = 0; |
2830 | lp->new_portid = 0; |
2831 | lp->reserved = 0; |
2832 | lp->new_reserved = 0; |
2833 | break; |
2834 | case FC_PORTDB_STATE_CHANGED: |
2835 | /* |
2836 | * XXXX FIX THIS |
2837 | */ |
2838 | lp->state = FC_PORTDB_STATE_VALID; |
2839 | isp_async(isp, ISPASYNC_DEV_CHANGED, chan, lp); |
2840 | lp->new_roles = 0; |
2841 | lp->new_portid = 0; |
2842 | lp->reserved = 0; |
2843 | lp->new_reserved = 0; |
2844 | break; |
2845 | case FC_PORTDB_STATE_PENDING_VALID: |
2846 | lp->portid = lp->new_portid; |
2847 | lp->roles = lp->new_roles; |
2848 | if (lp->dev_map_idx) { |
2849 | int t = lp->dev_map_idx - 1; |
2850 | fcp->isp_dev_map[t] = dbidx + 1; |
2851 | } |
2852 | lp->state = FC_PORTDB_STATE_VALID; |
2853 | isp_async(isp, ISPASYNC_DEV_STAYED, chan, lp); |
2854 | if (dbidx != FL_ID) { |
2855 | lp->new_roles = 0; |
2856 | lp->new_portid = 0; |
2857 | } |
2858 | lp->reserved = 0; |
2859 | lp->new_reserved = 0; |
2860 | break; |
2861 | case FC_PORTDB_STATE_ZOMBIE: |
2862 | break; |
2863 | default: |
2864 | isp_prt(isp, ISP_LOGWARN, |
2865 | "isp_scan_loop: state %d for idx %d" , |
2866 | lp->state, dbidx); |
2867 | isp_dump_portdb(isp, chan); |
2868 | } |
2869 | } |
2870 | |
2871 | /* |
2872 | * If we get here, we've for sure seen not only a valid loop |
2873 | * but know what is or isn't on it, so mark this for usage |
2874 | * in isp_start. |
2875 | */ |
2876 | fcp->loop_seen_once = 1; |
2877 | fcp->isp_loopstate = LOOP_READY; |
2878 | return (0); |
2879 | } |
2880 | |
2881 | /* |
2882 | * Scan local loop for devices. |
2883 | */ |
2884 | static int |
2885 | isp_scan_loop(ispsoftc_t *isp, int chan) |
2886 | { |
2887 | fcportdb_t *lp, tmp; |
2888 | fcparam *fcp = FCPARAM(isp, chan); |
2889 | int i; |
2890 | isp_pdb_t pdb; |
2891 | uint16_t handle, lim = 0; |
2892 | |
2893 | if (fcp->isp_fwstate < FW_READY || |
2894 | fcp->isp_loopstate < LOOP_PDB_RCVD) { |
2895 | return (-1); |
2896 | } |
2897 | |
2898 | if (fcp->isp_loopstate > LOOP_SCANNING_LOOP) { |
2899 | return (0); |
2900 | } |
2901 | |
2902 | /* |
2903 | * Check our connection topology. |
2904 | * |
2905 | * If we're a public or private loop, we scan 0..125 as handle values. |
2906 | * The firmware has (typically) peformed a PLOGI for us. We skip this |
2907 | * step if we're a ISP_24XX in NP-IV mode. |
2908 | * |
2909 | * If we're a N-port connection, we treat this is a short loop (0..1). |
2910 | */ |
2911 | switch (fcp->isp_topo) { |
2912 | case TOPO_NL_PORT: |
2913 | lim = LOCAL_LOOP_LIM; |
2914 | break; |
2915 | case TOPO_FL_PORT: |
2916 | if (IS_24XX(isp) && isp->isp_nchan > 1) { |
2917 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
2918 | "Chan %d Skipping Local Loop Scan" , chan); |
2919 | fcp->isp_loopstate = LOOP_LSCAN_DONE; |
2920 | return (0); |
2921 | } |
2922 | lim = LOCAL_LOOP_LIM; |
2923 | break; |
2924 | case TOPO_N_PORT: |
2925 | lim = 2; |
2926 | break; |
2927 | default: |
2928 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
2929 | "Chan %d no loop topology to scan" , chan); |
2930 | fcp->isp_loopstate = LOOP_LSCAN_DONE; |
2931 | return (0); |
2932 | } |
2933 | |
2934 | fcp->isp_loopstate = LOOP_SCANNING_LOOP; |
2935 | |
2936 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
2937 | "Chan %d FC scan loop 0..%d" , chan, lim-1); |
2938 | |
2939 | |
2940 | /* |
2941 | * Run through the list and get the port database info for each one. |
2942 | */ |
2943 | for (handle = 0; handle < lim; handle++) { |
2944 | int r; |
2945 | /* |
2946 | * Don't scan "special" ids. |
2947 | */ |
2948 | if (handle >= FL_ID && handle <= SNS_ID) { |
2949 | continue; |
2950 | } |
2951 | if (ISP_CAP_2KLOGIN(isp)) { |
2952 | if (handle >= NPH_RESERVED && handle <= NPH_FL_ID) { |
2953 | continue; |
2954 | } |
2955 | } |
2956 | /* |
2957 | * In older cards with older f/w GET_PORT_DATABASE has been |
2958 | * known to hang. This trick gets around that problem. |
2959 | */ |
2960 | if (IS_2100(isp) || IS_2200(isp)) { |
2961 | uint64_t node_wwn = isp_get_wwn(isp, chan, handle, 1); |
2962 | if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { |
2963 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
2964 | "Chan %d FC scan loop DONE (bad)" , chan); |
2965 | return (-1); |
2966 | } |
2967 | if (node_wwn == INI_NONE) { |
2968 | continue; |
2969 | } |
2970 | } |
2971 | |
2972 | /* |
2973 | * Get the port database entity for this index. |
2974 | */ |
2975 | r = isp_getpdb(isp, chan, handle, &pdb, 1); |
2976 | if (r != 0) { |
2977 | isp_prt(isp, ISP_LOGDEBUG1, |
2978 | "Chan %d FC scan loop handle %d returned %x" , |
2979 | chan, handle, r); |
2980 | if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { |
2981 | ISP_MARK_PORTDB(isp, chan, 1); |
2982 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
2983 | "Chan %d FC scan loop DONE (bad)" , chan); |
2984 | return (-1); |
2985 | } |
2986 | continue; |
2987 | } |
2988 | |
2989 | if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { |
2990 | ISP_MARK_PORTDB(isp, chan, 1); |
2991 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
2992 | "Chan %d FC scan loop DONE (bad)" , chan); |
2993 | return (-1); |
2994 | } |
2995 | |
2996 | /* |
2997 | * On *very* old 2100 firmware we would end up sometimes |
2998 | * with the firmware returning the port database entry |
2999 | * for something else. We used to restart this, but |
3000 | * now we just punt. |
3001 | */ |
3002 | if (IS_2100(isp) && pdb.handle != handle) { |
3003 | isp_prt(isp, ISP_LOGWARN, |
3004 | "Chan %d cannot synchronize port database" , chan); |
3005 | ISP_MARK_PORTDB(isp, chan, 1); |
3006 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3007 | "Chan %d FC scan loop DONE (bad)" , chan); |
3008 | return (-1); |
3009 | } |
3010 | |
3011 | /* |
3012 | * Save the pertinent info locally. |
3013 | */ |
3014 | MAKE_WWN_FROM_NODE_NAME(tmp.node_wwn, pdb.nodename); |
3015 | MAKE_WWN_FROM_NODE_NAME(tmp.port_wwn, pdb.portname); |
3016 | tmp.roles = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; |
3017 | tmp.portid = pdb.portid; |
3018 | tmp.handle = pdb.handle; |
3019 | |
3020 | /* |
3021 | * Check to make sure it's still a valid entry. The 24XX seems |
3022 | * to return a portid but not a WWPN/WWNN or role for devices |
3023 | * which shift on a loop. |
3024 | */ |
3025 | if (tmp.node_wwn == 0 || tmp.port_wwn == 0 || tmp.portid == 0) { |
3026 | int a, b, c; |
3027 | a = (tmp.node_wwn == 0); |
3028 | b = (tmp.port_wwn == 0); |
3029 | c = (tmp.portid == 0); |
3030 | if (a == 0 && b == 0) { |
3031 | tmp.node_wwn = |
3032 | isp_get_wwn(isp, chan, handle, 1); |
3033 | tmp.port_wwn = |
3034 | isp_get_wwn(isp, chan, handle, 0); |
3035 | if (tmp.node_wwn && tmp.port_wwn) { |
3036 | isp_prt(isp, ISP_LOGINFO, "DODGED!" ); |
3037 | goto cont; |
3038 | } |
3039 | } |
3040 | isp_prt(isp, ISP_LOGWARN, |
3041 | "Chan %d bad pdb (%1d%1d%1d) @ handle 0x%x" , chan, |
3042 | a, b, c, handle); |
3043 | isp_dump_portdb(isp, chan); |
3044 | continue; |
3045 | } |
3046 | cont: |
3047 | |
3048 | /* |
3049 | * Now search the entire port database |
3050 | * for the same Port and Node WWN. |
3051 | */ |
3052 | for (i = 0; i < MAX_FC_TARG; i++) { |
3053 | lp = &fcp->portdb[i]; |
3054 | |
3055 | if (lp->state == FC_PORTDB_STATE_NIL || |
3056 | lp->target_mode) { |
3057 | continue; |
3058 | } |
3059 | if (lp->node_wwn != tmp.node_wwn) { |
3060 | continue; |
3061 | } |
3062 | if (lp->port_wwn != tmp.port_wwn) { |
3063 | continue; |
3064 | } |
3065 | |
3066 | /* |
3067 | * Okay- we've found a non-nil entry that matches. |
3068 | * Check to make sure it's probational or a zombie. |
3069 | */ |
3070 | if (lp->state != FC_PORTDB_STATE_PROBATIONAL && |
3071 | lp->state != FC_PORTDB_STATE_ZOMBIE) { |
3072 | isp_prt(isp, ISP_LOGERR, |
3073 | "Chan %d [%d] not probational/zombie (0x%x)" , |
3074 | chan, i, lp->state); |
3075 | isp_dump_portdb(isp, chan); |
3076 | ISP_MARK_PORTDB(isp, chan, 1); |
3077 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3078 | "Chan %d FC scan loop DONE (bad)" , chan); |
3079 | return (-1); |
3080 | } |
3081 | |
3082 | /* |
3083 | * Mark the device as something the f/w logs into |
3084 | * automatically. |
3085 | */ |
3086 | lp->autologin = 1; |
3087 | |
3088 | /* |
3089 | * Check to make see if really still the same |
3090 | * device. If it is, we mark it pending valid. |
3091 | */ |
3092 | if (lp->portid == tmp.portid && |
3093 | lp->handle == tmp.handle && |
3094 | lp->roles == tmp.roles) { |
3095 | lp->new_portid = tmp.portid; |
3096 | lp->new_roles = tmp.roles; |
3097 | lp->state = FC_PORTDB_STATE_PENDING_VALID; |
3098 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3099 | "Chan %d Loop Port 0x%06x@0x%04x Pending " |
3100 | "Valid" , chan, tmp.portid, tmp.handle); |
3101 | break; |
3102 | } |
3103 | |
3104 | /* |
3105 | * We can wipe out the old handle value |
3106 | * here because it's no longer valid. |
3107 | */ |
3108 | lp->handle = tmp.handle; |
3109 | |
3110 | /* |
3111 | * Claim that this has changed and let somebody else |
3112 | * decide what to do. |
3113 | */ |
3114 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3115 | "Chan %d Loop Port 0x%06x@0x%04x changed" , |
3116 | chan, tmp.portid, tmp.handle); |
3117 | lp->state = FC_PORTDB_STATE_CHANGED; |
3118 | lp->new_portid = tmp.portid; |
3119 | lp->new_roles = tmp.roles; |
3120 | break; |
3121 | } |
3122 | |
3123 | /* |
3124 | * Did we find and update an old entry? |
3125 | */ |
3126 | if (i < MAX_FC_TARG) { |
3127 | continue; |
3128 | } |
3129 | |
3130 | /* |
3131 | * Ah. A new device entry. Find an empty slot |
3132 | * for it and save info for later disposition. |
3133 | */ |
3134 | for (i = 0; i < MAX_FC_TARG; i++) { |
3135 | if (fcp->portdb[i].target_mode) { |
3136 | continue; |
3137 | } |
3138 | if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) { |
3139 | break; |
3140 | } |
3141 | } |
3142 | if (i == MAX_FC_TARG) { |
3143 | isp_prt(isp, ISP_LOGERR, |
3144 | "Chan %d out of portdb entries" , chan); |
3145 | continue; |
3146 | } |
3147 | lp = &fcp->portdb[i]; |
3148 | |
3149 | ISP_MEMZERO(lp, sizeof (fcportdb_t)); |
3150 | lp->autologin = 1; |
3151 | lp->state = FC_PORTDB_STATE_NEW; |
3152 | lp->new_portid = tmp.portid; |
3153 | lp->new_roles = tmp.roles; |
3154 | lp->handle = tmp.handle; |
3155 | lp->port_wwn = tmp.port_wwn; |
3156 | lp->node_wwn = tmp.node_wwn; |
3157 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3158 | "Chan %d Loop Port 0x%06x@0x%04x is New Entry" , |
3159 | chan, tmp.portid, tmp.handle); |
3160 | } |
3161 | fcp->isp_loopstate = LOOP_LSCAN_DONE; |
3162 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3163 | "Chan %d FC scan loop DONE" , chan); |
3164 | return (0); |
3165 | } |
3166 | |
3167 | /* |
3168 | * Scan the fabric for devices and add them to our port database. |
3169 | * |
3170 | * Use the GID_FT command to get all Port IDs for FC4 SCSI devices it knows. |
3171 | * |
3172 | * For 2100-23XX cards, we can use the SNS mailbox command to pass simple |
3173 | * name server commands to the switch management server via the QLogic f/w. |
3174 | * |
3175 | * For the 24XX card, we have to use CT-Pass through run via the Execute IOCB |
3176 | * mailbox command. |
3177 | * |
3178 | * The net result is to leave the list of Port IDs setting untranslated in |
3179 | * offset IGPOFF of the FC scratch area, whereupon we'll canonicalize it to |
3180 | * host order at OGPOFF. |
3181 | */ |
3182 | |
3183 | /* |
3184 | * Take less than half of our scratch area to store Port IDs |
3185 | */ |
3186 | #define GIDLEN ((ISP_FC_SCRLEN >> 1) - 16 - SNS_GID_FT_REQ_SIZE) |
3187 | #define NGENT ((GIDLEN - 16) >> 2) |
3188 | |
3189 | #define IGPOFF (2 * QENTRY_LEN) |
3190 | #define OGPOFF (ISP_FC_SCRLEN >> 1) |
3191 | #define ZTXOFF (ISP_FC_SCRLEN - (1 * QENTRY_LEN)) |
3192 | #define CTXOFF (ISP_FC_SCRLEN - (2 * QENTRY_LEN)) |
3193 | #define XTXOFF (ISP_FC_SCRLEN - (3 * QENTRY_LEN)) |
3194 | |
3195 | static int |
3196 | isp_gid_ft_sns(ispsoftc_t *isp, int chan) |
3197 | { |
3198 | union { |
3199 | sns_gid_ft_req_t _x; |
3200 | uint8_t _y[SNS_GID_FT_REQ_SIZE]; |
3201 | } un; |
3202 | fcparam *fcp = FCPARAM(isp, chan); |
3203 | sns_gid_ft_req_t *rq = &un._x; |
3204 | mbreg_t mbs; |
3205 | |
3206 | isp_prt(isp, ISP_LOGDEBUG0, |
3207 | "Chan %d scanning fabric (GID_FT) via SNS" , chan); |
3208 | |
3209 | ISP_MEMZERO(rq, SNS_GID_FT_REQ_SIZE); |
3210 | rq->snscb_rblen = GIDLEN >> 1; |
3211 | rq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma + IGPOFF); |
3212 | rq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma + IGPOFF); |
3213 | rq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma + IGPOFF); |
3214 | rq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma + IGPOFF); |
3215 | rq->snscb_sblen = 6; |
3216 | rq->snscb_cmd = SNS_GID_FT; |
3217 | rq->snscb_mword_div_2 = NGENT; |
3218 | rq->snscb_fc4_type = FC4_SCSI; |
3219 | |
3220 | isp_put_gid_ft_request(isp, rq, fcp->isp_scratch); |
3221 | MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GID_FT_REQ_SIZE, chan); |
3222 | |
3223 | MBSINIT(&mbs, MBOX_SEND_SNS, MBLOGALL, 10000000); |
3224 | mbs.param[0] = MBOX_SEND_SNS; |
3225 | mbs.param[1] = SNS_GID_FT_REQ_SIZE >> 1; |
3226 | mbs.param[2] = DMA_WD1(fcp->isp_scdma); |
3227 | mbs.param[3] = DMA_WD0(fcp->isp_scdma); |
3228 | mbs.param[6] = DMA_WD3(fcp->isp_scdma); |
3229 | mbs.param[7] = DMA_WD2(fcp->isp_scdma); |
3230 | isp_mboxcmd(isp, &mbs); |
3231 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
3232 | if (mbs.param[0] == MBOX_INVALID_COMMAND) { |
3233 | return (1); |
3234 | } else { |
3235 | return (-1); |
3236 | } |
3237 | } |
3238 | return (0); |
3239 | } |
3240 | |
3241 | static int |
3242 | isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan) |
3243 | { |
3244 | mbreg_t mbs; |
3245 | fcparam *fcp = FCPARAM(isp, chan); |
3246 | union { |
3247 | isp_ct_pt_t plocal; |
3248 | ct_hdr_t clocal; |
3249 | uint8_t q[QENTRY_LEN]; |
3250 | } un; |
3251 | isp_ct_pt_t *pt; |
3252 | ct_hdr_t *ct; |
3253 | uint32_t *rp; |
3254 | uint8_t *scp = fcp->isp_scratch; |
3255 | |
3256 | isp_prt(isp, ISP_LOGDEBUG0, |
3257 | "Chan %d scanning fabric (GID_FT) via CT" , chan); |
3258 | |
3259 | if (!IS_24XX(isp)) { |
3260 | return (1); |
3261 | } |
3262 | |
3263 | /* |
3264 | * Build a Passthrough IOCB in memory. |
3265 | */ |
3266 | pt = &un.plocal; |
3267 | ISP_MEMZERO(un.q, QENTRY_LEN); |
3268 | pt->ctp_header.rqs_entry_count = 1; |
3269 | pt->ctp_header.rqs_entry_type = RQSTYPE_CT_PASSTHRU; |
3270 | pt->ctp_handle = 0xffffffff; |
3271 | pt->ctp_nphdl = fcp->isp_sns_hdl; |
3272 | pt->ctp_cmd_cnt = 1; |
3273 | pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan); |
3274 | pt->ctp_time = 30; |
3275 | pt->ctp_rsp_cnt = 1; |
3276 | pt->ctp_rsp_bcnt = GIDLEN; |
3277 | pt->ctp_cmd_bcnt = sizeof (*ct) + sizeof (uint32_t); |
3278 | pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF); |
3279 | pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF); |
3280 | pt->ctp_dataseg[0].ds_count = sizeof (*ct) + sizeof (uint32_t); |
3281 | pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF); |
3282 | pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF); |
3283 | pt->ctp_dataseg[1].ds_count = GIDLEN; |
3284 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
3285 | isp_print_bytes(isp, "ct IOCB" , QENTRY_LEN, pt); |
3286 | } |
3287 | isp_put_ct_pt(isp, pt, (isp_ct_pt_t *) &scp[CTXOFF]); |
3288 | |
3289 | /* |
3290 | * Build the CT header and command in memory. |
3291 | * |
3292 | * Note that the CT header has to end up as Big Endian format in memory. |
3293 | */ |
3294 | ct = &un.clocal; |
3295 | ISP_MEMZERO(ct, sizeof (*ct)); |
3296 | ct->ct_revision = CT_REVISION; |
3297 | ct->ct_fcs_type = CT_FC_TYPE_FC; |
3298 | ct->ct_fcs_subtype = CT_FC_SUBTYPE_NS; |
3299 | ct->ct_cmd_resp = SNS_GID_FT; |
3300 | ct->ct_bcnt_resid = (GIDLEN - 16) >> 2; |
3301 | |
3302 | isp_put_ct_hdr(isp, ct, (ct_hdr_t *) &scp[XTXOFF]); |
3303 | rp = (uint32_t *) &scp[XTXOFF+sizeof (*ct)]; |
3304 | ISP_IOZPUT_32(isp, FC4_SCSI, rp); |
3305 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
3306 | isp_print_bytes(isp, "CT HDR + payload after put" , |
3307 | sizeof (*ct) + sizeof (uint32_t), &scp[XTXOFF]); |
3308 | } |
3309 | ISP_MEMZERO(&scp[ZTXOFF], QENTRY_LEN); |
3310 | MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 500000); |
3311 | mbs.param[1] = QENTRY_LEN; |
3312 | mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF); |
3313 | mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF); |
3314 | mbs.param[6] = DMA_WD3(fcp->isp_scdma + CTXOFF); |
3315 | mbs.param[7] = DMA_WD2(fcp->isp_scdma + CTXOFF); |
3316 | MEMORYBARRIER(isp, SYNC_SFORDEV, XTXOFF, 2 * QENTRY_LEN, chan); |
3317 | isp_mboxcmd(isp, &mbs); |
3318 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
3319 | return (-1); |
3320 | } |
3321 | MEMORYBARRIER(isp, SYNC_SFORCPU, ZTXOFF, QENTRY_LEN, chan); |
3322 | pt = &un.plocal; |
3323 | isp_get_ct_pt(isp, (isp_ct_pt_t *) &scp[ZTXOFF], pt); |
3324 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
3325 | isp_print_bytes(isp, "IOCB response" , QENTRY_LEN, pt); |
3326 | } |
3327 | |
3328 | if (pt->ctp_status && pt->ctp_status != RQCS_DATA_UNDERRUN) { |
3329 | isp_prt(isp, ISP_LOGWARN, |
3330 | "Chan %d ISP GID FT CT Passthrough returned 0x%x" , |
3331 | chan, pt->ctp_status); |
3332 | return (-1); |
3333 | } |
3334 | MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN + 16, chan); |
3335 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
3336 | isp_print_bytes(isp, "CT response" , GIDLEN+16, &scp[IGPOFF]); |
3337 | } |
3338 | return (0); |
3339 | } |
3340 | |
3341 | static int |
3342 | isp_scan_fabric(ispsoftc_t *isp, int chan) |
3343 | { |
3344 | fcparam *fcp = FCPARAM(isp, chan); |
3345 | uint32_t portid; |
3346 | uint16_t handle, oldhandle, loopid; |
3347 | isp_pdb_t pdb; |
3348 | int portidx, portlim, r; |
3349 | sns_gid_ft_rsp_t *rs0, *rs1; |
3350 | |
3351 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3352 | "Chan %d FC Scan Fabric" , chan); |
3353 | if (fcp->isp_fwstate != FW_READY || |
3354 | fcp->isp_loopstate < LOOP_LSCAN_DONE) { |
3355 | return (-1); |
3356 | } |
3357 | if (fcp->isp_loopstate > LOOP_SCANNING_FABRIC) { |
3358 | return (0); |
3359 | } |
3360 | if (fcp->isp_topo != TOPO_FL_PORT && fcp->isp_topo != TOPO_F_PORT) { |
3361 | fcp->isp_loopstate = LOOP_FSCAN_DONE; |
3362 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3363 | "Chan %d FC Scan Fabric Done (no fabric)" , chan); |
3364 | return (0); |
3365 | } |
3366 | |
3367 | fcp->isp_loopstate = LOOP_SCANNING_FABRIC; |
3368 | if (FC_SCRATCH_ACQUIRE(isp, chan)) { |
3369 | isp_prt(isp, ISP_LOGERR, sacq); |
3370 | ISP_MARK_PORTDB(isp, chan, 1); |
3371 | return (-1); |
3372 | } |
3373 | if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { |
3374 | FC_SCRATCH_RELEASE(isp, chan); |
3375 | ISP_MARK_PORTDB(isp, chan, 1); |
3376 | return (-1); |
3377 | } |
3378 | |
3379 | /* |
3380 | * Make sure we still are logged into the fabric controller. |
3381 | */ |
3382 | if (IS_24XX(isp)) { /* XXX SHOULDN'T THIS BE TRUE FOR 2K F/W? XXX */ |
3383 | loopid = NPH_FL_ID; |
3384 | } else { |
3385 | loopid = FL_ID; |
3386 | } |
3387 | r = isp_getpdb(isp, chan, loopid, &pdb, 0); |
3388 | if (r == MBOX_NOT_LOGGED_IN) { |
3389 | isp_dump_chip_portdb(isp, chan, 0); |
3390 | } |
3391 | if (r) { |
3392 | fcp->isp_loopstate = LOOP_PDB_RCVD; |
3393 | FC_SCRATCH_RELEASE(isp, chan); |
3394 | ISP_MARK_PORTDB(isp, chan, 1); |
3395 | return (-1); |
3396 | } |
3397 | |
3398 | if (IS_24XX(isp)) { |
3399 | r = isp_gid_ft_ct_passthru(isp, chan); |
3400 | } else { |
3401 | r = isp_gid_ft_sns(isp, chan); |
3402 | } |
3403 | |
3404 | if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { |
3405 | FC_SCRATCH_RELEASE(isp, chan); |
3406 | ISP_MARK_PORTDB(isp, chan, 1); |
3407 | return (-1); |
3408 | } |
3409 | |
3410 | if (r > 0) { |
3411 | fcp->isp_loopstate = LOOP_FSCAN_DONE; |
3412 | FC_SCRATCH_RELEASE(isp, chan); |
3413 | return (0); |
3414 | } else if (r < 0) { |
3415 | fcp->isp_loopstate = LOOP_PDB_RCVD; /* try again */ |
3416 | FC_SCRATCH_RELEASE(isp, chan); |
3417 | return (0); |
3418 | } |
3419 | |
3420 | MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN, chan); |
3421 | rs0 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+IGPOFF); |
3422 | rs1 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+OGPOFF); |
3423 | isp_get_gid_ft_response(isp, rs0, rs1, NGENT); |
3424 | if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { |
3425 | FC_SCRATCH_RELEASE(isp, chan); |
3426 | ISP_MARK_PORTDB(isp, chan, 1); |
3427 | return (-1); |
3428 | } |
3429 | if (rs1->snscb_cthdr.ct_cmd_resp != LS_ACC) { |
3430 | int level; |
3431 | if (rs1->snscb_cthdr.ct_reason == 9 && |
3432 | rs1->snscb_cthdr.ct_explanation == 7) { |
3433 | level = ISP_LOGSANCFG|ISP_LOGDEBUG0; |
3434 | } else { |
3435 | level = ISP_LOGWARN; |
3436 | } |
3437 | isp_prt(isp, level, "Chan %d Fabric Nameserver rejected GID_FT" |
3438 | " (Reason=0x%x Expl=0x%x)" , chan, |
3439 | rs1->snscb_cthdr.ct_reason, |
3440 | rs1->snscb_cthdr.ct_explanation); |
3441 | FC_SCRATCH_RELEASE(isp, chan); |
3442 | fcp->isp_loopstate = LOOP_FSCAN_DONE; |
3443 | return (0); |
3444 | } |
3445 | |
3446 | |
3447 | /* |
3448 | * If we get this far, we certainly still have the fabric controller. |
3449 | */ |
3450 | fcp->portdb[FL_ID].state = FC_PORTDB_STATE_PENDING_VALID; |
3451 | |
3452 | /* |
3453 | * Prime the handle we will start using. |
3454 | */ |
3455 | oldhandle = FCPARAM(isp, 0)->isp_lasthdl; |
3456 | |
3457 | /* |
3458 | * Go through the list and remove duplicate port ids. |
3459 | */ |
3460 | |
3461 | portlim = 0; |
3462 | portidx = 0; |
3463 | for (portidx = 0; portidx < NGENT-1; portidx++) { |
3464 | if (rs1->snscb_ports[portidx].control & 0x80) { |
3465 | break; |
3466 | } |
3467 | } |
3468 | |
3469 | /* |
3470 | * If we're not at the last entry, our list wasn't big enough. |
3471 | */ |
3472 | if ((rs1->snscb_ports[portidx].control & 0x80) == 0) { |
3473 | isp_prt(isp, ISP_LOGWARN, |
3474 | "fabric too big for scratch area: increase ISP_FC_SCRLEN" ); |
3475 | } |
3476 | portlim = portidx + 1; |
3477 | isp_prt(isp, ISP_LOGSANCFG, |
3478 | "Chan %d got %d ports back from name server" , chan, portlim); |
3479 | |
3480 | for (portidx = 0; portidx < portlim; portidx++) { |
3481 | int npidx; |
3482 | |
3483 | portid = |
3484 | ((rs1->snscb_ports[portidx].portid[0]) << 16) | |
3485 | ((rs1->snscb_ports[portidx].portid[1]) << 8) | |
3486 | ((rs1->snscb_ports[portidx].portid[2])); |
3487 | |
3488 | for (npidx = portidx + 1; npidx < portlim; npidx++) { |
3489 | uint32_t new_portid = |
3490 | ((rs1->snscb_ports[npidx].portid[0]) << 16) | |
3491 | ((rs1->snscb_ports[npidx].portid[1]) << 8) | |
3492 | ((rs1->snscb_ports[npidx].portid[2])); |
3493 | if (new_portid == portid) { |
3494 | break; |
3495 | } |
3496 | } |
3497 | |
3498 | if (npidx < portlim) { |
3499 | rs1->snscb_ports[npidx].portid[0] = 0; |
3500 | rs1->snscb_ports[npidx].portid[1] = 0; |
3501 | rs1->snscb_ports[npidx].portid[2] = 0; |
3502 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3503 | "Chan %d removing duplicate PortID 0x%06x" |
3504 | " entry from list" , chan, portid); |
3505 | } |
3506 | } |
3507 | |
3508 | /* |
3509 | * We now have a list of Port IDs for all FC4 SCSI devices |
3510 | * that the Fabric Name server knows about. |
3511 | * |
3512 | * For each entry on this list go through our port database looking |
3513 | * for probational entries- if we find one, then an old entry is |
3514 | * maybe still this one. We get some information to find out. |
3515 | * |
3516 | * Otherwise, it's a new fabric device, and we log into it |
3517 | * (unconditionally). After searching the entire database |
3518 | * again to make sure that we never ever ever ever have more |
3519 | * than one entry that has the same PortID or the same |
3520 | * WWNN/WWPN duple, we enter the device into our database. |
3521 | */ |
3522 | |
3523 | for (portidx = 0; portidx < portlim; portidx++) { |
3524 | fcportdb_t *lp; |
3525 | uint64_t wwnn, wwpn; |
3526 | int dbidx, nr; |
3527 | |
3528 | portid = |
3529 | ((rs1->snscb_ports[portidx].portid[0]) << 16) | |
3530 | ((rs1->snscb_ports[portidx].portid[1]) << 8) | |
3531 | ((rs1->snscb_ports[portidx].portid[2])); |
3532 | |
3533 | if (portid == 0) { |
3534 | isp_prt(isp, ISP_LOGSANCFG, |
3535 | "Chan %d skipping null PortID at idx %d" , |
3536 | chan, portidx); |
3537 | continue; |
3538 | } |
3539 | |
3540 | /* |
3541 | * Skip ourselves here and on other channels. If we're |
3542 | * multi-id, we can't check the portids in other FCPARAM |
3543 | * arenas because the resolutions here aren't synchronized. |
3544 | * The best way to do this is to exclude looking at portids |
3545 | * that have the same domain and area code as our own |
3546 | * portid. |
3547 | */ |
3548 | if (ISP_CAP_MULTI_ID(isp)) { |
3549 | if ((portid >> 8) == (fcp->isp_portid >> 8)) { |
3550 | isp_prt(isp, ISP_LOGSANCFG, |
3551 | "Chan %d skip PortID 0x%06x" , |
3552 | chan, portid); |
3553 | continue; |
3554 | } |
3555 | } else if (portid == fcp->isp_portid) { |
3556 | isp_prt(isp, ISP_LOGSANCFG, |
3557 | "Chan %d skip ourselves on @ PortID 0x%06x" , |
3558 | chan, portid); |
3559 | continue; |
3560 | } |
3561 | |
3562 | isp_prt(isp, ISP_LOGSANCFG, |
3563 | "Chan %d Checking Fabric Port 0x%06x" , chan, portid); |
3564 | |
3565 | /* |
3566 | * We now search our Port Database for any |
3567 | * probational entries with this PortID. We don't |
3568 | * look for zombies here- only probational |
3569 | * entries (we've already logged out of zombies). |
3570 | */ |
3571 | for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { |
3572 | lp = &fcp->portdb[dbidx]; |
3573 | |
3574 | if (lp->state != FC_PORTDB_STATE_PROBATIONAL || |
3575 | lp->target_mode) { |
3576 | continue; |
3577 | } |
3578 | if (lp->portid == portid) { |
3579 | break; |
3580 | } |
3581 | } |
3582 | |
3583 | /* |
3584 | * We found a probational entry with this Port ID. |
3585 | */ |
3586 | if (dbidx < MAX_FC_TARG) { |
3587 | int handle_changed = 0; |
3588 | |
3589 | lp = &fcp->portdb[dbidx]; |
3590 | |
3591 | /* |
3592 | * See if we're still logged into it. |
3593 | * |
3594 | * If we aren't, mark it as a dead device and |
3595 | * leave the new portid in the database entry |
3596 | * for somebody further along to decide what to |
3597 | * do (policy choice). |
3598 | * |
3599 | * If we are, check to see if it's the same |
3600 | * device still (it should be). If for some |
3601 | * reason it isn't, mark it as a changed device |
3602 | * and leave the new portid and role in the |
3603 | * database entry for somebody further along to |
3604 | * decide what to do (policy choice). |
3605 | * |
3606 | */ |
3607 | |
3608 | r = isp_getpdb(isp, chan, lp->handle, &pdb, 0); |
3609 | if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { |
3610 | FC_SCRATCH_RELEASE(isp, chan); |
3611 | ISP_MARK_PORTDB(isp, chan, 1); |
3612 | return (-1); |
3613 | } |
3614 | if (r != 0) { |
3615 | lp->new_portid = portid; |
3616 | lp->state = FC_PORTDB_STATE_DEAD; |
3617 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3618 | "Chan %d Fabric Port 0x%06x is dead" , |
3619 | chan, portid); |
3620 | continue; |
3621 | } |
3622 | |
3623 | |
3624 | /* |
3625 | * Check to make sure that handle, portid, WWPN and |
3626 | * WWNN agree. If they don't, then the association |
3627 | * between this PortID and the stated handle has been |
3628 | * broken by the firmware. |
3629 | */ |
3630 | MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); |
3631 | MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname); |
3632 | if (pdb.handle != lp->handle || |
3633 | pdb.portid != portid || |
3634 | wwpn != lp->port_wwn || |
3635 | wwnn != lp->node_wwn) { |
3636 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3637 | fconf, chan, dbidx, pdb.handle, pdb.portid, |
3638 | (uint32_t) (wwnn >> 32), (uint32_t) wwnn, |
3639 | (uint32_t) (wwpn >> 32), (uint32_t) wwpn, |
3640 | lp->handle, portid, |
3641 | (uint32_t) (lp->node_wwn >> 32), |
3642 | (uint32_t) lp->node_wwn, |
3643 | (uint32_t) (lp->port_wwn >> 32), |
3644 | (uint32_t) lp->port_wwn); |
3645 | /* |
3646 | * Try to re-login to this device using a |
3647 | * new handle. If that fails, mark it dead. |
3648 | * |
3649 | * isp_login_device will check for handle and |
3650 | * portid consistency after re-login. |
3651 | * |
3652 | */ |
3653 | if (isp_login_device(isp, chan, portid, &pdb, |
3654 | &oldhandle)) { |
3655 | lp->new_portid = portid; |
3656 | lp->state = FC_PORTDB_STATE_DEAD; |
3657 | if (fcp->isp_loopstate != |
3658 | LOOP_SCANNING_FABRIC) { |
3659 | FC_SCRATCH_RELEASE(isp, chan); |
3660 | ISP_MARK_PORTDB(isp, chan, 1); |
3661 | return (-1); |
3662 | } |
3663 | continue; |
3664 | } |
3665 | if (fcp->isp_loopstate != |
3666 | LOOP_SCANNING_FABRIC) { |
3667 | FC_SCRATCH_RELEASE(isp, chan); |
3668 | ISP_MARK_PORTDB(isp, chan, 1); |
3669 | return (-1); |
3670 | } |
3671 | FCPARAM(isp, 0)->isp_lasthdl = oldhandle; |
3672 | MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); |
3673 | MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname); |
3674 | if (wwpn != lp->port_wwn || |
3675 | wwnn != lp->node_wwn) { |
3676 | isp_prt(isp, ISP_LOGWARN, "changed WWN" |
3677 | " after relogin" ); |
3678 | lp->new_portid = portid; |
3679 | lp->state = FC_PORTDB_STATE_DEAD; |
3680 | continue; |
3681 | } |
3682 | |
3683 | lp->handle = pdb.handle; |
3684 | handle_changed++; |
3685 | } |
3686 | |
3687 | nr = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; |
3688 | |
3689 | /* |
3690 | * Check to see whether the portid and roles have |
3691 | * stayed the same. If they have stayed the same, |
3692 | * we believe that this is the same device and it |
3693 | * hasn't become disconnected and reconnected, so |
3694 | * mark it as pending valid. |
3695 | * |
3696 | * If they aren't the same, mark the device as a |
3697 | * changed device and save the new port id and role |
3698 | * and let somebody else decide. |
3699 | */ |
3700 | |
3701 | lp->new_portid = portid; |
3702 | lp->new_roles = nr; |
3703 | if (pdb.portid != lp->portid || nr != lp->roles || |
3704 | handle_changed) { |
3705 | isp_prt(isp, ISP_LOGSANCFG, |
3706 | "Chan %d Fabric Port 0x%06x changed" , |
3707 | chan, portid); |
3708 | lp->state = FC_PORTDB_STATE_CHANGED; |
3709 | } else { |
3710 | isp_prt(isp, ISP_LOGSANCFG, |
3711 | "Chan %d Fabric Port 0x%06x " |
3712 | "Now Pending Valid" , chan, portid); |
3713 | lp->state = FC_PORTDB_STATE_PENDING_VALID; |
3714 | } |
3715 | continue; |
3716 | } |
3717 | |
3718 | /* |
3719 | * Ah- a new entry. Search the database again for all non-NIL |
3720 | * entries to make sure we never ever make a new database entry |
3721 | * with the same port id. While we're at it, mark where the |
3722 | * last free entry was. |
3723 | */ |
3724 | |
3725 | dbidx = MAX_FC_TARG; |
3726 | for (lp = fcp->portdb; lp < &fcp->portdb[MAX_FC_TARG]; lp++) { |
3727 | if (lp >= &fcp->portdb[FL_ID] && |
3728 | lp <= &fcp->portdb[SNS_ID]) { |
3729 | continue; |
3730 | } |
3731 | /* |
3732 | * Skip any target mode entries. |
3733 | */ |
3734 | if (lp->target_mode) { |
3735 | continue; |
3736 | } |
3737 | if (lp->state == FC_PORTDB_STATE_NIL) { |
3738 | if (dbidx == MAX_FC_TARG) { |
3739 | dbidx = lp - fcp->portdb; |
3740 | } |
3741 | continue; |
3742 | } |
3743 | if (lp->state == FC_PORTDB_STATE_ZOMBIE) { |
3744 | continue; |
3745 | } |
3746 | if (lp->portid == portid) { |
3747 | break; |
3748 | } |
3749 | } |
3750 | |
3751 | if (lp < &fcp->portdb[MAX_FC_TARG]) { |
3752 | isp_prt(isp, ISP_LOGWARN, "Chan %d PortID 0x%06x " |
3753 | "already at %d handle %d state %d" , |
3754 | chan, portid, dbidx, lp->handle, lp->state); |
3755 | continue; |
3756 | } |
3757 | |
3758 | /* |
3759 | * We should have the index of the first free entry seen. |
3760 | */ |
3761 | if (dbidx == MAX_FC_TARG) { |
3762 | isp_prt(isp, ISP_LOGERR, |
3763 | "port database too small to login PortID 0x%06x" |
3764 | "- increase MAX_FC_TARG" , portid); |
3765 | continue; |
3766 | } |
3767 | |
3768 | /* |
3769 | * Otherwise, point to our new home. |
3770 | */ |
3771 | lp = &fcp->portdb[dbidx]; |
3772 | |
3773 | /* |
3774 | * Try to see if we are logged into this device, |
3775 | * and maybe log into it. |
3776 | * |
3777 | * isp_login_device will check for handle and |
3778 | * portid consistency after login. |
3779 | */ |
3780 | if (isp_login_device(isp, chan, portid, &pdb, &oldhandle)) { |
3781 | if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { |
3782 | FC_SCRATCH_RELEASE(isp, chan); |
3783 | ISP_MARK_PORTDB(isp, chan, 1); |
3784 | return (-1); |
3785 | } |
3786 | continue; |
3787 | } |
3788 | if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { |
3789 | FC_SCRATCH_RELEASE(isp, chan); |
3790 | ISP_MARK_PORTDB(isp, chan, 1); |
3791 | return (-1); |
3792 | } |
3793 | FCPARAM(isp, 0)->isp_lasthdl = oldhandle; |
3794 | |
3795 | handle = pdb.handle; |
3796 | MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); |
3797 | MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname); |
3798 | nr = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; |
3799 | |
3800 | /* |
3801 | * And go through the database *one* more time to make sure |
3802 | * that we do not make more than one entry that has the same |
3803 | * WWNN/WWPN duple |
3804 | */ |
3805 | for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { |
3806 | if (dbidx >= FL_ID && dbidx <= SNS_ID) { |
3807 | continue; |
3808 | } |
3809 | if (fcp->portdb[dbidx].target_mode) { |
3810 | continue; |
3811 | } |
3812 | if (fcp->portdb[dbidx].node_wwn == wwnn && |
3813 | fcp->portdb[dbidx].port_wwn == wwpn) { |
3814 | break; |
3815 | } |
3816 | } |
3817 | |
3818 | if (dbidx == MAX_FC_TARG) { |
3819 | ISP_MEMZERO(lp, sizeof (fcportdb_t)); |
3820 | lp->handle = handle; |
3821 | lp->node_wwn = wwnn; |
3822 | lp->port_wwn = wwpn; |
3823 | lp->new_portid = portid; |
3824 | lp->new_roles = nr; |
3825 | lp->state = FC_PORTDB_STATE_NEW; |
3826 | isp_prt(isp, ISP_LOGSANCFG, |
3827 | "Chan %d Fabric Port 0x%06x is a New Entry" , |
3828 | chan, portid); |
3829 | continue; |
3830 | } |
3831 | |
3832 | if (fcp->portdb[dbidx].state != FC_PORTDB_STATE_ZOMBIE) { |
3833 | isp_prt(isp, ISP_LOGWARN, |
3834 | "Chan %d PortID 0x%x 0x%08x%08x/0x%08x%08x %ld " |
3835 | "already at idx %d, state 0x%x" , chan, portid, |
3836 | (uint32_t) (wwnn >> 32), (uint32_t) wwnn, |
3837 | (uint32_t) (wwpn >> 32), (uint32_t) wwpn, |
3838 | (long) (lp - fcp->portdb), dbidx, |
3839 | fcp->portdb[dbidx].state); |
3840 | continue; |
3841 | } |
3842 | |
3843 | /* |
3844 | * We found a zombie entry that matches us. |
3845 | * Revive it. We know that WWN and WWPN |
3846 | * are the same. For fabric devices, we |
3847 | * don't care that handle is different |
3848 | * as we assign that. If role or portid |
3849 | * are different, it maybe a changed device. |
3850 | */ |
3851 | lp = &fcp->portdb[dbidx]; |
3852 | lp->handle = handle; |
3853 | lp->new_portid = portid; |
3854 | lp->new_roles = nr; |
3855 | if (lp->portid != portid || lp->roles != nr) { |
3856 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3857 | "Chan %d Zombie Fabric Port 0x%06x Now Changed" , |
3858 | chan, portid); |
3859 | lp->state = FC_PORTDB_STATE_CHANGED; |
3860 | } else { |
3861 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3862 | "Chan %d Zombie Fabric Port 0x%06x " |
3863 | "Now Pending Valid" , chan, portid); |
3864 | lp->state = FC_PORTDB_STATE_PENDING_VALID; |
3865 | } |
3866 | } |
3867 | |
3868 | FC_SCRATCH_RELEASE(isp, chan); |
3869 | if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { |
3870 | ISP_MARK_PORTDB(isp, chan, 1); |
3871 | return (-1); |
3872 | } |
3873 | fcp->isp_loopstate = LOOP_FSCAN_DONE; |
3874 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
3875 | "Chan %d FC Scan Fabric Done" , chan); |
3876 | return (0); |
3877 | } |
3878 | |
3879 | /* |
3880 | * Find an unused handle and try and use to login to a port. |
3881 | */ |
3882 | static int |
3883 | isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint16_t *ohp) |
3884 | { |
3885 | int lim, i, r; |
3886 | uint16_t handle; |
3887 | |
3888 | if (ISP_CAP_2KLOGIN(isp)) { |
3889 | lim = NPH_MAX_2K; |
3890 | } else { |
3891 | lim = NPH_MAX; |
3892 | } |
3893 | |
3894 | handle = isp_nxt_handle(isp, chan, *ohp); |
3895 | for (i = 0; i < lim; i++) { |
3896 | /* |
3897 | * See if we're still logged into something with |
3898 | * this handle and that something agrees with this |
3899 | * port id. |
3900 | */ |
3901 | r = isp_getpdb(isp, chan, handle, p, 0); |
3902 | if (r == 0 && p->portid != portid) { |
3903 | (void) isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 1); |
3904 | } else if (r == 0) { |
3905 | break; |
3906 | } |
3907 | if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { |
3908 | return (-1); |
3909 | } |
3910 | /* |
3911 | * Now try and log into the device |
3912 | */ |
3913 | r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1); |
3914 | if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { |
3915 | return (-1); |
3916 | } |
3917 | if (r == 0) { |
3918 | *ohp = handle; |
3919 | break; |
3920 | } else if ((r & 0xffff) == MBOX_PORT_ID_USED) { |
3921 | /* |
3922 | * If we get here, then the firmwware still thinks we're logged into this device, but with a different |
3923 | * handle. We need to break that association. We used to try and just substitute the handle, but then |
3924 | * failed to get any data via isp_getpdb (below). |
3925 | */ |
3926 | if (isp_plogx(isp, chan, r >> 16, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 1)) { |
3927 | isp_prt(isp, ISP_LOGERR, "baw... logout of %x failed" , r >> 16); |
3928 | } |
3929 | if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { |
3930 | return (-1); |
3931 | } |
3932 | r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1); |
3933 | if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { |
3934 | return (-1); |
3935 | } |
3936 | if (r == 0) { |
3937 | *ohp = handle; |
3938 | } else { |
3939 | i = lim; |
3940 | } |
3941 | break; |
3942 | } else if ((r & 0xffff) == MBOX_LOOP_ID_USED) { |
3943 | /* |
3944 | * Try the next loop id. |
3945 | */ |
3946 | *ohp = handle; |
3947 | handle = isp_nxt_handle(isp, chan, handle); |
3948 | } else { |
3949 | /* |
3950 | * Give up. |
3951 | */ |
3952 | i = lim; |
3953 | break; |
3954 | } |
3955 | } |
3956 | |
3957 | if (i == lim) { |
3958 | isp_prt(isp, ISP_LOGWARN, "Chan %d PLOGI 0x%06x failed" , chan, portid); |
3959 | return (-1); |
3960 | } |
3961 | |
3962 | /* |
3963 | * If we successfully logged into it, get the PDB for it |
3964 | * so we can crosscheck that it is still what we think it |
3965 | * is and that we also have the role it plays |
3966 | */ |
3967 | r = isp_getpdb(isp, chan, handle, p, 0); |
3968 | if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { |
3969 | return (-1); |
3970 | } |
3971 | if (r != 0) { |
3972 | isp_prt(isp, ISP_LOGERR, "Chan %d new device 0x%06x@0x%x disappeared" , chan, portid, handle); |
3973 | return (-1); |
3974 | } |
3975 | |
3976 | if (p->handle != handle || p->portid != portid) { |
3977 | isp_prt(isp, ISP_LOGERR, "Chan %d new device 0x%06x@0x%x changed (0x%06x@0x%0x)" , |
3978 | chan, portid, handle, p->portid, p->handle); |
3979 | return (-1); |
3980 | } |
3981 | return (0); |
3982 | } |
3983 | |
3984 | static int |
3985 | isp_register_fc4_type(ispsoftc_t *isp, int chan) |
3986 | { |
3987 | fcparam *fcp = FCPARAM(isp, chan); |
3988 | uint8_t local[SNS_RFT_ID_REQ_SIZE]; |
3989 | sns_screq_t *reqp = (sns_screq_t *) local; |
3990 | mbreg_t mbs; |
3991 | |
3992 | ISP_MEMZERO((void *) reqp, SNS_RFT_ID_REQ_SIZE); |
3993 | reqp->snscb_rblen = SNS_RFT_ID_RESP_SIZE >> 1; |
3994 | reqp->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma + 0x100); |
3995 | reqp->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma + 0x100); |
3996 | reqp->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma + 0x100); |
3997 | reqp->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma + 0x100); |
3998 | reqp->snscb_sblen = 22; |
3999 | reqp->snscb_data[0] = SNS_RFT_ID; |
4000 | reqp->snscb_data[4] = fcp->isp_portid & 0xffff; |
4001 | reqp->snscb_data[5] = (fcp->isp_portid >> 16) & 0xff; |
4002 | reqp->snscb_data[6] = (1 << FC4_SCSI); |
4003 | if (FC_SCRATCH_ACQUIRE(isp, chan)) { |
4004 | isp_prt(isp, ISP_LOGERR, sacq); |
4005 | return (-1); |
4006 | } |
4007 | isp_put_sns_request(isp, reqp, (sns_screq_t *) fcp->isp_scratch); |
4008 | MBSINIT(&mbs, MBOX_SEND_SNS, MBLOGALL, 1000000); |
4009 | mbs.param[1] = SNS_RFT_ID_REQ_SIZE >> 1; |
4010 | mbs.param[2] = DMA_WD1(fcp->isp_scdma); |
4011 | mbs.param[3] = DMA_WD0(fcp->isp_scdma); |
4012 | mbs.param[6] = DMA_WD3(fcp->isp_scdma); |
4013 | mbs.param[7] = DMA_WD2(fcp->isp_scdma); |
4014 | MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_RFT_ID_REQ_SIZE, chan); |
4015 | isp_mboxcmd(isp, &mbs); |
4016 | FC_SCRATCH_RELEASE(isp, chan); |
4017 | if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { |
4018 | return (0); |
4019 | } else { |
4020 | return (-1); |
4021 | } |
4022 | } |
4023 | |
4024 | static int |
4025 | isp_register_fc4_type_24xx(ispsoftc_t *isp, int chan) |
4026 | { |
4027 | mbreg_t mbs; |
4028 | fcparam *fcp = FCPARAM(isp, chan); |
4029 | union { |
4030 | isp_ct_pt_t plocal; |
4031 | rft_id_t clocal; |
4032 | uint8_t q[QENTRY_LEN]; |
4033 | } un; |
4034 | isp_ct_pt_t *pt; |
4035 | ct_hdr_t *ct; |
4036 | rft_id_t *rp; |
4037 | uint8_t *scp = fcp->isp_scratch; |
4038 | |
4039 | if (FC_SCRATCH_ACQUIRE(isp, chan)) { |
4040 | isp_prt(isp, ISP_LOGERR, sacq); |
4041 | return (-1); |
4042 | } |
4043 | |
4044 | /* |
4045 | * Build a Passthrough IOCB in memory. |
4046 | */ |
4047 | ISP_MEMZERO(un.q, QENTRY_LEN); |
4048 | pt = &un.plocal; |
4049 | pt->ctp_header.rqs_entry_count = 1; |
4050 | pt->ctp_header.rqs_entry_type = RQSTYPE_CT_PASSTHRU; |
4051 | pt->ctp_handle = 0xffffffff; |
4052 | pt->ctp_nphdl = fcp->isp_sns_hdl; |
4053 | pt->ctp_cmd_cnt = 1; |
4054 | pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan); |
4055 | pt->ctp_time = 1; |
4056 | pt->ctp_rsp_cnt = 1; |
4057 | pt->ctp_rsp_bcnt = sizeof (ct_hdr_t); |
4058 | pt->ctp_cmd_bcnt = sizeof (rft_id_t); |
4059 | pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF); |
4060 | pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF); |
4061 | pt->ctp_dataseg[0].ds_count = sizeof (rft_id_t); |
4062 | pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF); |
4063 | pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF); |
4064 | pt->ctp_dataseg[1].ds_count = sizeof (ct_hdr_t); |
4065 | isp_put_ct_pt(isp, pt, (isp_ct_pt_t *) &scp[CTXOFF]); |
4066 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
4067 | isp_print_bytes(isp, "IOCB CT Request" , QENTRY_LEN, pt); |
4068 | } |
4069 | |
4070 | /* |
4071 | * Build the CT header and command in memory. |
4072 | * |
4073 | * Note that the CT header has to end up as Big Endian format in memory. |
4074 | */ |
4075 | ISP_MEMZERO(&un.clocal, sizeof (un.clocal)); |
4076 | ct = &un.clocal.rftid_hdr; |
4077 | ct->ct_revision = CT_REVISION; |
4078 | ct->ct_fcs_type = CT_FC_TYPE_FC; |
4079 | ct->ct_fcs_subtype = CT_FC_SUBTYPE_NS; |
4080 | ct->ct_cmd_resp = SNS_RFT_ID; |
4081 | ct->ct_bcnt_resid = (sizeof (rft_id_t) - sizeof (ct_hdr_t)) >> 2; |
4082 | rp = &un.clocal; |
4083 | rp->rftid_portid[0] = fcp->isp_portid >> 16; |
4084 | rp->rftid_portid[1] = fcp->isp_portid >> 8; |
4085 | rp->rftid_portid[2] = fcp->isp_portid; |
4086 | rp->rftid_fc4types[FC4_SCSI >> 5] = 1 << (FC4_SCSI & 0x1f); |
4087 | isp_put_rft_id(isp, rp, (rft_id_t *) &scp[XTXOFF]); |
4088 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
4089 | isp_print_bytes(isp, "CT Header" , QENTRY_LEN, &scp[XTXOFF]); |
4090 | } |
4091 | |
4092 | ISP_MEMZERO(&scp[ZTXOFF], sizeof (ct_hdr_t)); |
4093 | |
4094 | MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 1000000); |
4095 | mbs.param[1] = QENTRY_LEN; |
4096 | mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF); |
4097 | mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF); |
4098 | mbs.param[6] = DMA_WD3(fcp->isp_scdma + CTXOFF); |
4099 | mbs.param[7] = DMA_WD2(fcp->isp_scdma + CTXOFF); |
4100 | MEMORYBARRIER(isp, SYNC_SFORDEV, XTXOFF, 2 * QENTRY_LEN, chan); |
4101 | isp_mboxcmd(isp, &mbs); |
4102 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
4103 | FC_SCRATCH_RELEASE(isp, chan); |
4104 | return (-1); |
4105 | } |
4106 | MEMORYBARRIER(isp, SYNC_SFORCPU, ZTXOFF, QENTRY_LEN, chan); |
4107 | pt = &un.plocal; |
4108 | isp_get_ct_pt(isp, (isp_ct_pt_t *) &scp[ZTXOFF], pt); |
4109 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
4110 | isp_print_bytes(isp, "IOCB response" , QENTRY_LEN, pt); |
4111 | } |
4112 | if (pt->ctp_status) { |
4113 | FC_SCRATCH_RELEASE(isp, chan); |
4114 | isp_prt(isp, ISP_LOGWARN, |
4115 | "Chan %d Register FC4 Type CT Passthrough returned 0x%x" , |
4116 | chan, pt->ctp_status); |
4117 | return (1); |
4118 | } |
4119 | |
4120 | isp_get_ct_hdr(isp, (ct_hdr_t *) &scp[IGPOFF], ct); |
4121 | FC_SCRATCH_RELEASE(isp, chan); |
4122 | |
4123 | if (ct->ct_cmd_resp == LS_RJT) { |
4124 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
4125 | "Chan %d Register FC4 Type rejected" , chan); |
4126 | return (-1); |
4127 | } else if (ct->ct_cmd_resp == LS_ACC) { |
4128 | isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, |
4129 | "Chan %d Register FC4 Type accepted" , chan); |
4130 | return (0); |
4131 | } else { |
4132 | isp_prt(isp, ISP_LOGWARN, |
4133 | "Chan %d Register FC4 Type: 0x%x" , |
4134 | chan, ct->ct_cmd_resp); |
4135 | return (-1); |
4136 | } |
4137 | } |
4138 | |
4139 | static uint16_t |
4140 | isp_nxt_handle(ispsoftc_t *isp, int chan, uint16_t handle) |
4141 | { |
4142 | int i; |
4143 | if (handle == NIL_HANDLE) { |
4144 | if (FCPARAM(isp, chan)->isp_topo == TOPO_F_PORT) { |
4145 | handle = 0; |
4146 | } else { |
4147 | handle = SNS_ID+1; |
4148 | } |
4149 | } else { |
4150 | handle += 1; |
4151 | if (handle >= FL_ID && handle <= SNS_ID) { |
4152 | handle = SNS_ID+1; |
4153 | } |
4154 | if (handle >= NPH_RESERVED && handle <= NPH_FL_ID) { |
4155 | handle = NPH_FL_ID+1; |
4156 | } |
4157 | if (ISP_CAP_2KLOGIN(isp)) { |
4158 | if (handle == NPH_MAX_2K) { |
4159 | handle = 0; |
4160 | } |
4161 | } else { |
4162 | if (handle == NPH_MAX) { |
4163 | handle = 0; |
4164 | } |
4165 | } |
4166 | } |
4167 | if (handle == FCPARAM(isp, chan)->isp_loopid) { |
4168 | return (isp_nxt_handle(isp, chan, handle)); |
4169 | } |
4170 | for (i = 0; i < MAX_FC_TARG; i++) { |
4171 | if (FCPARAM(isp, chan)->portdb[i].state == |
4172 | FC_PORTDB_STATE_NIL) { |
4173 | continue; |
4174 | } |
4175 | if (FCPARAM(isp, chan)->portdb[i].handle == handle) { |
4176 | return (isp_nxt_handle(isp, chan, handle)); |
4177 | } |
4178 | } |
4179 | return (handle); |
4180 | } |
4181 | |
4182 | /* |
4183 | * Start a command. Locking is assumed done in the caller. |
4184 | */ |
4185 | |
4186 | int |
4187 | isp_start(XS_T *xs) |
4188 | { |
4189 | ispsoftc_t *isp; |
4190 | uint32_t handle, cdblen; |
4191 | uint8_t local[QENTRY_LEN]; |
4192 | ispreq_t *reqp; |
4193 | void *cdbp, *qep; |
4194 | uint16_t *tptr; |
4195 | int target, dmaresult, hdlidx = 0; |
4196 | |
4197 | XS_INITERR(xs); |
4198 | isp = XS_ISP(xs); |
4199 | |
4200 | /* |
4201 | * Now make sure we're running. |
4202 | */ |
4203 | |
4204 | if (isp->isp_state != ISP_RUNSTATE) { |
4205 | isp_prt(isp, ISP_LOGERR, "Adapter not at RUNSTATE" ); |
4206 | XS_SETERR(xs, HBA_BOTCH); |
4207 | return (CMD_COMPLETE); |
4208 | } |
4209 | |
4210 | /* |
4211 | * Check command CDB length, etc.. We really are limited to 16 bytes |
4212 | * for Fibre Channel, but can do up to 44 bytes in parallel SCSI, |
4213 | * but probably only if we're running fairly new firmware (we'll |
4214 | * let the old f/w choke on an extended command queue entry). |
4215 | */ |
4216 | |
4217 | if (XS_CDBLEN(xs) > (IS_FC(isp)? 16 : 44) || XS_CDBLEN(xs) == 0) { |
4218 | isp_prt(isp, ISP_LOGERR, "unsupported cdb length (%d, CDB[0]=0x%x)" , XS_CDBLEN(xs), XS_CDBP(xs)[0] & 0xff); |
4219 | XS_SETERR(xs, HBA_BOTCH); |
4220 | return (CMD_COMPLETE); |
4221 | } |
4222 | |
4223 | /* |
4224 | * Translate the target to device handle as appropriate, checking |
4225 | * for correct device state as well. |
4226 | */ |
4227 | target = XS_TGT(xs); |
4228 | if (IS_FC(isp)) { |
4229 | fcparam *fcp = FCPARAM(isp, XS_CHANNEL(xs)); |
4230 | |
4231 | if ((fcp->role & ISP_ROLE_INITIATOR) == 0) { |
4232 | XS_SETERR(xs, HBA_SELTIMEOUT); |
4233 | return (CMD_COMPLETE); |
4234 | } |
4235 | |
4236 | /* |
4237 | * Try again later. |
4238 | */ |
4239 | if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate != LOOP_READY) { |
4240 | return (CMD_RQLATER); |
4241 | } |
4242 | |
4243 | if (XS_TGT(xs) >= MAX_FC_TARG) { |
4244 | XS_SETERR(xs, HBA_SELTIMEOUT); |
4245 | return (CMD_COMPLETE); |
4246 | } |
4247 | |
4248 | hdlidx = fcp->isp_dev_map[XS_TGT(xs)] - 1; |
4249 | isp_prt(isp, ISP_LOGDEBUG2, "XS_TGT(xs)=%d- hdlidx value %d" , XS_TGT(xs), hdlidx); |
4250 | if (hdlidx < 0 || hdlidx >= MAX_FC_TARG) { |
4251 | XS_SETERR(xs, HBA_SELTIMEOUT); |
4252 | return (CMD_COMPLETE); |
4253 | } |
4254 | if (fcp->portdb[hdlidx].state == FC_PORTDB_STATE_ZOMBIE) { |
4255 | return (CMD_RQLATER); |
4256 | } |
4257 | if (fcp->portdb[hdlidx].state != FC_PORTDB_STATE_VALID) { |
4258 | XS_SETERR(xs, HBA_SELTIMEOUT); |
4259 | return (CMD_COMPLETE); |
4260 | } |
4261 | target = fcp->portdb[hdlidx].handle; |
4262 | fcp->portdb[hdlidx].dirty = 1; |
4263 | } else { |
4264 | sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); |
4265 | if ((sdp->role & ISP_ROLE_INITIATOR) == 0) { |
4266 | XS_SETERR(xs, HBA_SELTIMEOUT); |
4267 | return (CMD_COMPLETE); |
4268 | } |
4269 | if (sdp->update) { |
4270 | isp_spi_update(isp, XS_CHANNEL(xs)); |
4271 | } |
4272 | } |
4273 | |
4274 | start_again: |
4275 | |
4276 | qep = isp_getrqentry(isp); |
4277 | if (qep == NULL) { |
4278 | isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow" ); |
4279 | XS_SETERR(xs, HBA_BOTCH); |
4280 | return (CMD_EAGAIN); |
4281 | } |
4282 | XS_SETERR(xs, HBA_NOERROR); |
4283 | |
4284 | /* |
4285 | * Now see if we need to synchronize the ISP with respect to anything. |
4286 | * We do dual duty here (cough) for synchronizing for busses other |
4287 | * than which we got here to send a command to. |
4288 | */ |
4289 | reqp = (ispreq_t *) local; |
4290 | ISP_MEMZERO(local, QENTRY_LEN); |
4291 | if (ISP_TST_SENDMARKER(isp, XS_CHANNEL(xs))) { |
4292 | if (IS_24XX(isp)) { |
4293 | isp_marker_24xx_t *m = (isp_marker_24xx_t *) reqp; |
4294 | m->mrk_header.rqs_entry_count = 1; |
4295 | m->mrk_header.rqs_entry_type = RQSTYPE_MARKER; |
4296 | m->mrk_modifier = SYNC_ALL; |
4297 | isp_put_marker_24xx(isp, m, qep); |
4298 | } else { |
4299 | isp_marker_t *m = (isp_marker_t *) reqp; |
4300 | m->mrk_header.rqs_entry_count = 1; |
4301 | m->mrk_header.rqs_entry_type = RQSTYPE_MARKER; |
4302 | m->mrk_target = (XS_CHANNEL(xs) << 7); /* bus # */ |
4303 | m->mrk_modifier = SYNC_ALL; |
4304 | isp_put_marker(isp, m, qep); |
4305 | } |
4306 | ISP_SYNC_REQUEST(isp); |
4307 | ISP_SET_SENDMARKER(isp, XS_CHANNEL(xs), 0); |
4308 | goto start_again; |
4309 | } |
4310 | |
4311 | reqp->req_header.rqs_entry_count = 1; |
4312 | if (IS_24XX(isp)) { |
4313 | reqp->req_header.rqs_entry_type = RQSTYPE_T7RQS; |
4314 | } else if (IS_FC(isp)) { |
4315 | reqp->req_header.rqs_entry_type = RQSTYPE_T2RQS; |
4316 | } else { |
4317 | if (XS_CDBLEN(xs) > 12) { |
4318 | reqp->req_header.rqs_entry_type = RQSTYPE_CMDONLY; |
4319 | } else { |
4320 | reqp->req_header.rqs_entry_type = RQSTYPE_REQUEST; |
4321 | } |
4322 | } |
4323 | |
4324 | if (IS_24XX(isp)) { |
4325 | int ttype; |
4326 | if (XS_TAG_P(xs)) { |
4327 | ttype = XS_TAG_TYPE(xs); |
4328 | } else { |
4329 | if (XS_CDBP(xs)[0] == 0x3) { |
4330 | ttype = REQFLAG_HTAG; |
4331 | } else { |
4332 | ttype = REQFLAG_STAG; |
4333 | } |
4334 | } |
4335 | if (ttype == REQFLAG_OTAG) { |
4336 | ttype = FCP_CMND_TASK_ATTR_ORDERED; |
4337 | } else if (ttype == REQFLAG_HTAG) { |
4338 | ttype = FCP_CMND_TASK_ATTR_HEAD; |
4339 | } else { |
4340 | ttype = FCP_CMND_TASK_ATTR_SIMPLE; |
4341 | } |
4342 | ((ispreqt7_t *)reqp)->req_task_attribute = ttype; |
4343 | } else if (IS_FC(isp)) { |
4344 | /* |
4345 | * See comment in isp_intr |
4346 | */ |
4347 | /* XS_SET_RESID(xs, 0); */ |
4348 | |
4349 | /* |
4350 | * Fibre Channel always requires some kind of tag. |
4351 | * The Qlogic drivers seem be happy not to use a tag, |
4352 | * but this breaks for some devices (IBM drives). |
4353 | */ |
4354 | if (XS_TAG_P(xs)) { |
4355 | ((ispreqt2_t *)reqp)->req_flags = XS_TAG_TYPE(xs); |
4356 | } else { |
4357 | /* |
4358 | * If we don't know what tag to use, use HEAD OF QUEUE |
4359 | * for Request Sense or Simple. |
4360 | */ |
4361 | if (XS_CDBP(xs)[0] == 0x3) /* REQUEST SENSE */ |
4362 | ((ispreqt2_t *)reqp)->req_flags = REQFLAG_HTAG; |
4363 | else |
4364 | ((ispreqt2_t *)reqp)->req_flags = REQFLAG_STAG; |
4365 | } |
4366 | } else { |
4367 | sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); |
4368 | if ((sdp->isp_devparam[target].actv_flags & DPARM_TQING) && XS_TAG_P(xs)) { |
4369 | reqp->req_flags = XS_TAG_TYPE(xs); |
4370 | } |
4371 | } |
4372 | |
4373 | tptr = &reqp->req_time; |
4374 | |
4375 | /* |
4376 | * NB: we do not support long CDBs |
4377 | */ |
4378 | cdblen = XS_CDBLEN(xs); |
4379 | |
4380 | if (IS_SCSI(isp)) { |
4381 | reqp->req_target = target | (XS_CHANNEL(xs) << 7); |
4382 | reqp->req_lun_trn = XS_LUN(xs); |
4383 | cdblen = ISP_MIN(cdblen, sizeof (reqp->req_cdb)); |
4384 | cdbp = reqp->req_cdb; |
4385 | reqp->req_cdblen = cdblen; |
4386 | } else if (IS_24XX(isp)) { |
4387 | ispreqt7_t *t7 = (ispreqt7_t *)local; |
4388 | fcportdb_t *lp; |
4389 | |
4390 | lp = &FCPARAM(isp, XS_CHANNEL(xs))->portdb[hdlidx]; |
4391 | t7->req_nphdl = target; |
4392 | t7->req_tidlo = lp->portid; |
4393 | t7->req_tidhi = lp->portid >> 16; |
4394 | t7->req_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(xs)); |
4395 | if (XS_LUN(xs) > 256) { |
4396 | t7->req_lun[0] = XS_LUN(xs) >> 8; |
4397 | t7->req_lun[0] |= 0x40; |
4398 | } |
4399 | t7->req_lun[1] = XS_LUN(xs); |
4400 | tptr = &t7->req_time; |
4401 | cdbp = t7->req_cdb; |
4402 | cdblen = ISP_MIN(cdblen, sizeof (t7->req_cdb)); |
4403 | } else if (ISP_CAP_2KLOGIN(isp)) { |
4404 | ispreqt2e_t *t2e = (ispreqt2e_t *)local; |
4405 | t2e->req_target = target; |
4406 | t2e->req_scclun = XS_LUN(xs); |
4407 | cdbp = t2e->req_cdb; |
4408 | cdblen = ISP_MIN(cdblen, sizeof (t2e->req_cdb)); |
4409 | } else if (ISP_CAP_SCCFW(isp)) { |
4410 | ispreqt2_t *t2 = (ispreqt2_t *)local; |
4411 | t2->req_target = target; |
4412 | t2->req_scclun = XS_LUN(xs); |
4413 | cdbp = t2->req_cdb; |
4414 | cdblen = ISP_MIN(cdblen, sizeof (t2->req_cdb)); |
4415 | } else { |
4416 | ispreqt2_t *t2 = (ispreqt2_t *)local; |
4417 | t2->req_target = target; |
4418 | t2->req_lun_trn = XS_LUN(xs); |
4419 | cdbp = t2->req_cdb; |
4420 | cdblen = ISP_MIN(cdblen, sizeof (t2->req_cdb)); |
4421 | } |
4422 | ISP_MEMCPY(cdbp, XS_CDBP(xs), cdblen); |
4423 | |
4424 | *tptr = XS_TIME(xs) / 1000; |
4425 | if (*tptr == 0 && XS_TIME(xs)) { |
4426 | *tptr = 1; |
4427 | } |
4428 | if (IS_24XX(isp) && *tptr > 0x1999) { |
4429 | *tptr = 0x1999; |
4430 | } |
4431 | |
4432 | if (isp_allocate_xs(isp, xs, &handle)) { |
4433 | isp_prt(isp, ISP_LOGDEBUG0, "out of xflist pointers" ); |
4434 | XS_SETERR(xs, HBA_BOTCH); |
4435 | return (CMD_EAGAIN); |
4436 | } |
4437 | /* Whew. Thankfully the same for type 7 requests */ |
4438 | reqp->req_handle = handle; |
4439 | |
4440 | /* |
4441 | * Set up DMA and/or do any platform dependent swizzling of the request entry |
4442 | * so that the Qlogic F/W understands what is being asked of it. |
4443 | * |
4444 | * The callee is responsible for adding all requests at this point. |
4445 | */ |
4446 | dmaresult = ISP_DMASETUP(isp, xs, reqp); |
4447 | if (dmaresult != CMD_QUEUED) { |
4448 | isp_destroy_handle(isp, handle); |
4449 | /* |
4450 | * dmasetup sets actual error in packet, and |
4451 | * return what we were given to return. |
4452 | */ |
4453 | return (dmaresult); |
4454 | } |
4455 | isp_xs_prt(isp, xs, ISP_LOGDEBUG0, "START cmd cdb[0]=0x%x datalen %ld" , XS_CDBP(xs)[0], (long) XS_XFRLEN(xs)); |
4456 | isp->isp_nactive++; |
4457 | return (CMD_QUEUED); |
4458 | } |
4459 | |
4460 | /* |
4461 | * isp control |
4462 | * Locks (ints blocked) assumed held. |
4463 | */ |
4464 | |
4465 | int |
4466 | isp_control(ispsoftc_t *isp, ispctl_t ctl, ...) |
4467 | { |
4468 | XS_T *xs; |
4469 | mbreg_t *mbr, mbs; |
4470 | int chan, tgt; |
4471 | uint32_t handle; |
4472 | va_list ap; |
4473 | |
4474 | switch (ctl) { |
4475 | case ISPCTL_RESET_BUS: |
4476 | /* |
4477 | * Issue a bus reset. |
4478 | */ |
4479 | if (IS_24XX(isp)) { |
4480 | isp_prt(isp, ISP_LOGWARN, "RESET BUS NOT IMPLEMENTED" ); |
4481 | break; |
4482 | } else if (IS_FC(isp)) { |
4483 | mbs.param[1] = 10; |
4484 | chan = 0; |
4485 | } else { |
4486 | va_start(ap, ctl); |
4487 | chan = va_arg(ap, int); |
4488 | va_end(ap); |
4489 | mbs.param[1] = SDPARAM(isp, chan)->isp_bus_reset_delay; |
4490 | if (mbs.param[1] < 2) { |
4491 | mbs.param[1] = 2; |
4492 | } |
4493 | mbs.param[2] = chan; |
4494 | } |
4495 | MBSINIT(&mbs, MBOX_BUS_RESET, MBLOGALL, 0); |
4496 | ISP_SET_SENDMARKER(isp, chan, 1); |
4497 | isp_mboxcmd(isp, &mbs); |
4498 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
4499 | break; |
4500 | } |
4501 | isp_prt(isp, ISP_LOGINFO, |
4502 | "driver initiated bus reset of bus %d" , chan); |
4503 | return (0); |
4504 | |
4505 | case ISPCTL_RESET_DEV: |
4506 | va_start(ap, ctl); |
4507 | chan = va_arg(ap, int); |
4508 | tgt = va_arg(ap, int); |
4509 | va_end(ap); |
4510 | if (IS_24XX(isp)) { |
4511 | uint8_t local[QENTRY_LEN]; |
4512 | isp24xx_tmf_t *tmf; |
4513 | isp24xx_statusreq_t *sp; |
4514 | fcparam *fcp = FCPARAM(isp, chan); |
4515 | fcportdb_t *lp; |
4516 | int hdlidx; |
4517 | |
4518 | hdlidx = fcp->isp_dev_map[tgt] - 1; |
4519 | if (hdlidx < 0 || hdlidx >= MAX_FC_TARG) { |
4520 | isp_prt(isp, ISP_LOGWARN, |
4521 | "Chan %d bad handle %d trying to reset" |
4522 | "target %d" , chan, hdlidx, tgt); |
4523 | break; |
4524 | } |
4525 | lp = &fcp->portdb[hdlidx]; |
4526 | if (lp->state != FC_PORTDB_STATE_VALID) { |
4527 | isp_prt(isp, ISP_LOGWARN, |
4528 | "Chan %d handle %d for abort of target %d " |
4529 | "no longer valid" , chan, |
4530 | hdlidx, tgt); |
4531 | break; |
4532 | } |
4533 | |
4534 | tmf = (isp24xx_tmf_t *) local; |
4535 | ISP_MEMZERO(tmf, QENTRY_LEN); |
4536 | tmf->tmf_header.rqs_entry_type = RQSTYPE_TSK_MGMT; |
4537 | tmf->tmf_header.rqs_entry_count = 1; |
4538 | tmf->tmf_nphdl = lp->handle; |
4539 | tmf->tmf_delay = 2; |
4540 | tmf->tmf_timeout = 2; |
4541 | tmf->tmf_flags = ISP24XX_TMF_TARGET_RESET; |
4542 | tmf->tmf_tidlo = lp->portid; |
4543 | tmf->tmf_tidhi = lp->portid >> 16; |
4544 | tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan); |
4545 | isp_prt(isp, ISP_LOGALL, "Chan %d Reset N-Port Handle 0x%04x @ Port 0x%06x" , chan, lp->handle, lp->portid); |
4546 | MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000); |
4547 | mbs.param[1] = QENTRY_LEN; |
4548 | mbs.param[2] = DMA_WD1(fcp->isp_scdma); |
4549 | mbs.param[3] = DMA_WD0(fcp->isp_scdma); |
4550 | mbs.param[6] = DMA_WD3(fcp->isp_scdma); |
4551 | mbs.param[7] = DMA_WD2(fcp->isp_scdma); |
4552 | |
4553 | if (FC_SCRATCH_ACQUIRE(isp, chan)) { |
4554 | isp_prt(isp, ISP_LOGERR, sacq); |
4555 | break; |
4556 | } |
4557 | isp_put_24xx_tmf(isp, tmf, fcp->isp_scratch); |
4558 | MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN, chan); |
4559 | fcp->sendmarker = 1; |
4560 | isp_mboxcmd(isp, &mbs); |
4561 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
4562 | FC_SCRATCH_RELEASE(isp, chan); |
4563 | break; |
4564 | } |
4565 | MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, |
4566 | QENTRY_LEN, chan); |
4567 | sp = (isp24xx_statusreq_t *) local; |
4568 | isp_get_24xx_response(isp, |
4569 | &((isp24xx_statusreq_t *)fcp->isp_scratch)[1], sp); |
4570 | FC_SCRATCH_RELEASE(isp, chan); |
4571 | if (sp->req_completion_status == 0) { |
4572 | return (0); |
4573 | } |
4574 | isp_prt(isp, ISP_LOGWARN, |
4575 | "Chan %d reset of target %d returned 0x%x" , |
4576 | chan, tgt, sp->req_completion_status); |
4577 | break; |
4578 | } else if (IS_FC(isp)) { |
4579 | if (ISP_CAP_2KLOGIN(isp)) { |
4580 | mbs.param[1] = tgt; |
4581 | mbs.ibits = (1 << 10); |
4582 | } else { |
4583 | mbs.param[1] = (tgt << 8); |
4584 | } |
4585 | } else { |
4586 | mbs.param[1] = (chan << 15) | (tgt << 8); |
4587 | } |
4588 | MBSINIT(&mbs, MBOX_ABORT_TARGET, MBLOGALL, 0); |
4589 | mbs.param[2] = 3; /* 'delay', in seconds */ |
4590 | isp_mboxcmd(isp, &mbs); |
4591 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
4592 | break; |
4593 | } |
4594 | isp_prt(isp, ISP_LOGINFO, |
4595 | "Target %d on Bus %d Reset Succeeded" , tgt, chan); |
4596 | ISP_SET_SENDMARKER(isp, chan, 1); |
4597 | return (0); |
4598 | |
4599 | case ISPCTL_ABORT_CMD: |
4600 | va_start(ap, ctl); |
4601 | xs = va_arg(ap, XS_T *); |
4602 | va_end(ap); |
4603 | |
4604 | tgt = XS_TGT(xs); |
4605 | chan = XS_CHANNEL(xs); |
4606 | |
4607 | handle = isp_find_handle(isp, xs); |
4608 | if (handle == 0) { |
4609 | isp_prt(isp, ISP_LOGWARN, |
4610 | "cannot find handle for command to abort" ); |
4611 | break; |
4612 | } |
4613 | if (IS_24XX(isp)) { |
4614 | isp24xx_abrt_t local, *ab = &local, *ab2; |
4615 | fcparam *fcp; |
4616 | fcportdb_t *lp; |
4617 | int hdlidx; |
4618 | |
4619 | fcp = FCPARAM(isp, chan); |
4620 | hdlidx = fcp->isp_dev_map[tgt] - 1; |
4621 | if (hdlidx < 0 || hdlidx >= MAX_FC_TARG) { |
4622 | isp_prt(isp, ISP_LOGWARN, |
4623 | "Chan %d bad handle %d trying to abort" |
4624 | "target %d" , chan, hdlidx, tgt); |
4625 | break; |
4626 | } |
4627 | lp = &fcp->portdb[hdlidx]; |
4628 | if (lp->state != FC_PORTDB_STATE_VALID) { |
4629 | isp_prt(isp, ISP_LOGWARN, |
4630 | "Chan %d handle %d for abort of target %d " |
4631 | "no longer valid" , chan, hdlidx, tgt); |
4632 | break; |
4633 | } |
4634 | isp_prt(isp, ISP_LOGALL, |
4635 | "Chan %d Abort Cmd for N-Port 0x%04x @ Port " |
4636 | "0x%06x %p" , chan, lp->handle, lp->portid, xs); |
4637 | ISP_MEMZERO(ab, QENTRY_LEN); |
4638 | ab->abrt_header.rqs_entry_type = RQSTYPE_ABORT_IO; |
4639 | ab->abrt_header.rqs_entry_count = 1; |
4640 | ab->abrt_handle = lp->handle; |
4641 | ab->abrt_cmd_handle = handle; |
4642 | ab->abrt_tidlo = lp->portid; |
4643 | ab->abrt_tidhi = lp->portid >> 16; |
4644 | ab->abrt_vpidx = ISP_GET_VPIDX(isp, chan); |
4645 | |
4646 | ISP_MEMZERO(&mbs, sizeof (mbs)); |
4647 | MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000); |
4648 | mbs.param[1] = QENTRY_LEN; |
4649 | mbs.param[2] = DMA_WD1(fcp->isp_scdma); |
4650 | mbs.param[3] = DMA_WD0(fcp->isp_scdma); |
4651 | mbs.param[6] = DMA_WD3(fcp->isp_scdma); |
4652 | mbs.param[7] = DMA_WD2(fcp->isp_scdma); |
4653 | |
4654 | if (FC_SCRATCH_ACQUIRE(isp, chan)) { |
4655 | isp_prt(isp, ISP_LOGERR, sacq); |
4656 | break; |
4657 | } |
4658 | isp_put_24xx_abrt(isp, ab, fcp->isp_scratch); |
4659 | ab2 = (isp24xx_abrt_t *) |
4660 | &((uint8_t *)fcp->isp_scratch)[QENTRY_LEN]; |
4661 | ab2->abrt_nphdl = 0xdeaf; |
4662 | MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan); |
4663 | isp_mboxcmd(isp, &mbs); |
4664 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
4665 | FC_SCRATCH_RELEASE(isp, chan); |
4666 | break; |
4667 | } |
4668 | MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, |
4669 | QENTRY_LEN, chan); |
4670 | isp_get_24xx_abrt(isp, ab2, ab); |
4671 | FC_SCRATCH_RELEASE(isp, chan); |
4672 | if (ab->abrt_nphdl == ISP24XX_ABRT_OKAY) { |
4673 | return (0); |
4674 | } |
4675 | isp_prt(isp, ISP_LOGWARN, |
4676 | "Chan %d handle %d abort returned 0x%x" , chan, |
4677 | hdlidx, ab->abrt_nphdl); |
4678 | break; |
4679 | } else if (IS_FC(isp)) { |
4680 | if (ISP_CAP_SCCFW(isp)) { |
4681 | if (ISP_CAP_2KLOGIN(isp)) { |
4682 | mbs.param[1] = tgt; |
4683 | } else { |
4684 | mbs.param[1] = tgt << 8; |
4685 | } |
4686 | mbs.param[6] = XS_LUN(xs); |
4687 | } else { |
4688 | mbs.param[1] = tgt << 8 | XS_LUN(xs); |
4689 | } |
4690 | } else { |
4691 | mbs.param[1] = (chan << 15) | (tgt << 8) | XS_LUN(xs); |
4692 | } |
4693 | MBSINIT(&mbs, MBOX_ABORT, MBLOGALL & ~MBOX_COMMAND_ERROR, 0); |
4694 | mbs.param[2] = handle; |
4695 | isp_mboxcmd(isp, &mbs); |
4696 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
4697 | break; |
4698 | } |
4699 | return (0); |
4700 | |
4701 | case ISPCTL_UPDATE_PARAMS: |
4702 | |
4703 | va_start(ap, ctl); |
4704 | chan = va_arg(ap, int); |
4705 | va_end(ap); |
4706 | isp_spi_update(isp, chan); |
4707 | return (0); |
4708 | |
4709 | case ISPCTL_FCLINK_TEST: |
4710 | |
4711 | if (IS_FC(isp)) { |
4712 | int usdelay; |
4713 | va_start(ap, ctl); |
4714 | chan = va_arg(ap, int); |
4715 | usdelay = va_arg(ap, int); |
4716 | va_end(ap); |
4717 | if (usdelay == 0) { |
4718 | usdelay = 250000; |
4719 | } |
4720 | return (isp_fclink_test(isp, chan, usdelay)); |
4721 | } |
4722 | break; |
4723 | |
4724 | case ISPCTL_SCAN_FABRIC: |
4725 | |
4726 | if (IS_FC(isp)) { |
4727 | va_start(ap, ctl); |
4728 | chan = va_arg(ap, int); |
4729 | va_end(ap); |
4730 | return (isp_scan_fabric(isp, chan)); |
4731 | } |
4732 | break; |
4733 | |
4734 | case ISPCTL_SCAN_LOOP: |
4735 | |
4736 | if (IS_FC(isp)) { |
4737 | va_start(ap, ctl); |
4738 | chan = va_arg(ap, int); |
4739 | va_end(ap); |
4740 | return (isp_scan_loop(isp, chan)); |
4741 | } |
4742 | break; |
4743 | |
4744 | case ISPCTL_PDB_SYNC: |
4745 | |
4746 | if (IS_FC(isp)) { |
4747 | va_start(ap, ctl); |
4748 | chan = va_arg(ap, int); |
4749 | va_end(ap); |
4750 | return (isp_pdb_sync(isp, chan)); |
4751 | } |
4752 | break; |
4753 | |
4754 | case ISPCTL_SEND_LIP: |
4755 | |
4756 | if (IS_FC(isp) && !IS_24XX(isp)) { |
4757 | MBSINIT(&mbs, MBOX_INIT_LIP, MBLOGALL, 0); |
4758 | if (ISP_CAP_2KLOGIN(isp)) { |
4759 | mbs.ibits = (1 << 10); |
4760 | } |
4761 | isp_mboxcmd(isp, &mbs); |
4762 | if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { |
4763 | return (0); |
4764 | } |
4765 | } |
4766 | break; |
4767 | |
4768 | case ISPCTL_GET_PDB: |
4769 | if (IS_FC(isp)) { |
4770 | isp_pdb_t *pdb; |
4771 | va_start(ap, ctl); |
4772 | chan = va_arg(ap, int); |
4773 | tgt = va_arg(ap, int); |
4774 | pdb = va_arg(ap, isp_pdb_t *); |
4775 | va_end(ap); |
4776 | return (isp_getpdb(isp, chan, tgt, pdb, 1)); |
4777 | } |
4778 | break; |
4779 | |
4780 | case ISPCTL_GET_NAMES: |
4781 | { |
4782 | uint64_t *wwnn, *wwnp; |
4783 | va_start(ap, ctl); |
4784 | chan = va_arg(ap, int); |
4785 | tgt = va_arg(ap, int); |
4786 | wwnn = va_arg(ap, uint64_t *); |
4787 | wwnp = va_arg(ap, uint64_t *); |
4788 | va_end(ap); |
4789 | if (wwnn == NULL && wwnp == NULL) { |
4790 | break; |
4791 | } |
4792 | if (wwnn) { |
4793 | *wwnn = isp_get_wwn(isp, chan, tgt, 1); |
4794 | if (*wwnn == INI_NONE) { |
4795 | break; |
4796 | } |
4797 | } |
4798 | if (wwnp) { |
4799 | *wwnp = isp_get_wwn(isp, chan, tgt, 0); |
4800 | if (*wwnp == INI_NONE) { |
4801 | break; |
4802 | } |
4803 | } |
4804 | return (0); |
4805 | } |
4806 | case ISPCTL_RUN_MBOXCMD: |
4807 | { |
4808 | va_start(ap, ctl); |
4809 | mbr = va_arg(ap, mbreg_t *); |
4810 | va_end(ap); |
4811 | isp_mboxcmd(isp, mbr); |
4812 | return (0); |
4813 | } |
4814 | case ISPCTL_PLOGX: |
4815 | { |
4816 | isp_plcmd_t *p; |
4817 | int r; |
4818 | |
4819 | va_start(ap, ctl); |
4820 | p = va_arg(ap, isp_plcmd_t *); |
4821 | va_end(ap); |
4822 | |
4823 | if ((p->flags & PLOGX_FLG_CMD_MASK) != PLOGX_FLG_CMD_PLOGI || (p->handle != NIL_HANDLE)) { |
4824 | return (isp_plogx(isp, p->channel, p->handle, p->portid, p->flags, 0)); |
4825 | } |
4826 | do { |
4827 | p->handle = isp_nxt_handle(isp, p->channel, p->handle); |
4828 | r = isp_plogx(isp, p->channel, p->handle, p->portid, p->flags, 0); |
4829 | if ((r & 0xffff) == MBOX_PORT_ID_USED) { |
4830 | p->handle = r >> 16; |
4831 | r = 0; |
4832 | break; |
4833 | } |
4834 | } while ((r & 0xffff) == MBOX_LOOP_ID_USED); |
4835 | return (r); |
4836 | } |
4837 | default: |
4838 | isp_prt(isp, ISP_LOGERR, "Unknown Control Opcode 0x%x" , ctl); |
4839 | break; |
4840 | |
4841 | } |
4842 | return (-1); |
4843 | } |
4844 | |
4845 | /* |
4846 | * Interrupt Service Routine(s). |
4847 | * |
4848 | * External (OS) framework has done the appropriate locking, |
4849 | * and the locking will be held throughout this function. |
4850 | */ |
4851 | |
4852 | /* |
4853 | * Limit our stack depth by sticking with the max likely number |
4854 | * of completions on a request queue at any one time. |
4855 | */ |
4856 | #ifndef MAX_REQUESTQ_COMPLETIONS |
4857 | #define MAX_REQUESTQ_COMPLETIONS 32 |
4858 | #endif |
4859 | |
4860 | void |
4861 | isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) |
4862 | { |
4863 | XS_T *complist[MAX_REQUESTQ_COMPLETIONS], *xs; |
4864 | uint32_t iptr, optr, junk; |
4865 | int i, nlooked = 0, ndone = 0; |
4866 | |
4867 | again: |
4868 | optr = isp->isp_residx; |
4869 | /* |
4870 | * Is this a mailbox related interrupt? |
4871 | * The mailbox semaphore will be nonzero if so. |
4872 | */ |
4873 | if (sema) { |
4874 | fmbox: |
4875 | if (mbox & MBOX_COMMAND_COMPLETE) { |
4876 | isp->isp_intmboxc++; |
4877 | if (isp->isp_mboxbsy) { |
4878 | int obits = isp->isp_obits; |
4879 | isp->isp_mboxtmp[0] = mbox; |
4880 | for (i = 1; i < MAX_MAILBOX(isp); i++) { |
4881 | if ((obits & (1 << i)) == 0) { |
4882 | continue; |
4883 | } |
4884 | isp->isp_mboxtmp[i] = ISP_READ(isp, MBOX_OFF(i)); |
4885 | } |
4886 | if (isp->isp_mbxwrk0) { |
4887 | if (isp_mbox_continue(isp) == 0) { |
4888 | return; |
4889 | } |
4890 | } |
4891 | MBOX_NOTIFY_COMPLETE(isp); |
4892 | } else { |
4893 | isp_prt(isp, ISP_LOGWARN, "mailbox cmd (0x%x) with no waiters" , mbox); |
4894 | } |
4895 | } else { |
4896 | i = IS_FC(isp)? isp_parse_async_fc(isp, mbox) : isp_parse_async(isp, mbox); |
4897 | if (i < 0) { |
4898 | return; |
4899 | } |
4900 | } |
4901 | if ((IS_FC(isp) && mbox != ASYNC_RIOZIO_STALL) || isp->isp_state != ISP_RUNSTATE) { |
4902 | goto out; |
4903 | } |
4904 | } |
4905 | |
4906 | /* |
4907 | * We can't be getting this now. |
4908 | */ |
4909 | if (isp->isp_state != ISP_RUNSTATE) { |
4910 | /* |
4911 | * This seems to happen to 23XX and 24XX cards- don't know why. |
4912 | */ |
4913 | if (isp->isp_mboxbsy && isp->isp_lastmbxcmd == MBOX_ABOUT_FIRMWARE) { |
4914 | goto fmbox; |
4915 | } |
4916 | isp_prt(isp, ISP_LOGINFO, "interrupt (ISR=%x SEMA=%x) when not ready" , isr, sema); |
4917 | /* |
4918 | * Thank you very much! *Burrrp*! |
4919 | */ |
4920 | ISP_WRITE(isp, isp->isp_respoutrp, ISP_READ(isp, isp->isp_respinrp)); |
4921 | if (IS_24XX(isp)) { |
4922 | ISP_DISABLE_INTS(isp); |
4923 | } |
4924 | goto out; |
4925 | } |
4926 | |
4927 | #ifdef ISP_TARGET_MODE |
4928 | /* |
4929 | * Check for ATIO Queue entries. |
4930 | */ |
4931 | if (IS_24XX(isp)) { |
4932 | iptr = ISP_READ(isp, BIU2400_ATIO_RSPINP); |
4933 | optr = ISP_READ(isp, BIU2400_ATIO_RSPOUTP); |
4934 | |
4935 | while (optr != iptr) { |
4936 | uint8_t qe[QENTRY_LEN]; |
4937 | isphdr_t *hp; |
4938 | uint32_t oop; |
4939 | void *addr; |
4940 | |
4941 | oop = optr; |
4942 | MEMORYBARRIER(isp, SYNC_ATIOQ, oop, QENTRY_LEN, -1); |
4943 | addr = ISP_QUEUE_ENTRY(isp->isp_atioq, oop); |
4944 | isp_get_hdr(isp, addr, (isphdr_t *)qe); |
4945 | hp = (isphdr_t *)qe; |
4946 | switch (hp->rqs_entry_type) { |
4947 | case RQSTYPE_NOTIFY: |
4948 | case RQSTYPE_ATIO: |
4949 | (void) isp_target_notify(isp, addr, &oop); |
4950 | break; |
4951 | default: |
4952 | isp_print_qentry(isp, "?ATIOQ entry?" , oop, addr); |
4953 | break; |
4954 | } |
4955 | optr = ISP_NXT_QENTRY(oop, RESULT_QUEUE_LEN(isp)); |
4956 | ISP_WRITE(isp, BIU2400_ATIO_RSPOUTP, optr); |
4957 | } |
4958 | optr = isp->isp_residx; |
4959 | } |
4960 | #endif |
4961 | |
4962 | /* |
4963 | * Get the current Response Queue Out Pointer. |
4964 | * |
4965 | * If we're a 2300 or 2400, we can ask what hardware what it thinks. |
4966 | */ |
4967 | if (IS_23XX(isp) || IS_24XX(isp)) { |
4968 | optr = ISP_READ(isp, isp->isp_respoutrp); |
4969 | /* |
4970 | * Debug: to be taken out eventually |
4971 | */ |
4972 | if (isp->isp_residx != optr) { |
4973 | isp_prt(isp, ISP_LOGINFO, "isp_intr: hard optr=%x, soft optr %x" , optr, isp->isp_residx); |
4974 | isp->isp_residx = optr; |
4975 | } |
4976 | } else { |
4977 | optr = isp->isp_residx; |
4978 | } |
4979 | |
4980 | /* |
4981 | * You *must* read the Response Queue In Pointer |
4982 | * prior to clearing the RISC interrupt. |
4983 | * |
4984 | * Debounce the 2300 if revision less than 2. |
4985 | */ |
4986 | if (IS_2100(isp) || (IS_2300(isp) && isp->isp_revision < 2)) { |
4987 | i = 0; |
4988 | do { |
4989 | iptr = ISP_READ(isp, isp->isp_respinrp); |
4990 | junk = ISP_READ(isp, isp->isp_respinrp); |
4991 | } while (junk != iptr && ++i < 1000); |
4992 | |
4993 | if (iptr != junk) { |
4994 | isp_prt(isp, ISP_LOGWARN, "Response Queue Out Pointer Unstable (%x, %x)" , iptr, junk); |
4995 | goto out; |
4996 | } |
4997 | } else { |
4998 | iptr = ISP_READ(isp, isp->isp_respinrp); |
4999 | } |
5000 | isp->isp_resodx = iptr; |
5001 | |
5002 | |
5003 | if (optr == iptr && sema == 0) { |
5004 | /* |
5005 | * There are a lot of these- reasons unknown- mostly on |
5006 | * faster Alpha machines. |
5007 | * |
5008 | * I tried delaying after writing HCCR_CMD_CLEAR_RISC_INT to |
5009 | * make sure the old interrupt went away (to avoid 'ringing' |
5010 | * effects), but that didn't stop this from occurring. |
5011 | */ |
5012 | if (IS_24XX(isp)) { |
5013 | junk = 0; |
5014 | } else if (IS_23XX(isp)) { |
5015 | ISP_DELAY(100); |
5016 | iptr = ISP_READ(isp, isp->isp_respinrp); |
5017 | junk = ISP_READ(isp, BIU_R2HSTSLO); |
5018 | } else { |
5019 | junk = ISP_READ(isp, BIU_ISR); |
5020 | } |
5021 | if (optr == iptr) { |
5022 | if (IS_23XX(isp) || IS_24XX(isp)) { |
5023 | ; |
5024 | } else { |
5025 | sema = ISP_READ(isp, BIU_SEMA); |
5026 | mbox = ISP_READ(isp, OUTMAILBOX0); |
5027 | if ((sema & 0x3) && (mbox & 0x8000)) { |
5028 | goto again; |
5029 | } |
5030 | } |
5031 | isp->isp_intbogus++; |
5032 | isp_prt(isp, ISP_LOGDEBUG1, "bogus intr- isr %x (%x) iptr %x optr %x" , isr, junk, iptr, optr); |
5033 | } |
5034 | } |
5035 | isp->isp_resodx = iptr; |
5036 | |
5037 | while (optr != iptr) { |
5038 | uint8_t qe[QENTRY_LEN]; |
5039 | ispstatusreq_t *sp = (ispstatusreq_t *) qe; |
5040 | isphdr_t *hp; |
5041 | int buddaboom, etype, scsi_status, completion_status; |
5042 | int req_status_flags, req_state_flags; |
5043 | uint8_t *snsp, *resp; |
5044 | uint32_t rlen, slen; |
5045 | long resid; |
5046 | uint16_t oop; |
5047 | |
5048 | hp = (isphdr_t *) ISP_QUEUE_ENTRY(isp->isp_result, optr); |
5049 | oop = optr; |
5050 | optr = ISP_NXT_QENTRY(optr, RESULT_QUEUE_LEN(isp)); |
5051 | nlooked++; |
5052 | read_again: |
5053 | buddaboom = req_status_flags = req_state_flags = 0; |
5054 | resid = 0L; |
5055 | |
5056 | /* |
5057 | * Synchronize our view of this response queue entry. |
5058 | */ |
5059 | MEMORYBARRIER(isp, SYNC_RESULT, oop, QENTRY_LEN, -1); |
5060 | isp_get_hdr(isp, hp, &sp->req_header); |
5061 | etype = sp->req_header.rqs_entry_type; |
5062 | |
5063 | if (IS_24XX(isp) && etype == RQSTYPE_RESPONSE) { |
5064 | isp24xx_statusreq_t *sp2 = (isp24xx_statusreq_t *)qe; |
5065 | isp_get_24xx_response(isp, (isp24xx_statusreq_t *)hp, sp2); |
5066 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
5067 | isp_print_bytes(isp, "Response Queue Entry" , QENTRY_LEN, sp2); |
5068 | } |
5069 | scsi_status = sp2->req_scsi_status; |
5070 | completion_status = sp2->req_completion_status; |
5071 | req_state_flags = 0; |
5072 | resid = sp2->req_resid; |
5073 | } else if (etype == RQSTYPE_RESPONSE) { |
5074 | isp_get_response(isp, (ispstatusreq_t *) hp, sp); |
5075 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
5076 | isp_print_bytes(isp, "Response Queue Entry" , QENTRY_LEN, sp); |
5077 | } |
5078 | scsi_status = sp->req_scsi_status; |
5079 | completion_status = sp->req_completion_status; |
5080 | req_status_flags = sp->req_status_flags; |
5081 | req_state_flags = sp->req_state_flags; |
5082 | resid = sp->req_resid; |
5083 | } else if (etype == RQSTYPE_RIO1) { |
5084 | isp_rio1_t *rio = (isp_rio1_t *) qe; |
5085 | isp_get_rio1(isp, (isp_rio1_t *) hp, rio); |
5086 | if (isp->isp_dblev & ISP_LOGDEBUG1) { |
5087 | isp_print_bytes(isp, "Response Queue Entry" , QENTRY_LEN, rio); |
5088 | } |
5089 | for (i = 0; i < rio->req_header.rqs_seqno; i++) { |
5090 | isp_fastpost_complete(isp, rio->req_handles[i]); |
5091 | } |
5092 | if (isp->isp_fpcchiwater < rio->req_header.rqs_seqno) { |
5093 | isp->isp_fpcchiwater = rio->req_header.rqs_seqno; |
5094 | } |
5095 | ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ |
5096 | continue; |
5097 | } else if (etype == RQSTYPE_RIO2) { |
5098 | isp_prt(isp, ISP_LOGERR, "dropping RIO2 response\n" ); |
5099 | ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ |
5100 | continue; |
5101 | } else { |
5102 | /* |
5103 | * Somebody reachable via isp_handle_other_response |
5104 | * may have updated the response queue pointers for |
5105 | * us, so we reload our goal index. |
5106 | */ |
5107 | int r; |
5108 | uint32_t tsto = oop; |
5109 | r = isp_handle_other_response(isp, etype, hp, &tsto); |
5110 | if (r < 0) { |
5111 | goto read_again; |
5112 | } |
5113 | /* |
5114 | * If somebody updated the output pointer, then reset |
5115 | * optr to be one more than the updated amount. |
5116 | */ |
5117 | while (tsto != oop) { |
5118 | optr = ISP_NXT_QENTRY(tsto, |
5119 | RESULT_QUEUE_LEN(isp)); |
5120 | } |
5121 | if (r > 0) { |
5122 | ISP_WRITE(isp, isp->isp_respoutrp, optr); |
5123 | ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ |
5124 | continue; |
5125 | } |
5126 | |
5127 | /* |
5128 | * After this point, we'll just look at the header as |
5129 | * we don't know how to deal with the rest of the |
5130 | * response. |
5131 | */ |
5132 | |
5133 | /* |
5134 | * It really has to be a bounced request just copied |
5135 | * from the request queue to the response queue. If |
5136 | * not, something bad has happened. |
5137 | */ |
5138 | if (etype != RQSTYPE_REQUEST) { |
5139 | isp_prt(isp, ISP_LOGERR, notresp, |
5140 | etype, oop, optr, nlooked); |
5141 | isp_print_bytes(isp, |
5142 | "Request Queue Entry" , QENTRY_LEN, sp); |
5143 | ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ |
5144 | continue; |
5145 | } |
5146 | buddaboom = 1; |
5147 | scsi_status = sp->req_scsi_status; |
5148 | completion_status = sp->req_completion_status; |
5149 | req_status_flags = sp->req_status_flags; |
5150 | req_state_flags = sp->req_state_flags; |
5151 | resid = sp->req_resid; |
5152 | } |
5153 | |
5154 | if (sp->req_header.rqs_flags & RQSFLAG_MASK) { |
5155 | if (sp->req_header.rqs_flags & RQSFLAG_CONTINUATION) { |
5156 | isp_print_bytes(isp, "unexpected continuation segment" , QENTRY_LEN, sp); |
5157 | ISP_WRITE(isp, isp->isp_respoutrp, optr); |
5158 | continue; |
5159 | } |
5160 | if (sp->req_header.rqs_flags & RQSFLAG_FULL) { |
5161 | isp_prt(isp, ISP_LOGDEBUG0, "internal queues full" ); |
5162 | /* |
5163 | * We'll synthesize a QUEUE FULL message below. |
5164 | */ |
5165 | } |
5166 | if (sp->req_header.rqs_flags & RQSFLAG_BADHEADER) { |
5167 | isp_print_bytes(isp, "bad header flag" , QENTRY_LEN, sp); |
5168 | buddaboom++; |
5169 | } |
5170 | if (sp->req_header.rqs_flags & RQSFLAG_BADPACKET) { |
5171 | isp_print_bytes(isp, "bad request packet" , QENTRY_LEN, sp); |
5172 | buddaboom++; |
5173 | } |
5174 | if (sp->req_header.rqs_flags & RQSFLAG_BADCOUNT) { |
5175 | isp_print_bytes(isp, "invalid entry count" , QENTRY_LEN, sp); |
5176 | buddaboom++; |
5177 | } |
5178 | if (sp->req_header.rqs_flags & RQSFLAG_BADORDER) { |
5179 | isp_print_bytes(isp, "invalid IOCB ordering" , QENTRY_LEN, sp); |
5180 | ISP_WRITE(isp, isp->isp_respoutrp, optr); |
5181 | continue; |
5182 | } |
5183 | } |
5184 | |
5185 | if (!ISP_VALID_HANDLE(isp, sp->req_handle)) { |
5186 | isp_prt(isp, ISP_LOGERR, "bad request handle 0x%x (iocb type 0x%x)" , sp->req_handle, etype); |
5187 | ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ |
5188 | ISP_WRITE(isp, isp->isp_respoutrp, optr); |
5189 | continue; |
5190 | } |
5191 | xs = isp_find_xs(isp, sp->req_handle); |
5192 | if (xs == NULL) { |
5193 | uint8_t ts = completion_status & 0xff; |
5194 | /* |
5195 | * Only whine if this isn't the expected fallout of |
5196 | * aborting the command or resetting the target. |
5197 | */ |
5198 | if (etype != RQSTYPE_RESPONSE) { |
5199 | isp_prt(isp, ISP_LOGERR, "cannot find handle 0x%x (type 0x%x)" , sp->req_handle, etype); |
5200 | } else if (ts != RQCS_ABORTED && ts != RQCS_RESET_OCCURRED) { |
5201 | isp_prt(isp, ISP_LOGERR, "cannot find handle 0x%x (status 0x%x)" , sp->req_handle, ts); |
5202 | } |
5203 | ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ |
5204 | ISP_WRITE(isp, isp->isp_respoutrp, optr); |
5205 | continue; |
5206 | } |
5207 | if (req_status_flags & RQSTF_BUS_RESET) { |
5208 | XS_SETERR(xs, HBA_BUSRESET); |
5209 | ISP_SET_SENDMARKER(isp, XS_CHANNEL(xs), 1); |
5210 | } |
5211 | if (buddaboom) { |
5212 | XS_SETERR(xs, HBA_BOTCH); |
5213 | } |
5214 | |
5215 | resp = NULL; |
5216 | rlen = 0; |
5217 | snsp = NULL; |
5218 | slen = 0; |
5219 | if (IS_24XX(isp) && (scsi_status & (RQCS_RV|RQCS_SV)) != 0) { |
5220 | resp = ((isp24xx_statusreq_t *)sp)->req_rsp_sense; |
5221 | rlen = ((isp24xx_statusreq_t *)sp)->req_response_len; |
5222 | } else if (IS_FC(isp) && (scsi_status & RQCS_RV) != 0) { |
5223 | resp = sp->req_response; |
5224 | rlen = sp->req_response_len; |
5225 | } |
5226 | if (IS_FC(isp) && (scsi_status & RQCS_SV) != 0) { |
5227 | /* |
5228 | * Fibre Channel F/W doesn't say we got status |
5229 | * if there's Sense Data instead. I guess they |
5230 | * think it goes w/o saying. |
5231 | */ |
5232 | req_state_flags |= RQSF_GOT_STATUS|RQSF_GOT_SENSE; |
5233 | if (IS_24XX(isp)) { |
5234 | snsp = ((isp24xx_statusreq_t *)sp)->req_rsp_sense; |
5235 | snsp += rlen; |
5236 | slen = ((isp24xx_statusreq_t *)sp)->req_sense_len; |
5237 | } else { |
5238 | snsp = sp->req_sense_data; |
5239 | slen = sp->req_sense_len; |
5240 | } |
5241 | } else if (IS_SCSI(isp) && (req_state_flags & RQSF_GOT_SENSE)) { |
5242 | snsp = sp->req_sense_data; |
5243 | slen = sp->req_sense_len; |
5244 | } |
5245 | if (req_state_flags & RQSF_GOT_STATUS) { |
5246 | *XS_STSP(xs) = scsi_status & 0xff; |
5247 | } |
5248 | |
5249 | switch (etype) { |
5250 | case RQSTYPE_RESPONSE: |
5251 | if (resp && rlen >= 4 && resp[FCP_RSPNS_CODE_OFFSET] != 0) { |
5252 | const char *ptr; |
5253 | char lb[64]; |
5254 | const char *rnames[6] = { |
5255 | "Task Management Function Done" , |
5256 | "Data Length Differs From Burst Length" , |
5257 | "Invalid FCP Cmnd" , |
5258 | "FCP DATA RO mismatch with FCP DATA_XFR_RDY RO" , |
5259 | "Task Management Function Rejected" , |
5260 | "Task Management Function Failed" , |
5261 | }; |
5262 | if (resp[FCP_RSPNS_CODE_OFFSET] > 5) { |
5263 | ISP_SNPRINTF(lb, sizeof lb, "Unknown FCP Response Code 0x%x" , resp[FCP_RSPNS_CODE_OFFSET]); |
5264 | ptr = lb; |
5265 | } else { |
5266 | ptr = rnames[resp[FCP_RSPNS_CODE_OFFSET]]; |
5267 | } |
5268 | isp_xs_prt(isp, xs, ISP_LOGWARN, "FCP RESPONSE, LENGTH %u: %s CDB0=0x%02x" , rlen, ptr, XS_CDBP(xs)[0] & 0xff); |
5269 | if (resp[FCP_RSPNS_CODE_OFFSET] != 0) { |
5270 | XS_SETERR(xs, HBA_BOTCH); |
5271 | } |
5272 | } |
5273 | if (IS_24XX(isp)) { |
5274 | isp_parse_status_24xx(isp, (isp24xx_statusreq_t *)sp, xs, &resid); |
5275 | } else { |
5276 | isp_parse_status(isp, (void *)sp, xs, &resid); |
5277 | } |
5278 | if ((XS_NOERR(xs) || XS_ERR(xs) == HBA_NOERROR) && (*XS_STSP(xs) == SCSI_BUSY)) { |
5279 | XS_SETERR(xs, HBA_TGTBSY); |
5280 | } |
5281 | if (IS_SCSI(isp)) { |
5282 | XS_SET_RESID(xs, resid); |
5283 | /* |
5284 | * A new synchronous rate was negotiated for |
5285 | * this target. Mark state such that we'll go |
5286 | * look up that which has changed later. |
5287 | */ |
5288 | if (req_status_flags & RQSTF_NEGOTIATION) { |
5289 | int t = XS_TGT(xs); |
5290 | sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); |
5291 | sdp->isp_devparam[t].dev_refresh = 1; |
5292 | sdp->update = 1; |
5293 | } |
5294 | } else { |
5295 | if (req_status_flags & RQSF_XFER_COMPLETE) { |
5296 | XS_SET_RESID(xs, 0); |
5297 | } else if (scsi_status & RQCS_RESID) { |
5298 | XS_SET_RESID(xs, resid); |
5299 | } else { |
5300 | XS_SET_RESID(xs, 0); |
5301 | } |
5302 | } |
5303 | if (snsp && slen) { |
5304 | XS_SAVE_SENSE(xs, snsp, slen); |
5305 | } else if ((req_status_flags & RQSF_GOT_STATUS) && (scsi_status & 0xff) == SCSI_CHECK && IS_FC(isp)) { |
5306 | isp_prt(isp, ISP_LOGWARN, "CHECK CONDITION w/o sense data for CDB=0x%x" , XS_CDBP(xs)[0] & 0xff); |
5307 | isp_print_bytes(isp, "CC with no Sense" , QENTRY_LEN, qe); |
5308 | } |
5309 | isp_prt(isp, ISP_LOGDEBUG2, "asked for %ld got raw resid %ld settled for %ld" , (long) XS_XFRLEN(xs), resid, (long) XS_GET_RESID(xs)); |
5310 | break; |
5311 | case RQSTYPE_REQUEST: |
5312 | case RQSTYPE_A64: |
5313 | case RQSTYPE_T2RQS: |
5314 | case RQSTYPE_T3RQS: |
5315 | case RQSTYPE_T7RQS: |
5316 | if (!IS_24XX(isp) && (sp->req_header.rqs_flags & RQSFLAG_FULL)) { |
5317 | /* |
5318 | * Force Queue Full status. |
5319 | */ |
5320 | *XS_STSP(xs) = SCSI_QFULL; |
5321 | XS_SETERR(xs, HBA_NOERROR); |
5322 | } else if (XS_NOERR(xs)) { |
5323 | XS_SETERR(xs, HBA_BOTCH); |
5324 | } |
5325 | XS_SET_RESID(xs, XS_XFRLEN(xs)); |
5326 | break; |
5327 | default: |
5328 | isp_print_bytes(isp, "Unhandled Response Type" , QENTRY_LEN, qe); |
5329 | if (XS_NOERR(xs)) { |
5330 | XS_SETERR(xs, HBA_BOTCH); |
5331 | } |
5332 | break; |
5333 | } |
5334 | |
5335 | /* |
5336 | * Free any DMA resources. As a side effect, this may |
5337 | * also do any cache flushing necessary for data coherence. |
5338 | */ |
5339 | if (XS_XFRLEN(xs)) { |
5340 | ISP_DMAFREE(isp, xs, sp->req_handle); |
5341 | } |
5342 | isp_destroy_handle(isp, sp->req_handle); |
5343 | |
5344 | if (((isp->isp_dblev & (ISP_LOGDEBUG1|ISP_LOGDEBUG2|ISP_LOGDEBUG3))) || |
5345 | ((isp->isp_dblev & (ISP_LOGDEBUG0|ISP_LOG_CWARN) && ((!XS_NOERR(xs)) || (*XS_STSP(xs) != SCSI_GOOD))))) { |
5346 | isp_prt_endcmd(isp, xs); |
5347 | } |
5348 | if (isp->isp_nactive > 0) { |
5349 | isp->isp_nactive--; |
5350 | } |
5351 | complist[ndone++] = xs; /* defer completion call until later */ |
5352 | ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ |
5353 | if (ndone == MAX_REQUESTQ_COMPLETIONS) { |
5354 | break; |
5355 | } |
5356 | } |
5357 | |
5358 | /* |
5359 | * If we looked at any commands, then it's valid to find out |
5360 | * what the outpointer is. It also is a trigger to update the |
5361 | * ISP's notion of what we've seen so far. |
5362 | */ |
5363 | if (nlooked) { |
5364 | ISP_WRITE(isp, isp->isp_respoutrp, optr); |
5365 | /* |
5366 | * While we're at it, read the requst queue out pointer. |
5367 | */ |
5368 | isp->isp_reqodx = ISP_READ(isp, isp->isp_rqstoutrp); |
5369 | if (isp->isp_rscchiwater < ndone) { |
5370 | isp->isp_rscchiwater = ndone; |
5371 | } |
5372 | } |
5373 | |
5374 | out: |
5375 | |
5376 | if (IS_24XX(isp)) { |
5377 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT); |
5378 | } else { |
5379 | ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); |
5380 | ISP_WRITE(isp, BIU_SEMA, 0); |
5381 | } |
5382 | |
5383 | isp->isp_residx = optr; |
5384 | for (i = 0; i < ndone; i++) { |
5385 | xs = complist[i]; |
5386 | if (xs) { |
5387 | isp->isp_rsltccmplt++; |
5388 | isp_done(xs); |
5389 | } |
5390 | } |
5391 | } |
5392 | |
5393 | /* |
5394 | * Support routines. |
5395 | */ |
5396 | |
5397 | static void |
5398 | isp_prt_endcmd(ispsoftc_t *isp, XS_T *xs) |
5399 | { |
5400 | char cdbstr[16 * 5 + 1]; |
5401 | int i, lim; |
5402 | |
5403 | lim = XS_CDBLEN(xs) > 16? 16 : XS_CDBLEN(xs); |
5404 | ISP_SNPRINTF(cdbstr, sizeof (cdbstr), "0x%02x " , XS_CDBP(xs)[0]); |
5405 | for (i = 1; i < lim; i++) { |
5406 | ISP_SNPRINTF(cdbstr, sizeof (cdbstr), "%s0x%02x " , cdbstr, XS_CDBP(xs)[i]); |
5407 | } |
5408 | if (XS_SENSE_VALID(xs)) { |
5409 | isp_xs_prt(isp, xs, ISP_LOGALL, "FIN dl%d resid %ld CDB=%s KEY/ASC/ASCQ=0x%02x/0x%02x/0x%02x" , |
5410 | XS_XFRLEN(xs), (long) XS_GET_RESID(xs), cdbstr, XS_SNSKEY(xs), XS_SNSASC(xs), XS_SNSASCQ(xs)); |
5411 | } else { |
5412 | isp_xs_prt(isp, xs, ISP_LOGALL, "FIN dl%d resid %ld CDB=%s STS 0x%x XS_ERR=0x%x" , XS_XFRLEN(xs), (long) XS_GET_RESID(xs), cdbstr, *XS_STSP(xs), XS_ERR(xs)); |
5413 | } |
5414 | } |
5415 | |
5416 | /* |
5417 | * Parse an ASYNC mailbox complete |
5418 | * |
5419 | * Return non-zero if the event has been acknowledged. |
5420 | */ |
5421 | static int |
5422 | isp_parse_async(ispsoftc_t *isp, uint16_t mbox) |
5423 | { |
5424 | int acked = 0; |
5425 | uint32_t h1 = 0, h2 = 0; |
5426 | uint16_t chan = 0; |
5427 | |
5428 | /* |
5429 | * Pick up the channel, but not if this is a ASYNC_RIO32_2, |
5430 | * where Mailboxes 6/7 have the second handle. |
5431 | */ |
5432 | if (mbox != ASYNC_RIO32_2) { |
5433 | if (IS_DUALBUS(isp)) { |
5434 | chan = ISP_READ(isp, OUTMAILBOX6); |
5435 | } |
5436 | } |
5437 | isp_prt(isp, ISP_LOGDEBUG2, "Async Mbox 0x%x" , mbox); |
5438 | |
5439 | switch (mbox) { |
5440 | case ASYNC_BUS_RESET: |
5441 | ISP_SET_SENDMARKER(isp, chan, 1); |
5442 | #ifdef ISP_TARGET_MODE |
5443 | if (isp_target_async(isp, chan, mbox)) { |
5444 | acked = 1; |
5445 | } |
5446 | #endif |
5447 | isp_async(isp, ISPASYNC_BUS_RESET, chan); |
5448 | break; |
5449 | case ASYNC_SYSTEM_ERROR: |
5450 | isp->isp_dead = 1; |
5451 | isp->isp_state = ISP_CRASHED; |
5452 | /* |
5453 | * Were we waiting for a mailbox command to complete? |
5454 | * If so, it's dead, so wake up the waiter. |
5455 | */ |
5456 | if (isp->isp_mboxbsy) { |
5457 | isp->isp_obits = 1; |
5458 | isp->isp_mboxtmp[0] = MBOX_HOST_INTERFACE_ERROR; |
5459 | MBOX_NOTIFY_COMPLETE(isp); |
5460 | } |
5461 | /* |
5462 | * It's up to the handler for isp_async to reinit stuff and |
5463 | * restart the firmware |
5464 | */ |
5465 | isp_async(isp, ISPASYNC_FW_CRASH); |
5466 | acked = 1; |
5467 | break; |
5468 | |
5469 | case ASYNC_RQS_XFER_ERR: |
5470 | isp_prt(isp, ISP_LOGERR, "Request Queue Transfer Error" ); |
5471 | break; |
5472 | |
5473 | case ASYNC_RSP_XFER_ERR: |
5474 | isp_prt(isp, ISP_LOGERR, "Response Queue Transfer Error" ); |
5475 | break; |
5476 | |
5477 | case ASYNC_QWAKEUP: |
5478 | /* |
5479 | * We've just been notified that the Queue has woken up. |
5480 | * We don't need to be chatty about this- just unlatch things |
5481 | * and move on. |
5482 | */ |
5483 | mbox = ISP_READ(isp, isp->isp_rqstoutrp); |
5484 | break; |
5485 | |
5486 | case ASYNC_TIMEOUT_RESET: |
5487 | isp_prt(isp, ISP_LOGWARN, "timeout initiated SCSI bus reset of chan %d" , chan); |
5488 | ISP_SET_SENDMARKER(isp, chan, 1); |
5489 | #ifdef ISP_TARGET_MODE |
5490 | if (isp_target_async(isp, chan, mbox)) { |
5491 | acked = 1; |
5492 | } |
5493 | #endif |
5494 | break; |
5495 | |
5496 | case ASYNC_DEVICE_RESET: |
5497 | isp_prt(isp, ISP_LOGINFO, "device reset on chan %d" , chan); |
5498 | ISP_SET_SENDMARKER(isp, chan, 1); |
5499 | #ifdef ISP_TARGET_MODE |
5500 | if (isp_target_async(isp, chan, mbox)) { |
5501 | acked = 1; |
5502 | } |
5503 | #endif |
5504 | break; |
5505 | |
5506 | case ASYNC_EXTMSG_UNDERRUN: |
5507 | isp_prt(isp, ISP_LOGWARN, "extended message underrun" ); |
5508 | break; |
5509 | |
5510 | case ASYNC_SCAM_INT: |
5511 | isp_prt(isp, ISP_LOGINFO, "SCAM interrupt" ); |
5512 | break; |
5513 | |
5514 | case ASYNC_HUNG_SCSI: |
5515 | isp_prt(isp, ISP_LOGERR, "stalled SCSI Bus after DATA Overrun" ); |
5516 | /* XXX: Need to issue SCSI reset at this point */ |
5517 | break; |
5518 | |
5519 | case ASYNC_KILLED_BUS: |
5520 | isp_prt(isp, ISP_LOGERR, "SCSI Bus reset after DATA Overrun" ); |
5521 | break; |
5522 | |
5523 | case ASYNC_BUS_TRANSIT: |
5524 | mbox = ISP_READ(isp, OUTMAILBOX2); |
5525 | switch (mbox & SXP_PINS_MODE_MASK) { |
5526 | case SXP_PINS_LVD_MODE: |
5527 | isp_prt(isp, ISP_LOGINFO, "Transition to LVD mode" ); |
5528 | SDPARAM(isp, chan)->isp_diffmode = 0; |
5529 | SDPARAM(isp, chan)->isp_ultramode = 0; |
5530 | SDPARAM(isp, chan)->isp_lvdmode = 1; |
5531 | break; |
5532 | case SXP_PINS_HVD_MODE: |
5533 | isp_prt(isp, ISP_LOGINFO, |
5534 | "Transition to Differential mode" ); |
5535 | SDPARAM(isp, chan)->isp_diffmode = 1; |
5536 | SDPARAM(isp, chan)->isp_ultramode = 0; |
5537 | SDPARAM(isp, chan)->isp_lvdmode = 0; |
5538 | break; |
5539 | case SXP_PINS_SE_MODE: |
5540 | isp_prt(isp, ISP_LOGINFO, |
5541 | "Transition to Single Ended mode" ); |
5542 | SDPARAM(isp, chan)->isp_diffmode = 0; |
5543 | SDPARAM(isp, chan)->isp_ultramode = 1; |
5544 | SDPARAM(isp, chan)->isp_lvdmode = 0; |
5545 | break; |
5546 | default: |
5547 | isp_prt(isp, ISP_LOGWARN, |
5548 | "Transition to Unknown Mode 0x%x" , mbox); |
5549 | break; |
5550 | } |
5551 | /* |
5552 | * XXX: Set up to renegotiate again! |
5553 | */ |
5554 | /* Can only be for a 1080... */ |
5555 | ISP_SET_SENDMARKER(isp, chan, 1); |
5556 | break; |
5557 | |
5558 | case ASYNC_CMD_CMPLT: |
5559 | case ASYNC_RIO32_1: |
5560 | if (!IS_ULTRA3(isp)) { |
5561 | isp_prt(isp, ISP_LOGERR, "unexpected fast posting completion" ); |
5562 | break; |
5563 | } |
5564 | /* FALLTHROUGH */ |
5565 | h1 = (ISP_READ(isp, OUTMAILBOX2) << 16) | ISP_READ(isp, OUTMAILBOX1); |
5566 | break; |
5567 | |
5568 | case ASYNC_RIO32_2: |
5569 | h1 = (ISP_READ(isp, OUTMAILBOX2) << 16) | ISP_READ(isp, OUTMAILBOX1); |
5570 | h2 = (ISP_READ(isp, OUTMAILBOX7) << 16) | ISP_READ(isp, OUTMAILBOX6); |
5571 | break; |
5572 | |
5573 | case ASYNC_RIO16_5: |
5574 | case ASYNC_RIO16_4: |
5575 | case ASYNC_RIO16_3: |
5576 | case ASYNC_RIO16_2: |
5577 | case ASYNC_RIO16_1: |
5578 | isp_prt(isp, ISP_LOGERR, "unexpected 16 bit RIO handle" ); |
5579 | break; |
5580 | default: |
5581 | isp_prt(isp, ISP_LOGWARN, "%s: unhandled async code 0x%x" , __func__, mbox); |
5582 | break; |
5583 | } |
5584 | |
5585 | if (h1 || h2) { |
5586 | isp_prt(isp, ISP_LOGDEBUG3, "fast post/rio completion of 0x%08x" , h1); |
5587 | isp_fastpost_complete(isp, h1); |
5588 | if (h2) { |
5589 | isp_prt(isp, ISP_LOGDEBUG3, "fast post/rio completion of 0x%08x" , h2); |
5590 | isp_fastpost_complete(isp, h2); |
5591 | if (isp->isp_fpcchiwater < 2) { |
5592 | isp->isp_fpcchiwater = 2; |
5593 | } |
5594 | } else { |
5595 | if (isp->isp_fpcchiwater < 1) { |
5596 | isp->isp_fpcchiwater = 1; |
5597 | } |
5598 | } |
5599 | } else { |
5600 | isp->isp_intoasync++; |
5601 | } |
5602 | return (acked); |
5603 | } |
5604 | |
5605 | #define GET_24XX_BUS(isp, chan, msg) \ |
5606 | if (IS_24XX(isp)) { \ |
5607 | chan = ISP_READ(isp, OUTMAILBOX3) & 0xff; \ |
5608 | if (chan >= isp->isp_nchan) { \ |
5609 | isp_prt(isp, ISP_LOGERR, "bogus channel %u for %s at line %d", chan, msg, __LINE__); \ |
5610 | break; \ |
5611 | } \ |
5612 | } |
5613 | |
5614 | |
5615 | static int |
5616 | isp_parse_async_fc(ispsoftc_t *isp, uint16_t mbox) |
5617 | { |
5618 | int acked = 0; |
5619 | uint16_t chan; |
5620 | |
5621 | if (IS_DUALBUS(isp)) { |
5622 | chan = ISP_READ(isp, OUTMAILBOX6); |
5623 | } else { |
5624 | chan = 0; |
5625 | } |
5626 | isp_prt(isp, ISP_LOGDEBUG2, "Async Mbox 0x%x" , mbox); |
5627 | |
5628 | switch (mbox) { |
5629 | case ASYNC_SYSTEM_ERROR: |
5630 | isp->isp_dead = 1; |
5631 | isp->isp_state = ISP_CRASHED; |
5632 | FCPARAM(isp, chan)->isp_loopstate = LOOP_NIL; |
5633 | FCPARAM(isp, chan)->isp_fwstate = FW_CONFIG_WAIT; |
5634 | /* |
5635 | * Were we waiting for a mailbox command to complete? |
5636 | * If so, it's dead, so wake up the waiter. |
5637 | */ |
5638 | if (isp->isp_mboxbsy) { |
5639 | isp->isp_obits = 1; |
5640 | isp->isp_mboxtmp[0] = MBOX_HOST_INTERFACE_ERROR; |
5641 | MBOX_NOTIFY_COMPLETE(isp); |
5642 | } |
5643 | /* |
5644 | * It's up to the handler for isp_async to reinit stuff and |
5645 | * restart the firmware |
5646 | */ |
5647 | isp_async(isp, ISPASYNC_FW_CRASH); |
5648 | acked = 1; |
5649 | break; |
5650 | |
5651 | case ASYNC_RQS_XFER_ERR: |
5652 | isp_prt(isp, ISP_LOGERR, "Request Queue Transfer Error" ); |
5653 | break; |
5654 | |
5655 | case ASYNC_RSP_XFER_ERR: |
5656 | isp_prt(isp, ISP_LOGERR, "Response Queue Transfer Error" ); |
5657 | break; |
5658 | |
5659 | case ASYNC_QWAKEUP: |
5660 | #ifdef ISP_TARGET_MODE |
5661 | if (IS_24XX(isp)) { |
5662 | isp_prt(isp, ISP_LOGERR, "ATIO Queue Transfer Error" ); |
5663 | break; |
5664 | } |
5665 | #endif |
5666 | isp_prt(isp, ISP_LOGERR, "%s: unexpected ASYNC_QWAKEUP code" , __func__); |
5667 | break; |
5668 | |
5669 | case ASYNC_CMD_CMPLT: |
5670 | isp_fastpost_complete(isp, (ISP_READ(isp, OUTMAILBOX2) << 16) | ISP_READ(isp, OUTMAILBOX1)); |
5671 | if (isp->isp_fpcchiwater < 1) { |
5672 | isp->isp_fpcchiwater = 1; |
5673 | } |
5674 | break; |
5675 | |
5676 | case ASYNC_RIOZIO_STALL: |
5677 | break; |
5678 | |
5679 | case ASYNC_CTIO_DONE: |
5680 | #ifdef ISP_TARGET_MODE |
5681 | if (isp_target_async(isp, (ISP_READ(isp, OUTMAILBOX2) << 16) | ISP_READ(isp, OUTMAILBOX1), mbox)) { |
5682 | acked = 1; |
5683 | } else { |
5684 | isp->isp_fphccmplt++; |
5685 | } |
5686 | #else |
5687 | isp_prt(isp, ISP_LOGWARN, "unexpected ASYNC CTIO done" ); |
5688 | #endif |
5689 | break; |
5690 | case ASYNC_LIP_ERROR: |
5691 | case ASYNC_LIP_F8: |
5692 | case ASYNC_LIP_OCCURRED: |
5693 | case ASYNC_PTPMODE: |
5694 | /* |
5695 | * These are broadcast events that have to be sent across |
5696 | * all active channels. |
5697 | */ |
5698 | for (chan = 0; chan < isp->isp_nchan; chan++) { |
5699 | fcparam *fcp = FCPARAM(isp, chan); |
5700 | int topo = fcp->isp_topo; |
5701 | |
5702 | if (fcp->role == ISP_ROLE_NONE) { |
5703 | continue; |
5704 | } |
5705 | |
5706 | fcp->isp_fwstate = FW_CONFIG_WAIT; |
5707 | fcp->isp_loopstate = LOOP_LIP_RCVD; |
5708 | ISP_SET_SENDMARKER(isp, chan, 1); |
5709 | ISP_MARK_PORTDB(isp, chan, 1); |
5710 | isp_async(isp, ISPASYNC_LIP, chan); |
5711 | #ifdef ISP_TARGET_MODE |
5712 | if (isp_target_async(isp, chan, mbox)) { |
5713 | acked = 1; |
5714 | } |
5715 | #endif |
5716 | /* |
5717 | * We've had problems with data corruption occuring on |
5718 | * commands that complete (with no apparent error) after |
5719 | * we receive a LIP. This has been observed mostly on |
5720 | * Local Loop topologies. To be safe, let's just mark |
5721 | * all active initiator commands as dead. |
5722 | */ |
5723 | if (topo == TOPO_NL_PORT || topo == TOPO_FL_PORT) { |
5724 | int i, j; |
5725 | for (i = j = 0; i < isp->isp_maxcmds; i++) { |
5726 | XS_T *xs; |
5727 | isp_hdl_t *hdp; |
5728 | |
5729 | hdp = &isp->isp_xflist[i]; |
5730 | if (ISP_H2HT(hdp->handle) != ISP_HANDLE_INITIATOR) { |
5731 | continue; |
5732 | } |
5733 | xs = hdp->cmd; |
5734 | if (XS_CHANNEL(xs) != chan) { |
5735 | continue; |
5736 | } |
5737 | j++; |
5738 | XS_SETERR(xs, HBA_BUSRESET); |
5739 | } |
5740 | if (j) { |
5741 | isp_prt(isp, ISP_LOGERR, lipd, chan, j); |
5742 | } |
5743 | } |
5744 | } |
5745 | break; |
5746 | |
5747 | case ASYNC_LOOP_UP: |
5748 | /* |
5749 | * This is a broadcast event that has to be sent across |
5750 | * all active channels. |
5751 | */ |
5752 | for (chan = 0; chan < isp->isp_nchan; chan++) { |
5753 | fcparam *fcp = FCPARAM(isp, chan); |
5754 | |
5755 | if (fcp->role == ISP_ROLE_NONE) { |
5756 | continue; |
5757 | } |
5758 | |
5759 | ISP_SET_SENDMARKER(isp, chan, 1); |
5760 | |
5761 | fcp->isp_fwstate = FW_CONFIG_WAIT; |
5762 | fcp->isp_loopstate = LOOP_LIP_RCVD; |
5763 | ISP_MARK_PORTDB(isp, chan, 1); |
5764 | isp_async(isp, ISPASYNC_LOOP_UP, chan); |
5765 | #ifdef ISP_TARGET_MODE |
5766 | if (isp_target_async(isp, chan, mbox)) { |
5767 | acked = 1; |
5768 | } |
5769 | #endif |
5770 | } |
5771 | break; |
5772 | |
5773 | case ASYNC_LOOP_DOWN: |
5774 | /* |
5775 | * This is a broadcast event that has to be sent across |
5776 | * all active channels. |
5777 | */ |
5778 | for (chan = 0; chan < isp->isp_nchan; chan++) { |
5779 | fcparam *fcp = FCPARAM(isp, chan); |
5780 | |
5781 | if (fcp->role == ISP_ROLE_NONE) { |
5782 | continue; |
5783 | } |
5784 | |
5785 | ISP_SET_SENDMARKER(isp, chan, 1); |
5786 | fcp->isp_fwstate = FW_CONFIG_WAIT; |
5787 | fcp->isp_loopstate = LOOP_NIL; |
5788 | ISP_MARK_PORTDB(isp, chan, 1); |
5789 | isp_async(isp, ISPASYNC_LOOP_DOWN, chan); |
5790 | #ifdef ISP_TARGET_MODE |
5791 | if (isp_target_async(isp, chan, mbox)) { |
5792 | acked = 1; |
5793 | } |
5794 | #endif |
5795 | } |
5796 | break; |
5797 | |
5798 | case ASYNC_LOOP_RESET: |
5799 | /* |
5800 | * This is a broadcast event that has to be sent across |
5801 | * all active channels. |
5802 | */ |
5803 | for (chan = 0; chan < isp->isp_nchan; chan++) { |
5804 | fcparam *fcp = FCPARAM(isp, chan); |
5805 | |
5806 | if (fcp->role == ISP_ROLE_NONE) { |
5807 | continue; |
5808 | } |
5809 | |
5810 | ISP_SET_SENDMARKER(isp, chan, 1); |
5811 | fcp->isp_fwstate = FW_CONFIG_WAIT; |
5812 | fcp->isp_loopstate = LOOP_NIL; |
5813 | ISP_MARK_PORTDB(isp, chan, 1); |
5814 | isp_async(isp, ISPASYNC_LOOP_RESET, chan); |
5815 | #ifdef ISP_TARGET_MODE |
5816 | if (isp_target_async(isp, chan, mbox)) { |
5817 | acked = 1; |
5818 | } |
5819 | #endif |
5820 | } |
5821 | break; |
5822 | |
5823 | case ASYNC_PDB_CHANGED: |
5824 | { |
5825 | int nphdl, nlstate, reason; |
5826 | /* |
5827 | * We *should* get a channel out of the 24XX, but we don't seem |
5828 | * to get more than a PDB CHANGED on channel 0, so turn it into |
5829 | * a broadcast event. |
5830 | */ |
5831 | if (IS_24XX(isp)) { |
5832 | nphdl = ISP_READ(isp, OUTMAILBOX1); |
5833 | nlstate = ISP_READ(isp, OUTMAILBOX2); |
5834 | reason = ISP_READ(isp, OUTMAILBOX3) >> 8; |
5835 | } else { |
5836 | nphdl = NIL_HANDLE; |
5837 | nlstate = reason = 0; |
5838 | } |
5839 | for (chan = 0; chan < isp->isp_nchan; chan++) { |
5840 | fcparam *fcp = FCPARAM(isp, chan); |
5841 | |
5842 | if (fcp->role == ISP_ROLE_NONE) { |
5843 | continue; |
5844 | } |
5845 | ISP_SET_SENDMARKER(isp, chan, 1); |
5846 | fcp->isp_loopstate = LOOP_PDB_RCVD; |
5847 | ISP_MARK_PORTDB(isp, chan, 1); |
5848 | isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, ISPASYNC_CHANGE_PDB, nphdl, nlstate, reason); |
5849 | } |
5850 | break; |
5851 | } |
5852 | case ASYNC_CHANGE_NOTIFY: |
5853 | { |
5854 | int lochan, hichan; |
5855 | |
5856 | if (ISP_FW_NEWER_THAN(isp, 4, 0, 25) && ISP_CAP_MULTI_ID(isp)) { |
5857 | GET_24XX_BUS(isp, chan, "ASYNC_CHANGE_NOTIFY" ); |
5858 | lochan = chan; |
5859 | hichan = chan + 1; |
5860 | } else { |
5861 | lochan = 0; |
5862 | hichan = isp->isp_nchan; |
5863 | } |
5864 | for (chan = lochan; chan < hichan; chan++) { |
5865 | fcparam *fcp = FCPARAM(isp, chan); |
5866 | |
5867 | if (fcp->role == ISP_ROLE_NONE) { |
5868 | continue; |
5869 | } |
5870 | |
5871 | if (fcp->isp_topo == TOPO_F_PORT) { |
5872 | fcp->isp_loopstate = LOOP_LSCAN_DONE; |
5873 | } else { |
5874 | fcp->isp_loopstate = LOOP_PDB_RCVD; |
5875 | } |
5876 | ISP_MARK_PORTDB(isp, chan, 1); |
5877 | isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, ISPASYNC_CHANGE_SNS); |
5878 | } |
5879 | break; |
5880 | } |
5881 | |
5882 | case ASYNC_CONNMODE: |
5883 | /* |
5884 | * This only applies to 2100 amd 2200 cards |
5885 | */ |
5886 | if (!IS_2200(isp) && !IS_2100(isp)) { |
5887 | isp_prt(isp, ISP_LOGWARN, "bad card for ASYNC_CONNMODE event" ); |
5888 | break; |
5889 | } |
5890 | chan = 0; |
5891 | mbox = ISP_READ(isp, OUTMAILBOX1); |
5892 | ISP_MARK_PORTDB(isp, chan, 1); |
5893 | switch (mbox) { |
5894 | case ISP_CONN_LOOP: |
5895 | isp_prt(isp, ISP_LOGINFO, |
5896 | "Point-to-Point -> Loop mode" ); |
5897 | break; |
5898 | case ISP_CONN_PTP: |
5899 | isp_prt(isp, ISP_LOGINFO, |
5900 | "Loop -> Point-to-Point mode" ); |
5901 | break; |
5902 | case ISP_CONN_BADLIP: |
5903 | isp_prt(isp, ISP_LOGWARN, |
5904 | "Point-to-Point -> Loop mode (BAD LIP)" ); |
5905 | break; |
5906 | case ISP_CONN_FATAL: |
5907 | isp->isp_dead = 1; |
5908 | isp->isp_state = ISP_CRASHED; |
5909 | isp_prt(isp, ISP_LOGERR, "FATAL CONNECTION ERROR" ); |
5910 | isp_async(isp, ISPASYNC_FW_CRASH); |
5911 | return (-1); |
5912 | case ISP_CONN_LOOPBACK: |
5913 | isp_prt(isp, ISP_LOGWARN, |
5914 | "Looped Back in Point-to-Point mode" ); |
5915 | break; |
5916 | default: |
5917 | isp_prt(isp, ISP_LOGWARN, |
5918 | "Unknown connection mode (0x%x)" , mbox); |
5919 | break; |
5920 | } |
5921 | isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, ISPASYNC_CHANGE_OTHER); |
5922 | FCPARAM(isp, chan)->sendmarker = 1; |
5923 | FCPARAM(isp, chan)->isp_fwstate = FW_CONFIG_WAIT; |
5924 | FCPARAM(isp, chan)->isp_loopstate = LOOP_LIP_RCVD; |
5925 | break; |
5926 | |
5927 | case ASYNC_RCV_ERR: |
5928 | if (IS_24XX(isp)) { |
5929 | isp_prt(isp, ISP_LOGWARN, "Receive Error" ); |
5930 | } else { |
5931 | isp_prt(isp, ISP_LOGWARN, "unexpected ASYNC_RCV_ERR" ); |
5932 | } |
5933 | break; |
5934 | case ASYNC_RJT_SENT: /* same as ASYNC_QFULL_SENT */ |
5935 | if (IS_24XX(isp)) { |
5936 | isp_prt(isp, ISP_LOGTDEBUG0, "LS_RJT sent" ); |
5937 | break; |
5938 | } else if (IS_2200(isp)) { |
5939 | isp_prt(isp, ISP_LOGTDEBUG0, "QFULL sent" ); |
5940 | break; |
5941 | } |
5942 | /* FALLTHROUGH */ |
5943 | default: |
5944 | isp_prt(isp, ISP_LOGWARN, "Unknown Async Code 0x%x" , mbox); |
5945 | break; |
5946 | } |
5947 | if (mbox != ASYNC_CTIO_DONE && mbox != ASYNC_CMD_CMPLT) { |
5948 | isp->isp_intoasync++; |
5949 | } |
5950 | return (acked); |
5951 | } |
5952 | |
5953 | /* |
5954 | * Handle other response entries. A pointer to the request queue output |
5955 | * index is here in case we want to eat several entries at once, although |
5956 | * this is not used currently. |
5957 | */ |
5958 | |
5959 | static int |
5960 | isp_handle_other_response(ispsoftc_t *isp, int type, isphdr_t *hp, uint32_t *optrp) |
5961 | { |
5962 | switch (type) { |
5963 | case RQSTYPE_STATUS_CONT: |
5964 | isp_prt(isp, ISP_LOGDEBUG0, "Ignored Continuation Response" ); |
5965 | return (1); |
5966 | case RQSTYPE_MARKER: |
5967 | isp_prt(isp, ISP_LOGDEBUG0, "Marker Response" ); |
5968 | return (1); |
5969 | case RQSTYPE_ATIO: |
5970 | case RQSTYPE_CTIO: |
5971 | case RQSTYPE_ENABLE_LUN: |
5972 | case RQSTYPE_MODIFY_LUN: |
5973 | case RQSTYPE_NOTIFY: |
5974 | case RQSTYPE_NOTIFY_ACK: |
5975 | case RQSTYPE_CTIO1: |
5976 | case RQSTYPE_ATIO2: |
5977 | case RQSTYPE_CTIO2: |
5978 | case RQSTYPE_CTIO3: |
5979 | case RQSTYPE_CTIO7: |
5980 | case RQSTYPE_ABTS_RCVD: |
5981 | case RQSTYPE_ABTS_RSP: |
5982 | isp->isp_rsltccmplt++; /* count as a response completion */ |
5983 | #ifdef ISP_TARGET_MODE |
5984 | if (isp_target_notify(isp, (ispstatusreq_t *) hp, optrp)) { |
5985 | return (1); |
5986 | } |
5987 | #endif |
5988 | /* FALLTHROUGH */ |
5989 | case RQSTYPE_RPT_ID_ACQ: |
5990 | if (IS_24XX(isp)) { |
5991 | isp_ridacq_t rid; |
5992 | isp_get_ridacq(isp, (isp_ridacq_t *)hp, &rid); |
5993 | if (rid.ridacq_format == 0) { |
5994 | } |
5995 | return (1); |
5996 | } |
5997 | /* FALLTHROUGH */ |
5998 | case RQSTYPE_REQUEST: |
5999 | default: |
6000 | ISP_DELAY(100); |
6001 | if (type != isp_get_response_type(isp, hp)) { |
6002 | /* |
6003 | * This is questionable- we're just papering over |
6004 | * something we've seen on SMP linux in target |
6005 | * mode- we don't really know what's happening |
6006 | * here that causes us to think we've gotten |
6007 | * an entry, but that either the entry isn't |
6008 | * filled out yet or our CPU read data is stale. |
6009 | */ |
6010 | isp_prt(isp, ISP_LOGINFO, |
6011 | "unstable type in response queue" ); |
6012 | return (-1); |
6013 | } |
6014 | isp_prt(isp, ISP_LOGWARN, "Unhandled Response Type 0x%x" , |
6015 | isp_get_response_type(isp, hp)); |
6016 | return (0); |
6017 | } |
6018 | } |
6019 | |
6020 | static void |
6021 | isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs, long *rp) |
6022 | { |
6023 | switch (sp->req_completion_status & 0xff) { |
6024 | case RQCS_COMPLETE: |
6025 | if (XS_NOERR(xs)) { |
6026 | XS_SETERR(xs, HBA_NOERROR); |
6027 | } |
6028 | return; |
6029 | |
6030 | case RQCS_INCOMPLETE: |
6031 | if ((sp->req_state_flags & RQSF_GOT_TARGET) == 0) { |
6032 | isp_xs_prt(isp, xs, ISP_LOGDEBUG1, "Selection Timeout" ); |
6033 | if (XS_NOERR(xs)) { |
6034 | XS_SETERR(xs, HBA_SELTIMEOUT); |
6035 | *rp = XS_XFRLEN(xs); |
6036 | } |
6037 | return; |
6038 | } |
6039 | isp_xs_prt(isp, xs, ISP_LOGERR, "Command Incomplete, state 0x%x" , sp->req_state_flags); |
6040 | break; |
6041 | |
6042 | case RQCS_DMA_ERROR: |
6043 | isp_xs_prt(isp, xs, ISP_LOGERR, "DMA Error" ); |
6044 | *rp = XS_XFRLEN(xs); |
6045 | break; |
6046 | |
6047 | case RQCS_TRANSPORT_ERROR: |
6048 | { |
6049 | char buf[172]; |
6050 | ISP_SNPRINTF(buf, sizeof (buf), "states=>" ); |
6051 | if (sp->req_state_flags & RQSF_GOT_BUS) { |
6052 | ISP_SNPRINTF(buf, sizeof (buf), "%s GOT_BUS" , buf); |
6053 | } |
6054 | if (sp->req_state_flags & RQSF_GOT_TARGET) { |
6055 | ISP_SNPRINTF(buf, sizeof (buf), "%s GOT_TGT" , buf); |
6056 | } |
6057 | if (sp->req_state_flags & RQSF_SENT_CDB) { |
6058 | ISP_SNPRINTF(buf, sizeof (buf), "%s SENT_CDB" , buf); |
6059 | } |
6060 | if (sp->req_state_flags & RQSF_XFRD_DATA) { |
6061 | ISP_SNPRINTF(buf, sizeof (buf), "%s XFRD_DATA" , buf); |
6062 | } |
6063 | if (sp->req_state_flags & RQSF_GOT_STATUS) { |
6064 | ISP_SNPRINTF(buf, sizeof (buf), "%s GOT_STS" , buf); |
6065 | } |
6066 | if (sp->req_state_flags & RQSF_GOT_SENSE) { |
6067 | ISP_SNPRINTF(buf, sizeof (buf), "%s GOT_SNS" , buf); |
6068 | } |
6069 | if (sp->req_state_flags & RQSF_XFER_COMPLETE) { |
6070 | ISP_SNPRINTF(buf, sizeof (buf), "%s XFR_CMPLT" , buf); |
6071 | } |
6072 | ISP_SNPRINTF(buf, sizeof (buf), "%s\nstatus=>" , buf); |
6073 | if (sp->req_status_flags & RQSTF_DISCONNECT) { |
6074 | ISP_SNPRINTF(buf, sizeof (buf), "%s Disconnect" , buf); |
6075 | } |
6076 | if (sp->req_status_flags & RQSTF_SYNCHRONOUS) { |
6077 | ISP_SNPRINTF(buf, sizeof (buf), "%s Sync_xfr" , buf); |
6078 | } |
6079 | if (sp->req_status_flags & RQSTF_PARITY_ERROR) { |
6080 | ISP_SNPRINTF(buf, sizeof (buf), "%s Parity" , buf); |
6081 | } |
6082 | if (sp->req_status_flags & RQSTF_BUS_RESET) { |
6083 | ISP_SNPRINTF(buf, sizeof (buf), "%s Bus_Reset" , buf); |
6084 | } |
6085 | if (sp->req_status_flags & RQSTF_DEVICE_RESET) { |
6086 | ISP_SNPRINTF(buf, sizeof (buf), "%s Device_Reset" , buf); |
6087 | } |
6088 | if (sp->req_status_flags & RQSTF_ABORTED) { |
6089 | ISP_SNPRINTF(buf, sizeof (buf), "%s Aborted" , buf); |
6090 | } |
6091 | if (sp->req_status_flags & RQSTF_TIMEOUT) { |
6092 | ISP_SNPRINTF(buf, sizeof (buf), "%s Timeout" , buf); |
6093 | } |
6094 | if (sp->req_status_flags & RQSTF_NEGOTIATION) { |
6095 | ISP_SNPRINTF(buf, sizeof (buf), "%s Negotiation" , buf); |
6096 | } |
6097 | isp_xs_prt(isp, xs, ISP_LOGERR, "Transport Error: %s" , buf); |
6098 | *rp = XS_XFRLEN(xs); |
6099 | break; |
6100 | } |
6101 | case RQCS_RESET_OCCURRED: |
6102 | { |
6103 | int chan; |
6104 | isp_xs_prt(isp, xs, ISP_LOGWARN, "Bus Reset destroyed command" ); |
6105 | for (chan = 0; chan < isp->isp_nchan; chan++) { |
6106 | FCPARAM(isp, chan)->sendmarker = 1; |
6107 | } |
6108 | if (XS_NOERR(xs)) { |
6109 | XS_SETERR(xs, HBA_BUSRESET); |
6110 | } |
6111 | *rp = XS_XFRLEN(xs); |
6112 | return; |
6113 | } |
6114 | case RQCS_ABORTED: |
6115 | isp_xs_prt(isp, xs, ISP_LOGERR, "Command Aborted" ); |
6116 | ISP_SET_SENDMARKER(isp, XS_CHANNEL(xs), 1); |
6117 | if (XS_NOERR(xs)) { |
6118 | XS_SETERR(xs, HBA_ABORTED); |
6119 | } |
6120 | return; |
6121 | |
6122 | case RQCS_TIMEOUT: |
6123 | isp_xs_prt(isp, xs, ISP_LOGWARN, "Command timed out" ); |
6124 | /* |
6125 | * XXX: Check to see if we logged out of the device. |
6126 | */ |
6127 | if (XS_NOERR(xs)) { |
6128 | XS_SETERR(xs, HBA_CMDTIMEOUT); |
6129 | } |
6130 | return; |
6131 | |
6132 | case RQCS_DATA_OVERRUN: |
6133 | XS_SET_RESID(xs, sp->req_resid); |
6134 | isp_xs_prt(isp, xs, ISP_LOGERR, "data overrun (%ld)" , (long) XS_GET_RESID(xs)); |
6135 | if (XS_NOERR(xs)) { |
6136 | XS_SETERR(xs, HBA_DATAOVR); |
6137 | } |
6138 | return; |
6139 | |
6140 | case RQCS_COMMAND_OVERRUN: |
6141 | isp_xs_prt(isp, xs, ISP_LOGERR, "command overrun" ); |
6142 | break; |
6143 | |
6144 | case RQCS_STATUS_OVERRUN: |
6145 | isp_xs_prt(isp, xs, ISP_LOGERR, "status overrun" ); |
6146 | break; |
6147 | |
6148 | case RQCS_BAD_MESSAGE: |
6149 | isp_xs_prt(isp, xs, ISP_LOGERR, "msg not COMMAND COMPLETE after status" ); |
6150 | break; |
6151 | |
6152 | case RQCS_NO_MESSAGE_OUT: |
6153 | isp_xs_prt(isp, xs, ISP_LOGERR, "No MESSAGE OUT phase after selection" ); |
6154 | break; |
6155 | |
6156 | case RQCS_EXT_ID_FAILED: |
6157 | isp_xs_prt(isp, xs, ISP_LOGERR, "EXTENDED IDENTIFY failed" ); |
6158 | break; |
6159 | |
6160 | case RQCS_IDE_MSG_FAILED: |
6161 | isp_xs_prt(isp, xs, ISP_LOGERR, "INITIATOR DETECTED ERROR rejected" ); |
6162 | break; |
6163 | |
6164 | case RQCS_ABORT_MSG_FAILED: |
6165 | isp_xs_prt(isp, xs, ISP_LOGERR, "ABORT OPERATION rejected" ); |
6166 | break; |
6167 | |
6168 | case RQCS_REJECT_MSG_FAILED: |
6169 | isp_xs_prt(isp, xs, ISP_LOGERR, "MESSAGE REJECT rejected" ); |
6170 | break; |
6171 | |
6172 | case RQCS_NOP_MSG_FAILED: |
6173 | isp_xs_prt(isp, xs, ISP_LOGERR, "NOP rejected" ); |
6174 | break; |
6175 | |
6176 | case RQCS_PARITY_ERROR_MSG_FAILED: |
6177 | isp_xs_prt(isp, xs, ISP_LOGERR, "MESSAGE PARITY ERROR rejected" ); |
6178 | break; |
6179 | |
6180 | case RQCS_DEVICE_RESET_MSG_FAILED: |
6181 | isp_xs_prt(isp, xs, ISP_LOGWARN, "BUS DEVICE RESET rejected" ); |
6182 | break; |
6183 | |
6184 | case RQCS_ID_MSG_FAILED: |
6185 | isp_xs_prt(isp, xs, ISP_LOGERR, "IDENTIFY rejected" ); |
6186 | break; |
6187 | |
6188 | case RQCS_UNEXP_BUS_FREE: |
6189 | isp_xs_prt(isp, xs, ISP_LOGERR, "Unexpected Bus Free" ); |
6190 | break; |
6191 | |
6192 | case RQCS_DATA_UNDERRUN: |
6193 | { |
6194 | if (IS_FC(isp)) { |
6195 | int ru_marked = (sp->req_scsi_status & RQCS_RU) != 0; |
6196 | if (!ru_marked || sp->req_resid > XS_XFRLEN(xs)) { |
6197 | isp_xs_prt(isp, xs, ISP_LOGWARN, bun, XS_XFRLEN(xs), sp->req_resid, (ru_marked)? "marked" : "not marked" ); |
6198 | if (XS_NOERR(xs)) { |
6199 | XS_SETERR(xs, HBA_BOTCH); |
6200 | } |
6201 | return; |
6202 | } |
6203 | } |
6204 | XS_SET_RESID(xs, sp->req_resid); |
6205 | if (XS_NOERR(xs)) { |
6206 | XS_SETERR(xs, HBA_NOERROR); |
6207 | } |
6208 | return; |
6209 | } |
6210 | |
6211 | case RQCS_XACT_ERR1: |
6212 | isp_xs_prt(isp, xs, ISP_LOGERR, "HBA attempted queued transaction with disconnect not set" ); |
6213 | break; |
6214 | |
6215 | case RQCS_XACT_ERR2: |
6216 | isp_xs_prt(isp, xs, ISP_LOGERR, "HBA attempted queued transaction to target routine %d" , XS_LUN(xs)); |
6217 | break; |
6218 | |
6219 | case RQCS_XACT_ERR3: |
6220 | isp_xs_prt(isp, xs, ISP_LOGERR, "HBA attempted queued cmd when queueing disabled" ); |
6221 | break; |
6222 | |
6223 | case RQCS_BAD_ENTRY: |
6224 | isp_prt(isp, ISP_LOGERR, "Invalid IOCB entry type detected" ); |
6225 | break; |
6226 | |
6227 | case RQCS_QUEUE_FULL: |
6228 | isp_xs_prt(isp, xs, ISP_LOGDEBUG0, "internal queues full status 0x%x" , *XS_STSP(xs)); |
6229 | |
6230 | /* |
6231 | * If QFULL or some other status byte is set, then this |
6232 | * isn't an error, per se. |
6233 | * |
6234 | * Unfortunately, some QLogic f/w writers have, in |
6235 | * some cases, ommitted to *set* status to QFULL. |
6236 | * |
6237 | |
6238 | if (*XS_STSP(xs) != SCSI_GOOD && XS_NOERR(xs)) { |
6239 | XS_SETERR(xs, HBA_NOERROR); |
6240 | return; |
6241 | } |
6242 | |
6243 | * |
6244 | * |
6245 | */ |
6246 | |
6247 | *XS_STSP(xs) = SCSI_QFULL; |
6248 | XS_SETERR(xs, HBA_NOERROR); |
6249 | return; |
6250 | |
6251 | case RQCS_PHASE_SKIPPED: |
6252 | isp_xs_prt(isp, xs, ISP_LOGERR, "SCSI phase skipped" ); |
6253 | break; |
6254 | |
6255 | case RQCS_ARQS_FAILED: |
6256 | isp_xs_prt(isp, xs, ISP_LOGERR, "Auto Request Sense Failed" ); |
6257 | if (XS_NOERR(xs)) { |
6258 | XS_SETERR(xs, HBA_ARQFAIL); |
6259 | } |
6260 | return; |
6261 | |
6262 | case RQCS_WIDE_FAILED: |
6263 | isp_xs_prt(isp, xs, ISP_LOGERR, "Wide Negotiation Failed" ); |
6264 | if (IS_SCSI(isp)) { |
6265 | sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); |
6266 | sdp->isp_devparam[XS_TGT(xs)].goal_flags &= ~DPARM_WIDE; |
6267 | sdp->isp_devparam[XS_TGT(xs)].dev_update = 1; |
6268 | sdp->update = 1; |
6269 | } |
6270 | if (XS_NOERR(xs)) { |
6271 | XS_SETERR(xs, HBA_NOERROR); |
6272 | } |
6273 | return; |
6274 | |
6275 | case RQCS_SYNCXFER_FAILED: |
6276 | isp_xs_prt(isp, xs, ISP_LOGERR, "SDTR Message Failed" ); |
6277 | if (IS_SCSI(isp)) { |
6278 | sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); |
6279 | sdp += XS_CHANNEL(xs); |
6280 | sdp->isp_devparam[XS_TGT(xs)].goal_flags &= ~DPARM_SYNC; |
6281 | sdp->isp_devparam[XS_TGT(xs)].dev_update = 1; |
6282 | sdp->update = 1; |
6283 | } |
6284 | break; |
6285 | |
6286 | case RQCS_LVD_BUSERR: |
6287 | isp_xs_prt(isp, xs, ISP_LOGERR, "Bad LVD condition" ); |
6288 | break; |
6289 | |
6290 | case RQCS_PORT_UNAVAILABLE: |
6291 | /* |
6292 | * No such port on the loop. Moral equivalent of SELTIMEO |
6293 | */ |
6294 | case RQCS_PORT_LOGGED_OUT: |
6295 | { |
6296 | const char *reason; |
6297 | uint8_t sts = sp->req_completion_status & 0xff; |
6298 | |
6299 | /* |
6300 | * It was there (maybe)- treat as a selection timeout. |
6301 | */ |
6302 | if (sts == RQCS_PORT_UNAVAILABLE) { |
6303 | reason = "unavailable" ; |
6304 | } else { |
6305 | reason = "logout" ; |
6306 | } |
6307 | |
6308 | isp_prt(isp, ISP_LOGINFO, "port %s for target %d" , |
6309 | reason, XS_TGT(xs)); |
6310 | |
6311 | /* |
6312 | * If we're on a local loop, force a LIP (which is overkill) |
6313 | * to force a re-login of this unit. If we're on fabric, |
6314 | * then we'll have to log in again as a matter of course. |
6315 | */ |
6316 | if (FCPARAM(isp, 0)->isp_topo == TOPO_NL_PORT || |
6317 | FCPARAM(isp, 0)->isp_topo == TOPO_FL_PORT) { |
6318 | mbreg_t mbs; |
6319 | MBSINIT(&mbs, MBOX_INIT_LIP, MBLOGALL, 0); |
6320 | if (ISP_CAP_2KLOGIN(isp)) { |
6321 | mbs.ibits = (1 << 10); |
6322 | } |
6323 | isp_mboxcmd_qnw(isp, &mbs, 1); |
6324 | } |
6325 | if (XS_NOERR(xs)) { |
6326 | XS_SETERR(xs, HBA_SELTIMEOUT); |
6327 | } |
6328 | return; |
6329 | } |
6330 | case RQCS_PORT_CHANGED: |
6331 | isp_prt(isp, ISP_LOGWARN, |
6332 | "port changed for target %d" , XS_TGT(xs)); |
6333 | if (XS_NOERR(xs)) { |
6334 | XS_SETERR(xs, HBA_SELTIMEOUT); |
6335 | } |
6336 | return; |
6337 | |
6338 | case RQCS_PORT_BUSY: |
6339 | isp_prt(isp, ISP_LOGWARN, |
6340 | "port busy for target %d" , XS_TGT(xs)); |
6341 | if (XS_NOERR(xs)) { |
6342 | XS_SETERR(xs, HBA_TGTBSY); |
6343 | } |
6344 | return; |
6345 | |
6346 | default: |
6347 | isp_prt(isp, ISP_LOGERR, "Unknown Completion Status 0x%x" , |
6348 | sp->req_completion_status); |
6349 | break; |
6350 | } |
6351 | if (XS_NOERR(xs)) { |
6352 | XS_SETERR(xs, HBA_BOTCH); |
6353 | } |
6354 | } |
6355 | |
6356 | static void |
6357 | isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, XS_T *xs, long *rp) |
6358 | { |
6359 | int ru_marked, sv_marked; |
6360 | int chan = XS_CHANNEL(xs); |
6361 | |
6362 | switch (sp->req_completion_status) { |
6363 | case RQCS_COMPLETE: |
6364 | if (XS_NOERR(xs)) { |
6365 | XS_SETERR(xs, HBA_NOERROR); |
6366 | } |
6367 | return; |
6368 | |
6369 | case RQCS_DMA_ERROR: |
6370 | isp_xs_prt(isp, xs, ISP_LOGERR, "DMA error" ); |
6371 | break; |
6372 | |
6373 | case RQCS_TRANSPORT_ERROR: |
6374 | isp_xs_prt(isp, xs, ISP_LOGERR, "Transport Error" ); |
6375 | break; |
6376 | |
6377 | case RQCS_RESET_OCCURRED: |
6378 | isp_xs_prt(isp, xs, ISP_LOGWARN, "reset destroyed command" ); |
6379 | FCPARAM(isp, chan)->sendmarker = 1; |
6380 | if (XS_NOERR(xs)) { |
6381 | XS_SETERR(xs, HBA_BUSRESET); |
6382 | } |
6383 | return; |
6384 | |
6385 | case RQCS_ABORTED: |
6386 | isp_xs_prt(isp, xs, ISP_LOGERR, "Command Aborted" ); |
6387 | FCPARAM(isp, chan)->sendmarker = 1; |
6388 | if (XS_NOERR(xs)) { |
6389 | XS_SETERR(xs, HBA_ABORTED); |
6390 | } |
6391 | return; |
6392 | |
6393 | case RQCS_TIMEOUT: |
6394 | isp_xs_prt(isp, xs, ISP_LOGWARN, "Command Timed Out" ); |
6395 | if (XS_NOERR(xs)) { |
6396 | XS_SETERR(xs, HBA_CMDTIMEOUT); |
6397 | } |
6398 | return; |
6399 | |
6400 | case RQCS_DATA_OVERRUN: |
6401 | XS_SET_RESID(xs, sp->req_resid); |
6402 | isp_xs_prt(isp, xs, ISP_LOGERR, "Data Overrun" ); |
6403 | if (XS_NOERR(xs)) { |
6404 | XS_SETERR(xs, HBA_DATAOVR); |
6405 | } |
6406 | return; |
6407 | |
6408 | case RQCS_24XX_DRE: /* data reassembly error */ |
6409 | isp_prt(isp, ISP_LOGERR, |
6410 | "Chan %d data reassembly error for target %d" , |
6411 | chan, XS_TGT(xs)); |
6412 | if (XS_NOERR(xs)) { |
6413 | XS_SETERR(xs, HBA_ABORTED); |
6414 | } |
6415 | *rp = XS_XFRLEN(xs); |
6416 | return; |
6417 | |
6418 | case RQCS_24XX_TABORT: /* aborted by target */ |
6419 | isp_prt(isp, ISP_LOGERR, "Chan %d target %d sent ABTS" , |
6420 | chan, XS_TGT(xs)); |
6421 | if (XS_NOERR(xs)) { |
6422 | XS_SETERR(xs, HBA_ABORTED); |
6423 | } |
6424 | return; |
6425 | |
6426 | case RQCS_DATA_UNDERRUN: |
6427 | ru_marked = (sp->req_scsi_status & RQCS_RU) != 0; |
6428 | /* |
6429 | * We can get an underrun w/o things being marked |
6430 | * if we got a non-zero status. |
6431 | */ |
6432 | sv_marked = (sp->req_scsi_status & (RQCS_SV|RQCS_RV)) != 0; |
6433 | if ((ru_marked == 0 && sv_marked == 0) || |
6434 | (sp->req_resid > XS_XFRLEN(xs))) { |
6435 | isp_xs_prt(isp, xs, ISP_LOGWARN, bun, XS_XFRLEN(xs), sp->req_resid, (ru_marked)? "marked" : "not marked" ); |
6436 | if (XS_NOERR(xs)) { |
6437 | XS_SETERR(xs, HBA_BOTCH); |
6438 | } |
6439 | return; |
6440 | } |
6441 | XS_SET_RESID(xs, sp->req_resid); |
6442 | isp_xs_prt(isp, xs, ISP_LOGDEBUG0, "Data Underrun (%d) for command 0x%x" , sp->req_resid, XS_CDBP(xs)[0] & 0xff); |
6443 | if (XS_NOERR(xs)) { |
6444 | XS_SETERR(xs, HBA_NOERROR); |
6445 | } |
6446 | return; |
6447 | |
6448 | case RQCS_PORT_UNAVAILABLE: |
6449 | /* |
6450 | * No such port on the loop. Moral equivalent of SELTIMEO |
6451 | */ |
6452 | case RQCS_PORT_LOGGED_OUT: |
6453 | { |
6454 | const char *reason; |
6455 | uint8_t sts = sp->req_completion_status & 0xff; |
6456 | |
6457 | /* |
6458 | * It was there (maybe)- treat as a selection timeout. |
6459 | */ |
6460 | if (sts == RQCS_PORT_UNAVAILABLE) { |
6461 | reason = "unavailable" ; |
6462 | } else { |
6463 | reason = "logout" ; |
6464 | } |
6465 | |
6466 | isp_prt(isp, ISP_LOGINFO, "Chan %d port %s for target %d" , |
6467 | chan, reason, XS_TGT(xs)); |
6468 | |
6469 | /* |
6470 | * There is no MBOX_INIT_LIP for the 24XX. |
6471 | */ |
6472 | if (XS_NOERR(xs)) { |
6473 | XS_SETERR(xs, HBA_SELTIMEOUT); |
6474 | } |
6475 | return; |
6476 | } |
6477 | case RQCS_PORT_CHANGED: |
6478 | isp_prt(isp, ISP_LOGWARN, |
6479 | "port changed for target %d chan %d" , XS_TGT(xs), chan); |
6480 | if (XS_NOERR(xs)) { |
6481 | XS_SETERR(xs, HBA_SELTIMEOUT); |
6482 | } |
6483 | return; |
6484 | |
6485 | |
6486 | case RQCS_24XX_ENOMEM: /* f/w resource unavailable */ |
6487 | isp_prt(isp, ISP_LOGWARN, |
6488 | "f/w resource unavailable for target %d chan %d" , |
6489 | XS_TGT(xs), chan); |
6490 | if (XS_NOERR(xs)) { |
6491 | *XS_STSP(xs) = SCSI_BUSY; |
6492 | XS_SETERR(xs, HBA_TGTBSY); |
6493 | } |
6494 | return; |
6495 | |
6496 | case RQCS_24XX_TMO: /* task management overrun */ |
6497 | isp_prt(isp, ISP_LOGWARN, |
6498 | "command for target %d overlapped task management for " |
6499 | "chan %d" , XS_TGT(xs), chan); |
6500 | if (XS_NOERR(xs)) { |
6501 | *XS_STSP(xs) = SCSI_BUSY; |
6502 | XS_SETERR(xs, HBA_TGTBSY); |
6503 | } |
6504 | return; |
6505 | |
6506 | default: |
6507 | isp_prt(isp, ISP_LOGERR, |
6508 | "Unknown Completion Status 0x%x on chan %d" , |
6509 | sp->req_completion_status, chan); |
6510 | break; |
6511 | } |
6512 | if (XS_NOERR(xs)) { |
6513 | XS_SETERR(xs, HBA_BOTCH); |
6514 | } |
6515 | } |
6516 | |
6517 | static void |
6518 | isp_fastpost_complete(ispsoftc_t *isp, uint32_t fph) |
6519 | { |
6520 | XS_T *xs; |
6521 | |
6522 | if (fph == 0) { |
6523 | return; |
6524 | } |
6525 | xs = isp_find_xs(isp, fph); |
6526 | if (xs == NULL) { |
6527 | isp_prt(isp, ISP_LOGWARN, |
6528 | "Command for fast post handle 0x%x not found" , fph); |
6529 | return; |
6530 | } |
6531 | isp_destroy_handle(isp, fph); |
6532 | |
6533 | /* |
6534 | * Since we don't have a result queue entry item, |
6535 | * we must believe that SCSI status is zero and |
6536 | * that all data transferred. |
6537 | */ |
6538 | XS_SET_RESID(xs, 0); |
6539 | *XS_STSP(xs) = SCSI_GOOD; |
6540 | if (XS_XFRLEN(xs)) { |
6541 | ISP_DMAFREE(isp, xs, fph); |
6542 | } |
6543 | if (isp->isp_nactive) { |
6544 | isp->isp_nactive--; |
6545 | } |
6546 | isp->isp_fphccmplt++; |
6547 | isp_done(xs); |
6548 | } |
6549 | |
6550 | static int |
6551 | isp_mbox_continue(ispsoftc_t *isp) |
6552 | { |
6553 | mbreg_t mbs; |
6554 | uint16_t *ptr; |
6555 | uint32_t offset; |
6556 | |
6557 | switch (isp->isp_lastmbxcmd) { |
6558 | case MBOX_WRITE_RAM_WORD: |
6559 | case MBOX_READ_RAM_WORD: |
6560 | case MBOX_WRITE_RAM_WORD_EXTENDED: |
6561 | case MBOX_READ_RAM_WORD_EXTENDED: |
6562 | break; |
6563 | default: |
6564 | return (1); |
6565 | } |
6566 | if (isp->isp_mboxtmp[0] != MBOX_COMMAND_COMPLETE) { |
6567 | isp->isp_mbxwrk0 = 0; |
6568 | return (-1); |
6569 | } |
6570 | |
6571 | /* |
6572 | * Clear the previous interrupt. |
6573 | */ |
6574 | if (IS_24XX(isp)) { |
6575 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT); |
6576 | } else { |
6577 | ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); |
6578 | ISP_WRITE(isp, BIU_SEMA, 0); |
6579 | } |
6580 | |
6581 | /* |
6582 | * Continue with next word. |
6583 | */ |
6584 | ISP_MEMZERO(&mbs, sizeof (mbs)); |
6585 | ptr = isp->isp_mbxworkp; |
6586 | switch (isp->isp_lastmbxcmd) { |
6587 | case MBOX_WRITE_RAM_WORD: |
6588 | mbs.param[1] = isp->isp_mbxwrk1++; |
6589 | mbs.param[2] = *ptr++; |
6590 | break; |
6591 | case MBOX_READ_RAM_WORD: |
6592 | *ptr++ = isp->isp_mboxtmp[2]; |
6593 | mbs.param[1] = isp->isp_mbxwrk1++; |
6594 | break; |
6595 | case MBOX_WRITE_RAM_WORD_EXTENDED: |
6596 | offset = isp->isp_mbxwrk1; |
6597 | offset |= isp->isp_mbxwrk8 << 16; |
6598 | |
6599 | mbs.param[2] = *ptr++; |
6600 | mbs.param[1] = offset; |
6601 | mbs.param[8] = offset >> 16; |
6602 | isp->isp_mbxwrk1 = ++offset; |
6603 | isp->isp_mbxwrk8 = offset >> 16; |
6604 | break; |
6605 | case MBOX_READ_RAM_WORD_EXTENDED: |
6606 | offset = isp->isp_mbxwrk1; |
6607 | offset |= isp->isp_mbxwrk8 << 16; |
6608 | |
6609 | *ptr++ = isp->isp_mboxtmp[2]; |
6610 | mbs.param[1] = offset; |
6611 | mbs.param[8] = offset >> 16; |
6612 | isp->isp_mbxwrk1 = ++offset; |
6613 | isp->isp_mbxwrk8 = offset >> 16; |
6614 | break; |
6615 | } |
6616 | isp->isp_mbxworkp = ptr; |
6617 | isp->isp_mbxwrk0--; |
6618 | mbs.param[0] = isp->isp_lastmbxcmd; |
6619 | mbs.logval = MBLOGALL; |
6620 | isp_mboxcmd_qnw(isp, &mbs, 0); |
6621 | return (0); |
6622 | } |
6623 | |
6624 | #define HIWRD(x) ((x) >> 16) |
6625 | #define LOWRD(x) ((x) & 0xffff) |
6626 | #define ISPOPMAP(a, b) (((a) << 16) | (b)) |
6627 | static const uint32_t mbpscsi[] = { |
6628 | ISPOPMAP(0x01, 0x01), /* 0x00: MBOX_NO_OP */ |
6629 | ISPOPMAP(0x1f, 0x01), /* 0x01: MBOX_LOAD_RAM */ |
6630 | ISPOPMAP(0x03, 0x01), /* 0x02: MBOX_EXEC_FIRMWARE */ |
6631 | ISPOPMAP(0x1f, 0x01), /* 0x03: MBOX_DUMP_RAM */ |
6632 | ISPOPMAP(0x07, 0x07), /* 0x04: MBOX_WRITE_RAM_WORD */ |
6633 | ISPOPMAP(0x03, 0x07), /* 0x05: MBOX_READ_RAM_WORD */ |
6634 | ISPOPMAP(0x3f, 0x3f), /* 0x06: MBOX_MAILBOX_REG_TEST */ |
6635 | ISPOPMAP(0x07, 0x07), /* 0x07: MBOX_VERIFY_CHECKSUM */ |
6636 | ISPOPMAP(0x01, 0x0f), /* 0x08: MBOX_ABOUT_FIRMWARE */ |
6637 | ISPOPMAP(0x00, 0x00), /* 0x09: */ |
6638 | ISPOPMAP(0x00, 0x00), /* 0x0a: */ |
6639 | ISPOPMAP(0x00, 0x00), /* 0x0b: */ |
6640 | ISPOPMAP(0x00, 0x00), /* 0x0c: */ |
6641 | ISPOPMAP(0x00, 0x00), /* 0x0d: */ |
6642 | ISPOPMAP(0x01, 0x05), /* 0x0e: MBOX_CHECK_FIRMWARE */ |
6643 | ISPOPMAP(0x00, 0x00), /* 0x0f: */ |
6644 | ISPOPMAP(0x1f, 0x1f), /* 0x10: MBOX_INIT_REQ_QUEUE */ |
6645 | ISPOPMAP(0x3f, 0x3f), /* 0x11: MBOX_INIT_RES_QUEUE */ |
6646 | ISPOPMAP(0x0f, 0x0f), /* 0x12: MBOX_EXECUTE_IOCB */ |
6647 | ISPOPMAP(0x03, 0x03), /* 0x13: MBOX_WAKE_UP */ |
6648 | ISPOPMAP(0x01, 0x3f), /* 0x14: MBOX_STOP_FIRMWARE */ |
6649 | ISPOPMAP(0x0f, 0x0f), /* 0x15: MBOX_ABORT */ |
6650 | ISPOPMAP(0x03, 0x03), /* 0x16: MBOX_ABORT_DEVICE */ |
6651 | ISPOPMAP(0x07, 0x07), /* 0x17: MBOX_ABORT_TARGET */ |
6652 | ISPOPMAP(0x07, 0x07), /* 0x18: MBOX_BUS_RESET */ |
6653 | ISPOPMAP(0x03, 0x07), /* 0x19: MBOX_STOP_QUEUE */ |
6654 | ISPOPMAP(0x03, 0x07), /* 0x1a: MBOX_START_QUEUE */ |
6655 | ISPOPMAP(0x03, 0x07), /* 0x1b: MBOX_SINGLE_STEP_QUEUE */ |
6656 | ISPOPMAP(0x03, 0x07), /* 0x1c: MBOX_ABORT_QUEUE */ |
6657 | ISPOPMAP(0x03, 0x4f), /* 0x1d: MBOX_GET_DEV_QUEUE_STATUS */ |
6658 | ISPOPMAP(0x00, 0x00), /* 0x1e: */ |
6659 | ISPOPMAP(0x01, 0x07), /* 0x1f: MBOX_GET_FIRMWARE_STATUS */ |
6660 | ISPOPMAP(0x01, 0x07), /* 0x20: MBOX_GET_INIT_SCSI_ID */ |
6661 | ISPOPMAP(0x01, 0x07), /* 0x21: MBOX_GET_SELECT_TIMEOUT */ |
6662 | ISPOPMAP(0x01, 0xc7), /* 0x22: MBOX_GET_RETRY_COUNT */ |
6663 | ISPOPMAP(0x01, 0x07), /* 0x23: MBOX_GET_TAG_AGE_LIMIT */ |
6664 | ISPOPMAP(0x01, 0x03), /* 0x24: MBOX_GET_CLOCK_RATE */ |
6665 | ISPOPMAP(0x01, 0x07), /* 0x25: MBOX_GET_ACT_NEG_STATE */ |
6666 | ISPOPMAP(0x01, 0x07), /* 0x26: MBOX_GET_ASYNC_DATA_SETUP_TIME */ |
6667 | ISPOPMAP(0x01, 0x07), /* 0x27: MBOX_GET_PCI_PARAMS */ |
6668 | ISPOPMAP(0x03, 0x4f), /* 0x28: MBOX_GET_TARGET_PARAMS */ |
6669 | ISPOPMAP(0x03, 0x0f), /* 0x29: MBOX_GET_DEV_QUEUE_PARAMS */ |
6670 | ISPOPMAP(0x01, 0x07), /* 0x2a: MBOX_GET_RESET_DELAY_PARAMS */ |
6671 | ISPOPMAP(0x00, 0x00), /* 0x2b: */ |
6672 | ISPOPMAP(0x00, 0x00), /* 0x2c: */ |
6673 | ISPOPMAP(0x00, 0x00), /* 0x2d: */ |
6674 | ISPOPMAP(0x00, 0x00), /* 0x2e: */ |
6675 | ISPOPMAP(0x00, 0x00), /* 0x2f: */ |
6676 | ISPOPMAP(0x03, 0x03), /* 0x30: MBOX_SET_INIT_SCSI_ID */ |
6677 | ISPOPMAP(0x07, 0x07), /* 0x31: MBOX_SET_SELECT_TIMEOUT */ |
6678 | ISPOPMAP(0xc7, 0xc7), /* 0x32: MBOX_SET_RETRY_COUNT */ |
6679 | ISPOPMAP(0x07, 0x07), /* 0x33: MBOX_SET_TAG_AGE_LIMIT */ |
6680 | ISPOPMAP(0x03, 0x03), /* 0x34: MBOX_SET_CLOCK_RATE */ |
6681 | ISPOPMAP(0x07, 0x07), /* 0x35: MBOX_SET_ACT_NEG_STATE */ |
6682 | ISPOPMAP(0x07, 0x07), /* 0x36: MBOX_SET_ASYNC_DATA_SETUP_TIME */ |
6683 | ISPOPMAP(0x07, 0x07), /* 0x37: MBOX_SET_PCI_CONTROL_PARAMS */ |
6684 | ISPOPMAP(0x4f, 0x4f), /* 0x38: MBOX_SET_TARGET_PARAMS */ |
6685 | ISPOPMAP(0x0f, 0x0f), /* 0x39: MBOX_SET_DEV_QUEUE_PARAMS */ |
6686 | ISPOPMAP(0x07, 0x07), /* 0x3a: MBOX_SET_RESET_DELAY_PARAMS */ |
6687 | ISPOPMAP(0x00, 0x00), /* 0x3b: */ |
6688 | ISPOPMAP(0x00, 0x00), /* 0x3c: */ |
6689 | ISPOPMAP(0x00, 0x00), /* 0x3d: */ |
6690 | ISPOPMAP(0x00, 0x00), /* 0x3e: */ |
6691 | ISPOPMAP(0x00, 0x00), /* 0x3f: */ |
6692 | ISPOPMAP(0x01, 0x03), /* 0x40: MBOX_RETURN_BIOS_BLOCK_ADDR */ |
6693 | ISPOPMAP(0x3f, 0x01), /* 0x41: MBOX_WRITE_FOUR_RAM_WORDS */ |
6694 | ISPOPMAP(0x03, 0x07), /* 0x42: MBOX_EXEC_BIOS_IOCB */ |
6695 | ISPOPMAP(0x00, 0x00), /* 0x43: */ |
6696 | ISPOPMAP(0x00, 0x00), /* 0x44: */ |
6697 | ISPOPMAP(0x03, 0x03), /* 0x45: SET SYSTEM PARAMETER */ |
6698 | ISPOPMAP(0x01, 0x03), /* 0x46: GET SYSTEM PARAMETER */ |
6699 | ISPOPMAP(0x00, 0x00), /* 0x47: */ |
6700 | ISPOPMAP(0x01, 0xcf), /* 0x48: GET SCAM CONFIGURATION */ |
6701 | ISPOPMAP(0xcf, 0xcf), /* 0x49: SET SCAM CONFIGURATION */ |
6702 | ISPOPMAP(0x03, 0x03), /* 0x4a: MBOX_SET_FIRMWARE_FEATURES */ |
6703 | ISPOPMAP(0x01, 0x03), /* 0x4b: MBOX_GET_FIRMWARE_FEATURES */ |
6704 | ISPOPMAP(0x00, 0x00), /* 0x4c: */ |
6705 | ISPOPMAP(0x00, 0x00), /* 0x4d: */ |
6706 | ISPOPMAP(0x00, 0x00), /* 0x4e: */ |
6707 | ISPOPMAP(0x00, 0x00), /* 0x4f: */ |
6708 | ISPOPMAP(0xdf, 0xdf), /* 0x50: LOAD RAM A64 */ |
6709 | ISPOPMAP(0xdf, 0xdf), /* 0x51: DUMP RAM A64 */ |
6710 | ISPOPMAP(0xdf, 0xff), /* 0x52: INITIALIZE REQUEST QUEUE A64 */ |
6711 | ISPOPMAP(0xef, 0xff), /* 0x53: INITIALIZE RESPONSE QUEUE A64 */ |
6712 | ISPOPMAP(0xcf, 0x01), /* 0x54: EXECUCUTE COMMAND IOCB A64 */ |
6713 | ISPOPMAP(0x07, 0x01), /* 0x55: ENABLE TARGET MODE */ |
6714 | ISPOPMAP(0x03, 0x0f), /* 0x56: GET TARGET STATUS */ |
6715 | ISPOPMAP(0x00, 0x00), /* 0x57: */ |
6716 | ISPOPMAP(0x00, 0x00), /* 0x58: */ |
6717 | ISPOPMAP(0x00, 0x00), /* 0x59: */ |
6718 | ISPOPMAP(0x03, 0x03), /* 0x5a: SET DATA OVERRUN RECOVERY MODE */ |
6719 | ISPOPMAP(0x01, 0x03), /* 0x5b: GET DATA OVERRUN RECOVERY MODE */ |
6720 | ISPOPMAP(0x0f, 0x0f), /* 0x5c: SET HOST DATA */ |
6721 | ISPOPMAP(0x01, 0x01) /* 0x5d: GET NOST DATA */ |
6722 | }; |
6723 | |
6724 | static const char *scsi_mbcmd_names[] = { |
6725 | "NO-OP" , |
6726 | "LOAD RAM" , |
6727 | "EXEC FIRMWARE" , |
6728 | "DUMP RAM" , |
6729 | "WRITE RAM WORD" , |
6730 | "READ RAM WORD" , |
6731 | "MAILBOX REG TEST" , |
6732 | "VERIFY CHECKSUM" , |
6733 | "ABOUT FIRMWARE" , |
6734 | NULL, |
6735 | NULL, |
6736 | NULL, |
6737 | NULL, |
6738 | NULL, |
6739 | "CHECK FIRMWARE" , |
6740 | NULL, |
6741 | "INIT REQUEST QUEUE" , |
6742 | "INIT RESULT QUEUE" , |
6743 | "EXECUTE IOCB" , |
6744 | "WAKE UP" , |
6745 | "STOP FIRMWARE" , |
6746 | "ABORT" , |
6747 | "ABORT DEVICE" , |
6748 | "ABORT TARGET" , |
6749 | "BUS RESET" , |
6750 | "STOP QUEUE" , |
6751 | "START QUEUE" , |
6752 | "SINGLE STEP QUEUE" , |
6753 | "ABORT QUEUE" , |
6754 | "GET DEV QUEUE STATUS" , |
6755 | NULL, |
6756 | "GET FIRMWARE STATUS" , |
6757 | "GET INIT SCSI ID" , |
6758 | "GET SELECT TIMEOUT" , |
6759 | "GET RETRY COUNT" , |
6760 | "GET TAG AGE LIMIT" , |
6761 | "GET CLOCK RATE" , |
6762 | "GET ACT NEG STATE" , |
6763 | "GET ASYNC DATA SETUP TIME" , |
6764 | "GET PCI PARAMS" , |
6765 | "GET TARGET PARAMS" , |
6766 | "GET DEV QUEUE PARAMS" , |
6767 | "GET RESET DELAY PARAMS" , |
6768 | NULL, |
6769 | NULL, |
6770 | NULL, |
6771 | NULL, |
6772 | NULL, |
6773 | "SET INIT SCSI ID" , |
6774 | "SET SELECT TIMEOUT" , |
6775 | "SET RETRY COUNT" , |
6776 | "SET TAG AGE LIMIT" , |
6777 | "SET CLOCK RATE" , |
6778 | "SET ACT NEG STATE" , |
6779 | "SET ASYNC DATA SETUP TIME" , |
6780 | "SET PCI CONTROL PARAMS" , |
6781 | "SET TARGET PARAMS" , |
6782 | "SET DEV QUEUE PARAMS" , |
6783 | "SET RESET DELAY PARAMS" , |
6784 | NULL, |
6785 | NULL, |
6786 | NULL, |
6787 | NULL, |
6788 | NULL, |
6789 | "RETURN BIOS BLOCK ADDR" , |
6790 | "WRITE FOUR RAM WORDS" , |
6791 | "EXEC BIOS IOCB" , |
6792 | NULL, |
6793 | NULL, |
6794 | "SET SYSTEM PARAMETER" , |
6795 | "GET SYSTEM PARAMETER" , |
6796 | NULL, |
6797 | "GET SCAM CONFIGURATION" , |
6798 | "SET SCAM CONFIGURATION" , |
6799 | "SET FIRMWARE FEATURES" , |
6800 | "GET FIRMWARE FEATURES" , |
6801 | NULL, |
6802 | NULL, |
6803 | NULL, |
6804 | NULL, |
6805 | "LOAD RAM A64" , |
6806 | "DUMP RAM A64" , |
6807 | "INITIALIZE REQUEST QUEUE A64" , |
6808 | "INITIALIZE RESPONSE QUEUE A64" , |
6809 | "EXECUTE IOCB A64" , |
6810 | "ENABLE TARGET MODE" , |
6811 | "GET TARGET MODE STATE" , |
6812 | NULL, |
6813 | NULL, |
6814 | NULL, |
6815 | "SET DATA OVERRUN RECOVERY MODE" , |
6816 | "GET DATA OVERRUN RECOVERY MODE" , |
6817 | "SET HOST DATA" , |
6818 | "GET NOST DATA" , |
6819 | }; |
6820 | |
6821 | static const uint32_t mbpfc[] = { |
6822 | ISPOPMAP(0x01, 0x01), /* 0x00: MBOX_NO_OP */ |
6823 | ISPOPMAP(0x1f, 0x01), /* 0x01: MBOX_LOAD_RAM */ |
6824 | ISPOPMAP(0x0f, 0x01), /* 0x02: MBOX_EXEC_FIRMWARE */ |
6825 | ISPOPMAP(0xdf, 0x01), /* 0x03: MBOX_DUMP_RAM */ |
6826 | ISPOPMAP(0x07, 0x07), /* 0x04: MBOX_WRITE_RAM_WORD */ |
6827 | ISPOPMAP(0x03, 0x07), /* 0x05: MBOX_READ_RAM_WORD */ |
6828 | ISPOPMAP(0xff, 0xff), /* 0x06: MBOX_MAILBOX_REG_TEST */ |
6829 | ISPOPMAP(0x07, 0x07), /* 0x07: MBOX_VERIFY_CHECKSUM */ |
6830 | ISPOPMAP(0x01, 0x4f), /* 0x08: MBOX_ABOUT_FIRMWARE */ |
6831 | ISPOPMAP(0xdf, 0x01), /* 0x09: MBOX_LOAD_RISC_RAM_2100 */ |
6832 | ISPOPMAP(0xdf, 0x01), /* 0x0a: DUMP RAM */ |
6833 | ISPOPMAP(0x1ff, 0x01), /* 0x0b: MBOX_LOAD_RISC_RAM */ |
6834 | ISPOPMAP(0x00, 0x00), /* 0x0c: */ |
6835 | ISPOPMAP(0x10f, 0x01), /* 0x0d: MBOX_WRITE_RAM_WORD_EXTENDED */ |
6836 | ISPOPMAP(0x01, 0x05), /* 0x0e: MBOX_CHECK_FIRMWARE */ |
6837 | ISPOPMAP(0x10f, 0x05), /* 0x0f: MBOX_READ_RAM_WORD_EXTENDED */ |
6838 | ISPOPMAP(0x1f, 0x11), /* 0x10: MBOX_INIT_REQ_QUEUE */ |
6839 | ISPOPMAP(0x2f, 0x21), /* 0x11: MBOX_INIT_RES_QUEUE */ |
6840 | ISPOPMAP(0x0f, 0x01), /* 0x12: MBOX_EXECUTE_IOCB */ |
6841 | ISPOPMAP(0x03, 0x03), /* 0x13: MBOX_WAKE_UP */ |
6842 | ISPOPMAP(0x01, 0xff), /* 0x14: MBOX_STOP_FIRMWARE */ |
6843 | ISPOPMAP(0x4f, 0x01), /* 0x15: MBOX_ABORT */ |
6844 | ISPOPMAP(0x07, 0x01), /* 0x16: MBOX_ABORT_DEVICE */ |
6845 | ISPOPMAP(0x07, 0x01), /* 0x17: MBOX_ABORT_TARGET */ |
6846 | ISPOPMAP(0x03, 0x03), /* 0x18: MBOX_BUS_RESET */ |
6847 | ISPOPMAP(0x07, 0x05), /* 0x19: MBOX_STOP_QUEUE */ |
6848 | ISPOPMAP(0x07, 0x05), /* 0x1a: MBOX_START_QUEUE */ |
6849 | ISPOPMAP(0x07, 0x05), /* 0x1b: MBOX_SINGLE_STEP_QUEUE */ |
6850 | ISPOPMAP(0x07, 0x05), /* 0x1c: MBOX_ABORT_QUEUE */ |
6851 | ISPOPMAP(0x07, 0x03), /* 0x1d: MBOX_GET_DEV_QUEUE_STATUS */ |
6852 | ISPOPMAP(0x00, 0x00), /* 0x1e: */ |
6853 | ISPOPMAP(0x01, 0x07), /* 0x1f: MBOX_GET_FIRMWARE_STATUS */ |
6854 | ISPOPMAP(0x01, 0x4f), /* 0x20: MBOX_GET_LOOP_ID */ |
6855 | ISPOPMAP(0x00, 0x00), /* 0x21: */ |
6856 | ISPOPMAP(0x01, 0x07), /* 0x22: MBOX_GET_RETRY_COUNT */ |
6857 | ISPOPMAP(0x00, 0x00), /* 0x23: */ |
6858 | ISPOPMAP(0x00, 0x00), /* 0x24: */ |
6859 | ISPOPMAP(0x00, 0x00), /* 0x25: */ |
6860 | ISPOPMAP(0x00, 0x00), /* 0x26: */ |
6861 | ISPOPMAP(0x00, 0x00), /* 0x27: */ |
6862 | ISPOPMAP(0x01, 0x03), /* 0x28: MBOX_GET_FIRMWARE_OPTIONS */ |
6863 | ISPOPMAP(0x03, 0x07), /* 0x29: MBOX_GET_PORT_QUEUE_PARAMS */ |
6864 | ISPOPMAP(0x00, 0x00), /* 0x2a: */ |
6865 | ISPOPMAP(0x00, 0x00), /* 0x2b: */ |
6866 | ISPOPMAP(0x00, 0x00), /* 0x2c: */ |
6867 | ISPOPMAP(0x00, 0x00), /* 0x2d: */ |
6868 | ISPOPMAP(0x00, 0x00), /* 0x2e: */ |
6869 | ISPOPMAP(0x00, 0x00), /* 0x2f: */ |
6870 | ISPOPMAP(0x00, 0x00), /* 0x30: */ |
6871 | ISPOPMAP(0x00, 0x00), /* 0x31: */ |
6872 | ISPOPMAP(0x07, 0x07), /* 0x32: MBOX_SET_RETRY_COUNT */ |
6873 | ISPOPMAP(0x00, 0x00), /* 0x33: */ |
6874 | ISPOPMAP(0x00, 0x00), /* 0x34: */ |
6875 | ISPOPMAP(0x00, 0x00), /* 0x35: */ |
6876 | ISPOPMAP(0x00, 0x00), /* 0x36: */ |
6877 | ISPOPMAP(0x00, 0x00), /* 0x37: */ |
6878 | ISPOPMAP(0x0f, 0x01), /* 0x38: MBOX_SET_FIRMWARE_OPTIONS */ |
6879 | ISPOPMAP(0x0f, 0x07), /* 0x39: MBOX_SET_PORT_QUEUE_PARAMS */ |
6880 | ISPOPMAP(0x00, 0x00), /* 0x3a: */ |
6881 | ISPOPMAP(0x00, 0x00), /* 0x3b: */ |
6882 | ISPOPMAP(0x00, 0x00), /* 0x3c: */ |
6883 | ISPOPMAP(0x00, 0x00), /* 0x3d: */ |
6884 | ISPOPMAP(0x00, 0x00), /* 0x3e: */ |
6885 | ISPOPMAP(0x00, 0x00), /* 0x3f: */ |
6886 | ISPOPMAP(0x03, 0x01), /* 0x40: MBOX_LOOP_PORT_BYPASS */ |
6887 | ISPOPMAP(0x03, 0x01), /* 0x41: MBOX_LOOP_PORT_ENABLE */ |
6888 | ISPOPMAP(0x03, 0x07), /* 0x42: MBOX_GET_RESOURCE_COUNT */ |
6889 | ISPOPMAP(0x01, 0x01), /* 0x43: MBOX_REQUEST_OFFLINE_MODE */ |
6890 | ISPOPMAP(0x00, 0x00), /* 0x44: */ |
6891 | ISPOPMAP(0x00, 0x00), /* 0x45: */ |
6892 | ISPOPMAP(0x00, 0x00), /* 0x46: */ |
6893 | ISPOPMAP(0xcf, 0x03), /* 0x47: GET PORT_DATABASE ENHANCED */ |
6894 | ISPOPMAP(0xcd, 0x01), /* 0x48: MBOX_INIT_FIRMWARE_MULTI_ID */ |
6895 | ISPOPMAP(0xcd, 0x01), /* 0x49: MBOX_GET_VP_DATABASE */ |
6896 | ISPOPMAP(0x2cd, 0x01), /* 0x4a: MBOX_GET_VP_DATABASE_ENTRY */ |
6897 | ISPOPMAP(0x00, 0x00), /* 0x4b: */ |
6898 | ISPOPMAP(0x00, 0x00), /* 0x4c: */ |
6899 | ISPOPMAP(0x00, 0x00), /* 0x4d: */ |
6900 | ISPOPMAP(0x00, 0x00), /* 0x4e: */ |
6901 | ISPOPMAP(0x00, 0x00), /* 0x4f: */ |
6902 | ISPOPMAP(0x00, 0x00), /* 0x50: */ |
6903 | ISPOPMAP(0x00, 0x00), /* 0x51: */ |
6904 | ISPOPMAP(0x00, 0x00), /* 0x52: */ |
6905 | ISPOPMAP(0x00, 0x00), /* 0x53: */ |
6906 | ISPOPMAP(0xcf, 0x01), /* 0x54: EXECUTE IOCB A64 */ |
6907 | ISPOPMAP(0x00, 0x00), /* 0x55: */ |
6908 | ISPOPMAP(0x00, 0x00), /* 0x56: */ |
6909 | ISPOPMAP(0x00, 0x00), /* 0x57: */ |
6910 | ISPOPMAP(0x00, 0x00), /* 0x58: */ |
6911 | ISPOPMAP(0x00, 0x00), /* 0x59: */ |
6912 | ISPOPMAP(0x00, 0x00), /* 0x5a: */ |
6913 | ISPOPMAP(0x03, 0x01), /* 0x5b: MBOX_DRIVER_HEARTBEAT */ |
6914 | ISPOPMAP(0xcf, 0x01), /* 0x5c: MBOX_FW_HEARTBEAT */ |
6915 | ISPOPMAP(0x07, 0x03), /* 0x5d: MBOX_GET_SET_DATA_RATE */ |
6916 | ISPOPMAP(0x00, 0x00), /* 0x5e: */ |
6917 | ISPOPMAP(0x00, 0x00), /* 0x5f: */ |
6918 | ISPOPMAP(0xcd, 0x01), /* 0x60: MBOX_INIT_FIRMWARE */ |
6919 | ISPOPMAP(0x00, 0x00), /* 0x61: */ |
6920 | ISPOPMAP(0x01, 0x01), /* 0x62: MBOX_INIT_LIP */ |
6921 | ISPOPMAP(0xcd, 0x03), /* 0x63: MBOX_GET_FC_AL_POSITION_MAP */ |
6922 | ISPOPMAP(0xcf, 0x01), /* 0x64: MBOX_GET_PORT_DB */ |
6923 | ISPOPMAP(0x07, 0x01), /* 0x65: MBOX_CLEAR_ACA */ |
6924 | ISPOPMAP(0x07, 0x01), /* 0x66: MBOX_TARGET_RESET */ |
6925 | ISPOPMAP(0x07, 0x01), /* 0x67: MBOX_CLEAR_TASK_SET */ |
6926 | ISPOPMAP(0x07, 0x01), /* 0x68: MBOX_ABORT_TASK_SET */ |
6927 | ISPOPMAP(0x01, 0x07), /* 0x69: MBOX_GET_FW_STATE */ |
6928 | ISPOPMAP(0x03, 0xcf), /* 0x6a: MBOX_GET_PORT_NAME */ |
6929 | ISPOPMAP(0xcf, 0x01), /* 0x6b: MBOX_GET_LINK_STATUS */ |
6930 | ISPOPMAP(0x0f, 0x01), /* 0x6c: MBOX_INIT_LIP_RESET */ |
6931 | ISPOPMAP(0x00, 0x00), /* 0x6d: */ |
6932 | ISPOPMAP(0xcf, 0x03), /* 0x6e: MBOX_SEND_SNS */ |
6933 | ISPOPMAP(0x0f, 0x07), /* 0x6f: MBOX_FABRIC_LOGIN */ |
6934 | ISPOPMAP(0x03, 0x01), /* 0x70: MBOX_SEND_CHANGE_REQUEST */ |
6935 | ISPOPMAP(0x03, 0x03), /* 0x71: MBOX_FABRIC_LOGOUT */ |
6936 | ISPOPMAP(0x0f, 0x0f), /* 0x72: MBOX_INIT_LIP_LOGIN */ |
6937 | ISPOPMAP(0x00, 0x00), /* 0x73: */ |
6938 | ISPOPMAP(0x07, 0x01), /* 0x74: LOGIN LOOP PORT */ |
6939 | ISPOPMAP(0xcf, 0x03), /* 0x75: GET PORT/NODE NAME LIST */ |
6940 | ISPOPMAP(0x4f, 0x01), /* 0x76: SET VENDOR ID */ |
6941 | ISPOPMAP(0xcd, 0x01), /* 0x77: INITIALIZE IP MAILBOX */ |
6942 | ISPOPMAP(0x00, 0x00), /* 0x78: */ |
6943 | ISPOPMAP(0x00, 0x00), /* 0x79: */ |
6944 | ISPOPMAP(0x00, 0x00), /* 0x7a: */ |
6945 | ISPOPMAP(0x00, 0x00), /* 0x7b: */ |
6946 | ISPOPMAP(0x4f, 0x03), /* 0x7c: Get ID List */ |
6947 | ISPOPMAP(0xcf, 0x01), /* 0x7d: SEND LFA */ |
6948 | ISPOPMAP(0x0f, 0x01) /* 0x7e: LUN RESET */ |
6949 | }; |
6950 | /* |
6951 | * Footnotes |
6952 | * |
6953 | * (1): this sets bits 21..16 in mailbox register #8, which we nominally |
6954 | * do not access at this time in the core driver. The caller is |
6955 | * responsible for setting this register first (Gross!). The assumption |
6956 | * is that we won't overflow. |
6957 | */ |
6958 | |
6959 | static const char *fc_mbcmd_names[] = { |
6960 | "NO-OP" , |
6961 | "LOAD RAM" , |
6962 | "EXEC FIRMWARE" , |
6963 | "DUMP RAM" , |
6964 | "WRITE RAM WORD" , |
6965 | "READ RAM WORD" , |
6966 | "MAILBOX REG TEST" , |
6967 | "VERIFY CHECKSUM" , |
6968 | "ABOUT FIRMWARE" , |
6969 | "LOAD RAM" , |
6970 | "DUMP RAM" , |
6971 | "WRITE RAM WORD EXTENDED" , |
6972 | NULL, |
6973 | "READ RAM WORD EXTENDED" , |
6974 | "CHECK FIRMWARE" , |
6975 | NULL, |
6976 | "INIT REQUEST QUEUE" , |
6977 | "INIT RESULT QUEUE" , |
6978 | "EXECUTE IOCB" , |
6979 | "WAKE UP" , |
6980 | "STOP FIRMWARE" , |
6981 | "ABORT" , |
6982 | "ABORT DEVICE" , |
6983 | "ABORT TARGET" , |
6984 | "BUS RESET" , |
6985 | "STOP QUEUE" , |
6986 | "START QUEUE" , |
6987 | "SINGLE STEP QUEUE" , |
6988 | "ABORT QUEUE" , |
6989 | "GET DEV QUEUE STATUS" , |
6990 | NULL, |
6991 | "GET FIRMWARE STATUS" , |
6992 | "GET LOOP ID" , |
6993 | NULL, |
6994 | "GET RETRY COUNT" , |
6995 | NULL, |
6996 | NULL, |
6997 | NULL, |
6998 | NULL, |
6999 | NULL, |
7000 | "GET FIRMWARE OPTIONS" , |
7001 | "GET PORT QUEUE PARAMS" , |
7002 | NULL, |
7003 | NULL, |
7004 | NULL, |
7005 | NULL, |
7006 | NULL, |
7007 | NULL, |
7008 | NULL, |
7009 | NULL, |
7010 | "SET RETRY COUNT" , |
7011 | NULL, |
7012 | NULL, |
7013 | NULL, |
7014 | NULL, |
7015 | NULL, |
7016 | "SET FIRMWARE OPTIONS" , |
7017 | "SET PORT QUEUE PARAMS" , |
7018 | NULL, |
7019 | NULL, |
7020 | NULL, |
7021 | NULL, |
7022 | NULL, |
7023 | NULL, |
7024 | "LOOP PORT BYPASS" , |
7025 | "LOOP PORT ENABLE" , |
7026 | "GET RESOURCE COUNT" , |
7027 | "REQUEST NON PARTICIPATING MODE" , |
7028 | NULL, |
7029 | NULL, |
7030 | NULL, |
7031 | "GET PORT DATABASE ENHANCED" , |
7032 | "INIT FIRMWARE MULTI ID" , |
7033 | "GET VP DATABASE" , |
7034 | "GET VP DATABASE ENTRY" , |
7035 | NULL, |
7036 | NULL, |
7037 | NULL, |
7038 | NULL, |
7039 | NULL, |
7040 | NULL, |
7041 | NULL, |
7042 | NULL, |
7043 | NULL, |
7044 | "EXECUTE IOCB A64" , |
7045 | NULL, |
7046 | NULL, |
7047 | NULL, |
7048 | NULL, |
7049 | NULL, |
7050 | NULL, |
7051 | "DRIVER HEARTBEAT" , |
7052 | NULL, |
7053 | "GET/SET DATA RATE" , |
7054 | NULL, |
7055 | NULL, |
7056 | "INIT FIRMWARE" , |
7057 | NULL, |
7058 | "INIT LIP" , |
7059 | "GET FC-AL POSITION MAP" , |
7060 | "GET PORT DATABASE" , |
7061 | "CLEAR ACA" , |
7062 | "TARGET RESET" , |
7063 | "CLEAR TASK SET" , |
7064 | "ABORT TASK SET" , |
7065 | "GET FW STATE" , |
7066 | "GET PORT NAME" , |
7067 | "GET LINK STATUS" , |
7068 | "INIT LIP RESET" , |
7069 | NULL, |
7070 | "SEND SNS" , |
7071 | "FABRIC LOGIN" , |
7072 | "SEND CHANGE REQUEST" , |
7073 | "FABRIC LOGOUT" , |
7074 | "INIT LIP LOGIN" , |
7075 | NULL, |
7076 | "LOGIN LOOP PORT" , |
7077 | "GET PORT/NODE NAME LIST" , |
7078 | "SET VENDOR ID" , |
7079 | "INITIALIZE IP MAILBOX" , |
7080 | NULL, |
7081 | NULL, |
7082 | NULL, |
7083 | NULL, |
7084 | "Get ID List" , |
7085 | "SEND LFA" , |
7086 | "Lun RESET" |
7087 | }; |
7088 | |
7089 | static void |
7090 | isp_mboxcmd_qnw(ispsoftc_t *isp, mbreg_t *mbp, int nodelay) |
7091 | { |
7092 | unsigned int ibits, obits, box, opcode; |
7093 | const uint32_t *mcp; |
7094 | |
7095 | if (IS_FC(isp)) { |
7096 | mcp = mbpfc; |
7097 | } else { |
7098 | mcp = mbpscsi; |
7099 | } |
7100 | opcode = mbp->param[0]; |
7101 | ibits = HIWRD(mcp[opcode]) & NMBOX_BMASK(isp); |
7102 | obits = LOWRD(mcp[opcode]) & NMBOX_BMASK(isp); |
7103 | ibits |= mbp->ibits; |
7104 | obits |= mbp->obits; |
7105 | for (box = 0; box < MAX_MAILBOX(isp); box++) { |
7106 | if (ibits & (1 << box)) { |
7107 | ISP_WRITE(isp, MBOX_OFF(box), mbp->param[box]); |
7108 | } |
7109 | if (nodelay == 0) { |
7110 | isp->isp_mboxtmp[box] = mbp->param[box] = 0; |
7111 | } |
7112 | } |
7113 | if (nodelay == 0) { |
7114 | isp->isp_lastmbxcmd = opcode; |
7115 | isp->isp_obits = obits; |
7116 | isp->isp_mboxbsy = 1; |
7117 | } |
7118 | if (IS_24XX(isp)) { |
7119 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_SET_HOST_INT); |
7120 | } else { |
7121 | ISP_WRITE(isp, HCCR, HCCR_CMD_SET_HOST_INT); |
7122 | } |
7123 | /* |
7124 | * Oddly enough, if we're not delaying for an answer, |
7125 | * delay a bit to give the f/w a chance to pick up the |
7126 | * command. |
7127 | */ |
7128 | if (nodelay) { |
7129 | ISP_DELAY(1000); |
7130 | } |
7131 | } |
7132 | |
7133 | static void |
7134 | isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp) |
7135 | { |
7136 | const char *cname, *xname; |
7137 | char tname[16], mname[16]; |
7138 | unsigned int lim, ibits, obits, box, opcode; |
7139 | const uint32_t *mcp; |
7140 | |
7141 | if (IS_FC(isp)) { |
7142 | mcp = mbpfc; |
7143 | lim = (sizeof (mbpfc) / sizeof (mbpfc[0])); |
7144 | } else { |
7145 | mcp = mbpscsi; |
7146 | lim = (sizeof (mbpscsi) / sizeof (mbpscsi[0])); |
7147 | } |
7148 | |
7149 | if ((opcode = mbp->param[0]) >= lim) { |
7150 | mbp->param[0] = MBOX_INVALID_COMMAND; |
7151 | isp_prt(isp, ISP_LOGERR, "Unknown Command 0x%x" , opcode); |
7152 | return; |
7153 | } |
7154 | |
7155 | ibits = HIWRD(mcp[opcode]) & NMBOX_BMASK(isp); |
7156 | obits = LOWRD(mcp[opcode]) & NMBOX_BMASK(isp); |
7157 | |
7158 | /* |
7159 | * Pick up any additional bits that the caller might have set. |
7160 | */ |
7161 | ibits |= mbp->ibits; |
7162 | obits |= mbp->obits; |
7163 | |
7164 | if (ibits == 0 && obits == 0) { |
7165 | mbp->param[0] = MBOX_COMMAND_PARAM_ERROR; |
7166 | isp_prt(isp, ISP_LOGERR, "no parameters for 0x%x" , opcode); |
7167 | return; |
7168 | } |
7169 | |
7170 | /* |
7171 | * Get exclusive usage of mailbox registers. |
7172 | */ |
7173 | if (MBOX_ACQUIRE(isp)) { |
7174 | mbp->param[0] = MBOX_REGS_BUSY; |
7175 | goto out; |
7176 | } |
7177 | |
7178 | for (box = 0; box < MAX_MAILBOX(isp); box++) { |
7179 | if (ibits & (1 << box)) { |
7180 | isp_prt(isp, ISP_LOGDEBUG3, "IN mbox %d = 0x%04x" , box, |
7181 | mbp->param[box]); |
7182 | ISP_WRITE(isp, MBOX_OFF(box), mbp->param[box]); |
7183 | } |
7184 | isp->isp_mboxtmp[box] = mbp->param[box] = 0; |
7185 | } |
7186 | |
7187 | isp->isp_lastmbxcmd = opcode; |
7188 | |
7189 | /* |
7190 | * We assume that we can't overwrite a previous command. |
7191 | */ |
7192 | isp->isp_obits = obits; |
7193 | isp->isp_mboxbsy = 1; |
7194 | |
7195 | /* |
7196 | * Set Host Interrupt condition so that RISC will pick up mailbox regs. |
7197 | */ |
7198 | if (IS_24XX(isp)) { |
7199 | ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_SET_HOST_INT); |
7200 | } else { |
7201 | ISP_WRITE(isp, HCCR, HCCR_CMD_SET_HOST_INT); |
7202 | } |
7203 | |
7204 | /* |
7205 | * While we haven't finished the command, spin our wheels here. |
7206 | */ |
7207 | MBOX_WAIT_COMPLETE(isp, mbp); |
7208 | |
7209 | /* |
7210 | * Did the command time out? |
7211 | */ |
7212 | if (mbp->param[0] == MBOX_TIMEOUT) { |
7213 | isp->isp_mboxbsy = 0; |
7214 | MBOX_RELEASE(isp); |
7215 | goto out; |
7216 | } |
7217 | |
7218 | /* |
7219 | * Copy back output registers. |
7220 | */ |
7221 | for (box = 0; box < MAX_MAILBOX(isp); box++) { |
7222 | if (obits & (1 << box)) { |
7223 | mbp->param[box] = isp->isp_mboxtmp[box]; |
7224 | isp_prt(isp, ISP_LOGDEBUG3, "OUT mbox %d = 0x%04x" , box, |
7225 | mbp->param[box]); |
7226 | } |
7227 | } |
7228 | |
7229 | isp->isp_mboxbsy = 0; |
7230 | MBOX_RELEASE(isp); |
7231 | out: |
7232 | if (mbp->logval == 0 || opcode == MBOX_EXEC_FIRMWARE) { |
7233 | return; |
7234 | } |
7235 | cname = (IS_FC(isp))? fc_mbcmd_names[opcode] : scsi_mbcmd_names[opcode]; |
7236 | if (cname == NULL) { |
7237 | cname = tname; |
7238 | ISP_SNPRINTF(tname, sizeof tname, "opcode %x" , opcode); |
7239 | } |
7240 | |
7241 | /* |
7242 | * Just to be chatty here... |
7243 | */ |
7244 | xname = NULL; |
7245 | switch (mbp->param[0]) { |
7246 | case MBOX_COMMAND_COMPLETE: |
7247 | break; |
7248 | case MBOX_INVALID_COMMAND: |
7249 | if (mbp->logval & MBLOGMASK(MBOX_COMMAND_COMPLETE)) { |
7250 | xname = "INVALID COMMAND" ; |
7251 | } |
7252 | break; |
7253 | case MBOX_HOST_INTERFACE_ERROR: |
7254 | if (mbp->logval & MBLOGMASK(MBOX_HOST_INTERFACE_ERROR)) { |
7255 | xname = "HOST INTERFACE ERROR" ; |
7256 | } |
7257 | break; |
7258 | case MBOX_TEST_FAILED: |
7259 | if (mbp->logval & MBLOGMASK(MBOX_TEST_FAILED)) { |
7260 | xname = "TEST FAILED" ; |
7261 | } |
7262 | break; |
7263 | case MBOX_COMMAND_ERROR: |
7264 | if (mbp->logval & MBLOGMASK(MBOX_COMMAND_ERROR)) { |
7265 | xname = "COMMAND ERROR" ; |
7266 | } |
7267 | break; |
7268 | case MBOX_COMMAND_PARAM_ERROR: |
7269 | if (mbp->logval & MBLOGMASK(MBOX_COMMAND_PARAM_ERROR)) { |
7270 | xname = "COMMAND PARAMETER ERROR" ; |
7271 | } |
7272 | break; |
7273 | case MBOX_LOOP_ID_USED: |
7274 | if (mbp->logval & MBLOGMASK(MBOX_LOOP_ID_USED)) { |
7275 | xname = "LOOP ID ALREADY IN USE" ; |
7276 | } |
7277 | break; |
7278 | case MBOX_PORT_ID_USED: |
7279 | if (mbp->logval & MBLOGMASK(MBOX_PORT_ID_USED)) { |
7280 | xname = "PORT ID ALREADY IN USE" ; |
7281 | } |
7282 | break; |
7283 | case MBOX_ALL_IDS_USED: |
7284 | if (mbp->logval & MBLOGMASK(MBOX_ALL_IDS_USED)) { |
7285 | xname = "ALL LOOP IDS IN USE" ; |
7286 | } |
7287 | break; |
7288 | case MBOX_REGS_BUSY: |
7289 | xname = "REGISTERS BUSY" ; |
7290 | break; |
7291 | case MBOX_TIMEOUT: |
7292 | xname = "TIMEOUT" ; |
7293 | break; |
7294 | default: |
7295 | ISP_SNPRINTF(mname, sizeof mname, "error 0x%x" , mbp->param[0]); |
7296 | xname = mname; |
7297 | break; |
7298 | } |
7299 | if (xname) { |
7300 | isp_prt(isp, ISP_LOGALL, "Mailbox Command '%s' failed (%s)" , |
7301 | cname, xname); |
7302 | } |
7303 | } |
7304 | |
7305 | static void |
7306 | isp_fw_state(ispsoftc_t *isp, int chan) |
7307 | { |
7308 | if (IS_FC(isp)) { |
7309 | mbreg_t mbs; |
7310 | fcparam *fcp = FCPARAM(isp, chan); |
7311 | |
7312 | MBSINIT(&mbs, MBOX_GET_FW_STATE, MBLOGALL, 0); |
7313 | isp_mboxcmd(isp, &mbs); |
7314 | if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { |
7315 | fcp->isp_fwstate = mbs.param[1]; |
7316 | } |
7317 | } |
7318 | } |
7319 | |
7320 | static void |
7321 | isp_spi_update(ispsoftc_t *isp, int chan) |
7322 | { |
7323 | int tgt; |
7324 | mbreg_t mbs; |
7325 | sdparam *sdp; |
7326 | |
7327 | if (IS_FC(isp)) { |
7328 | /* |
7329 | * There are no 'per-bus' settings for Fibre Channel. |
7330 | */ |
7331 | return; |
7332 | } |
7333 | sdp = SDPARAM(isp, chan); |
7334 | sdp->update = 0; |
7335 | |
7336 | for (tgt = 0; tgt < MAX_TARGETS; tgt++) { |
7337 | uint16_t flags, period, offset; |
7338 | int get; |
7339 | |
7340 | if (sdp->isp_devparam[tgt].dev_enable == 0) { |
7341 | sdp->isp_devparam[tgt].dev_update = 0; |
7342 | sdp->isp_devparam[tgt].dev_refresh = 0; |
7343 | isp_prt(isp, ISP_LOGDEBUG0, "skipping target %d bus %d update" , tgt, chan); |
7344 | continue; |
7345 | } |
7346 | /* |
7347 | * If the goal is to update the status of the device, |
7348 | * take what's in goal_flags and try and set the device |
7349 | * toward that. Otherwise, if we're just refreshing the |
7350 | * current device state, get the current parameters. |
7351 | */ |
7352 | |
7353 | MBSINIT(&mbs, 0, MBLOGALL, 0); |
7354 | |
7355 | /* |
7356 | * Refresh overrides set |
7357 | */ |
7358 | if (sdp->isp_devparam[tgt].dev_refresh) { |
7359 | mbs.param[0] = MBOX_GET_TARGET_PARAMS; |
7360 | get = 1; |
7361 | } else if (sdp->isp_devparam[tgt].dev_update) { |
7362 | mbs.param[0] = MBOX_SET_TARGET_PARAMS; |
7363 | |
7364 | /* |
7365 | * Make sure goal_flags has "Renegotiate on Error" |
7366 | * on and "Freeze Queue on Error" off. |
7367 | */ |
7368 | sdp->isp_devparam[tgt].goal_flags |= DPARM_RENEG; |
7369 | sdp->isp_devparam[tgt].goal_flags &= ~DPARM_QFRZ; |
7370 | mbs.param[2] = sdp->isp_devparam[tgt].goal_flags; |
7371 | |
7372 | /* |
7373 | * Insist that PARITY must be enabled |
7374 | * if SYNC or WIDE is enabled. |
7375 | */ |
7376 | if ((mbs.param[2] & (DPARM_SYNC|DPARM_WIDE)) != 0) { |
7377 | mbs.param[2] |= DPARM_PARITY; |
7378 | } |
7379 | |
7380 | if (mbs.param[2] & DPARM_SYNC) { |
7381 | mbs.param[3] = |
7382 | (sdp->isp_devparam[tgt].goal_offset << 8) | |
7383 | (sdp->isp_devparam[tgt].goal_period); |
7384 | } |
7385 | /* |
7386 | * A command completion later that has |
7387 | * RQSTF_NEGOTIATION set can cause |
7388 | * the dev_refresh/announce cycle also. |
7389 | * |
7390 | * Note: It is really important to update our current |
7391 | * flags with at least the state of TAG capabilities- |
7392 | * otherwise we might try and send a tagged command |
7393 | * when we have it all turned off. So change it here |
7394 | * to say that current already matches goal. |
7395 | */ |
7396 | sdp->isp_devparam[tgt].actv_flags &= ~DPARM_TQING; |
7397 | sdp->isp_devparam[tgt].actv_flags |= |
7398 | (sdp->isp_devparam[tgt].goal_flags & DPARM_TQING); |
7399 | isp_prt(isp, ISP_LOGDEBUG0, "bus %d set tgt %d flags 0x%x off 0x%x period 0x%x" , |
7400 | chan, tgt, mbs.param[2], mbs.param[3] >> 8, mbs.param[3] & 0xff); |
7401 | get = 0; |
7402 | } else { |
7403 | continue; |
7404 | } |
7405 | mbs.param[1] = (chan << 15) | (tgt << 8); |
7406 | isp_mboxcmd(isp, &mbs); |
7407 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
7408 | continue; |
7409 | } |
7410 | if (get == 0) { |
7411 | sdp->sendmarker = 1; |
7412 | sdp->isp_devparam[tgt].dev_update = 0; |
7413 | sdp->isp_devparam[tgt].dev_refresh = 1; |
7414 | } else { |
7415 | sdp->isp_devparam[tgt].dev_refresh = 0; |
7416 | flags = mbs.param[2]; |
7417 | period = mbs.param[3] & 0xff; |
7418 | offset = mbs.param[3] >> 8; |
7419 | sdp->isp_devparam[tgt].actv_flags = flags; |
7420 | sdp->isp_devparam[tgt].actv_period = period; |
7421 | sdp->isp_devparam[tgt].actv_offset = offset; |
7422 | isp_async(isp, ISPASYNC_NEW_TGT_PARAMS, chan, tgt); |
7423 | } |
7424 | } |
7425 | |
7426 | for (tgt = 0; tgt < MAX_TARGETS; tgt++) { |
7427 | if (sdp->isp_devparam[tgt].dev_update || |
7428 | sdp->isp_devparam[tgt].dev_refresh) { |
7429 | sdp->update = 1; |
7430 | break; |
7431 | } |
7432 | } |
7433 | } |
7434 | |
7435 | static void |
7436 | isp_setdfltsdparm(ispsoftc_t *isp) |
7437 | { |
7438 | int tgt; |
7439 | sdparam *sdp, *sdp1; |
7440 | |
7441 | sdp = SDPARAM(isp, 0); |
7442 | sdp->role = GET_DEFAULT_ROLE(isp, 0); |
7443 | if (IS_DUALBUS(isp)) { |
7444 | sdp1 = sdp + 1; |
7445 | sdp1->role = GET_DEFAULT_ROLE(isp, 1); |
7446 | } else { |
7447 | sdp1 = NULL; |
7448 | } |
7449 | |
7450 | /* |
7451 | * Establish some default parameters. |
7452 | */ |
7453 | sdp->isp_cmd_dma_burst_enable = 0; |
7454 | sdp->isp_data_dma_burst_enabl = 1; |
7455 | sdp->isp_fifo_threshold = 0; |
7456 | sdp->isp_initiator_id = DEFAULT_IID(isp, 0); |
7457 | if (isp->isp_type >= ISP_HA_SCSI_1040) { |
7458 | sdp->isp_async_data_setup = 9; |
7459 | } else { |
7460 | sdp->isp_async_data_setup = 6; |
7461 | } |
7462 | sdp->isp_selection_timeout = 250; |
7463 | sdp->isp_max_queue_depth = MAXISPREQUEST(isp); |
7464 | sdp->isp_tag_aging = 8; |
7465 | sdp->isp_bus_reset_delay = 5; |
7466 | /* |
7467 | * Don't retry selection, busy or queue full automatically- reflect |
7468 | * these back to us. |
7469 | */ |
7470 | sdp->isp_retry_count = 0; |
7471 | sdp->isp_retry_delay = 0; |
7472 | |
7473 | for (tgt = 0; tgt < MAX_TARGETS; tgt++) { |
7474 | sdp->isp_devparam[tgt].exc_throttle = ISP_EXEC_THROTTLE; |
7475 | sdp->isp_devparam[tgt].dev_enable = 1; |
7476 | } |
7477 | |
7478 | /* |
7479 | * The trick here is to establish a default for the default (honk!) |
7480 | * state (goal_flags). Then try and get the current status from |
7481 | * the card to fill in the current state. We don't, in fact, set |
7482 | * the default to the SAFE default state- that's not the goal state. |
7483 | */ |
7484 | for (tgt = 0; tgt < MAX_TARGETS; tgt++) { |
7485 | uint8_t off, per; |
7486 | sdp->isp_devparam[tgt].actv_offset = 0; |
7487 | sdp->isp_devparam[tgt].actv_period = 0; |
7488 | sdp->isp_devparam[tgt].actv_flags = 0; |
7489 | |
7490 | sdp->isp_devparam[tgt].goal_flags = |
7491 | sdp->isp_devparam[tgt].nvrm_flags = DPARM_DEFAULT; |
7492 | |
7493 | /* |
7494 | * We default to Wide/Fast for versions less than a 1040 |
7495 | * (unless it's SBus). |
7496 | */ |
7497 | if (IS_ULTRA3(isp)) { |
7498 | off = ISP_80M_SYNCPARMS >> 8; |
7499 | per = ISP_80M_SYNCPARMS & 0xff; |
7500 | } else if (IS_ULTRA2(isp)) { |
7501 | off = ISP_40M_SYNCPARMS >> 8; |
7502 | per = ISP_40M_SYNCPARMS & 0xff; |
7503 | } else if (IS_1240(isp)) { |
7504 | off = ISP_20M_SYNCPARMS >> 8; |
7505 | per = ISP_20M_SYNCPARMS & 0xff; |
7506 | } else if ((isp->isp_bustype == ISP_BT_SBUS && |
7507 | isp->isp_type < ISP_HA_SCSI_1020A) || |
7508 | (isp->isp_bustype == ISP_BT_PCI && |
7509 | isp->isp_type < ISP_HA_SCSI_1040) || |
7510 | (isp->isp_clock && isp->isp_clock < 60) || |
7511 | (sdp->isp_ultramode == 0)) { |
7512 | off = ISP_10M_SYNCPARMS >> 8; |
7513 | per = ISP_10M_SYNCPARMS & 0xff; |
7514 | } else { |
7515 | off = ISP_20M_SYNCPARMS_1040 >> 8; |
7516 | per = ISP_20M_SYNCPARMS_1040 & 0xff; |
7517 | } |
7518 | sdp->isp_devparam[tgt].goal_offset = |
7519 | sdp->isp_devparam[tgt].nvrm_offset = off; |
7520 | sdp->isp_devparam[tgt].goal_period = |
7521 | sdp->isp_devparam[tgt].nvrm_period = per; |
7522 | |
7523 | } |
7524 | |
7525 | /* |
7526 | * If we're a dual bus card, just copy the data over |
7527 | */ |
7528 | if (sdp1) { |
7529 | *sdp1 = *sdp; |
7530 | sdp1->isp_initiator_id = DEFAULT_IID(isp, 1); |
7531 | } |
7532 | |
7533 | /* |
7534 | * If we've not been told to avoid reading NVRAM, try and read it. |
7535 | * If we're successful reading it, we can then return because NVRAM |
7536 | * will tell us what the desired settings are. Otherwise, we establish |
7537 | * some reasonable 'fake' nvram and goal defaults. |
7538 | */ |
7539 | if ((isp->isp_confopts & ISP_CFG_NONVRAM) == 0) { |
7540 | mbreg_t mbs; |
7541 | |
7542 | if (isp_read_nvram(isp, 0) == 0) { |
7543 | if (IS_DUALBUS(isp)) { |
7544 | if (isp_read_nvram(isp, 1) == 0) { |
7545 | return; |
7546 | } |
7547 | } |
7548 | } |
7549 | MBSINIT(&mbs, MBOX_GET_ACT_NEG_STATE, MBLOGNONE, 0); |
7550 | isp_mboxcmd(isp, &mbs); |
7551 | if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { |
7552 | sdp->isp_req_ack_active_neg = 1; |
7553 | sdp->isp_data_line_active_neg = 1; |
7554 | if (sdp1) { |
7555 | sdp1->isp_req_ack_active_neg = 1; |
7556 | sdp1->isp_data_line_active_neg = 1; |
7557 | } |
7558 | } else { |
7559 | sdp->isp_req_ack_active_neg = |
7560 | (mbs.param[1] >> 4) & 0x1; |
7561 | sdp->isp_data_line_active_neg = |
7562 | (mbs.param[1] >> 5) & 0x1; |
7563 | if (sdp1) { |
7564 | sdp1->isp_req_ack_active_neg = |
7565 | (mbs.param[2] >> 4) & 0x1; |
7566 | sdp1->isp_data_line_active_neg = |
7567 | (mbs.param[2] >> 5) & 0x1; |
7568 | } |
7569 | } |
7570 | } |
7571 | |
7572 | } |
7573 | |
7574 | static void |
7575 | isp_setdfltfcparm(ispsoftc_t *isp, int chan) |
7576 | { |
7577 | fcparam *fcp = FCPARAM(isp, chan); |
7578 | |
7579 | /* |
7580 | * Establish some default parameters. |
7581 | */ |
7582 | fcp->role = GET_DEFAULT_ROLE(isp, chan); |
7583 | fcp->isp_maxalloc = ICB_DFLT_ALLOC; |
7584 | fcp->isp_retry_delay = ICB_DFLT_RDELAY; |
7585 | fcp->isp_retry_count = ICB_DFLT_RCOUNT; |
7586 | fcp->isp_loopid = DEFAULT_LOOPID(isp, chan); |
7587 | fcp->isp_wwnn_nvram = DEFAULT_NODEWWN(isp, chan); |
7588 | fcp->isp_wwpn_nvram = DEFAULT_PORTWWN(isp, chan); |
7589 | fcp->isp_fwoptions = 0; |
7590 | fcp->isp_lasthdl = NIL_HANDLE; |
7591 | |
7592 | if (IS_24XX(isp)) { |
7593 | fcp->isp_fwoptions |= ICB2400_OPT1_FAIRNESS; |
7594 | fcp->isp_fwoptions |= ICB2400_OPT1_HARD_ADDRESS; |
7595 | if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX) { |
7596 | fcp->isp_fwoptions |= ICB2400_OPT1_FULL_DUPLEX; |
7597 | } |
7598 | fcp->isp_fwoptions |= ICB2400_OPT1_BOTH_WWNS; |
7599 | } else { |
7600 | fcp->isp_fwoptions |= ICBOPT_FAIRNESS; |
7601 | fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE; |
7602 | fcp->isp_fwoptions |= ICBOPT_HARD_ADDRESS; |
7603 | if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX) { |
7604 | fcp->isp_fwoptions |= ICBOPT_FULL_DUPLEX; |
7605 | } |
7606 | /* |
7607 | * Make sure this is turned off now until we get |
7608 | * extended options from NVRAM |
7609 | */ |
7610 | fcp->isp_fwoptions &= ~ICBOPT_EXTENDED; |
7611 | } |
7612 | |
7613 | |
7614 | /* |
7615 | * Now try and read NVRAM unless told to not do so. |
7616 | * This will set fcparam's isp_wwnn_nvram && isp_wwpn_nvram. |
7617 | */ |
7618 | if ((isp->isp_confopts & ISP_CFG_NONVRAM) == 0) { |
7619 | int i, j = 0; |
7620 | /* |
7621 | * Give a couple of tries at reading NVRAM. |
7622 | */ |
7623 | for (i = 0; i < 2; i++) { |
7624 | j = isp_read_nvram(isp, chan); |
7625 | if (j == 0) { |
7626 | break; |
7627 | } |
7628 | } |
7629 | if (j) { |
7630 | isp->isp_confopts |= ISP_CFG_NONVRAM; |
7631 | } |
7632 | } |
7633 | |
7634 | fcp->isp_wwnn = ACTIVE_NODEWWN(isp, chan); |
7635 | fcp->isp_wwpn = ACTIVE_PORTWWN(isp, chan); |
7636 | isp_prt(isp, ISP_LOGCONFIG, "Chan %d 0x%08x%08x/0x%08x%08x Role %s" , |
7637 | chan, (uint32_t) (fcp->isp_wwnn >> 32), (uint32_t) (fcp->isp_wwnn), |
7638 | (uint32_t) (fcp->isp_wwpn >> 32), (uint32_t) (fcp->isp_wwpn), |
7639 | isp_class3_roles[fcp->role]); |
7640 | } |
7641 | |
7642 | /* |
7643 | * Re-initialize the ISP and complete all orphaned commands |
7644 | * with a 'botched' notice. The reset/init routines should |
7645 | * not disturb an already active list of commands. |
7646 | */ |
7647 | |
7648 | void |
7649 | isp_reinit(ispsoftc_t *isp, int do_load_defaults) |
7650 | { |
7651 | int i; |
7652 | |
7653 | isp_reset(isp, do_load_defaults); |
7654 | |
7655 | if (isp->isp_state != ISP_RESETSTATE) { |
7656 | isp_prt(isp, ISP_LOGERR, "%s: cannot reset card" , __func__); |
7657 | ISP_DISABLE_INTS(isp); |
7658 | goto cleanup; |
7659 | } |
7660 | |
7661 | isp_init(isp); |
7662 | |
7663 | if (isp->isp_state == ISP_INITSTATE) { |
7664 | isp->isp_state = ISP_RUNSTATE; |
7665 | } |
7666 | |
7667 | if (isp->isp_state != ISP_RUNSTATE) { |
7668 | #ifndef ISP_TARGET_MODE |
7669 | isp_prt(isp, ISP_LOGWARN, "%s: not at runstate" , __func__); |
7670 | #endif |
7671 | ISP_DISABLE_INTS(isp); |
7672 | if (IS_FC(isp)) { |
7673 | /* |
7674 | * If we're in ISP_ROLE_NONE, turn off the lasers. |
7675 | */ |
7676 | if (!IS_24XX(isp)) { |
7677 | ISP_WRITE(isp, BIU2100_CSR, BIU2100_FPM0_REGS); |
7678 | ISP_WRITE(isp, FPM_DIAG_CONFIG, FPM_SOFT_RESET); |
7679 | ISP_WRITE(isp, BIU2100_CSR, BIU2100_FB_REGS); |
7680 | ISP_WRITE(isp, FBM_CMD, FBMCMD_FIFO_RESET_ALL); |
7681 | ISP_WRITE(isp, BIU2100_CSR, BIU2100_RISC_REGS); |
7682 | } |
7683 | } |
7684 | } |
7685 | |
7686 | cleanup: |
7687 | |
7688 | isp->isp_nactive = 0; |
7689 | |
7690 | isp_clear_commands(isp); |
7691 | if (IS_FC(isp)) { |
7692 | for (i = 0; i < isp->isp_nchan; i++) { |
7693 | ISP_MARK_PORTDB(isp, i, -1); |
7694 | } |
7695 | } |
7696 | } |
7697 | |
7698 | /* |
7699 | * NVRAM Routines |
7700 | */ |
7701 | static int |
7702 | isp_read_nvram(ispsoftc_t *isp, int bus) |
7703 | { |
7704 | int i, amt, retval; |
7705 | uint8_t csum, minversion; |
7706 | union { |
7707 | uint8_t _x[ISP2400_NVRAM_SIZE]; |
7708 | uint16_t _s[ISP2400_NVRAM_SIZE>>1]; |
7709 | } _n; |
7710 | #define nvram_data _n._x |
7711 | #define nvram_words _n._s |
7712 | |
7713 | if (IS_24XX(isp)) { |
7714 | return (isp_read_nvram_2400(isp, nvram_data)); |
7715 | } else if (IS_FC(isp)) { |
7716 | amt = ISP2100_NVRAM_SIZE; |
7717 | minversion = 1; |
7718 | } else if (IS_ULTRA2(isp)) { |
7719 | amt = ISP1080_NVRAM_SIZE; |
7720 | minversion = 0; |
7721 | } else { |
7722 | amt = ISP_NVRAM_SIZE; |
7723 | minversion = 2; |
7724 | } |
7725 | |
7726 | for (i = 0; i < amt>>1; i++) { |
7727 | isp_rdnvram_word(isp, i, &nvram_words[i]); |
7728 | } |
7729 | |
7730 | if (nvram_data[0] != 'I' || nvram_data[1] != 'S' || |
7731 | nvram_data[2] != 'P') { |
7732 | if (isp->isp_bustype != ISP_BT_SBUS) { |
7733 | isp_prt(isp, ISP_LOGWARN, "invalid NVRAM header" ); |
7734 | isp_prt(isp, ISP_LOGDEBUG0, "%x %x %x" , nvram_data[0], nvram_data[1], nvram_data[2]); |
7735 | } |
7736 | retval = -1; |
7737 | goto out; |
7738 | } |
7739 | |
7740 | for (csum = 0, i = 0; i < amt; i++) { |
7741 | csum += nvram_data[i]; |
7742 | } |
7743 | if (csum != 0) { |
7744 | isp_prt(isp, ISP_LOGWARN, "invalid NVRAM checksum" ); |
7745 | retval = -1; |
7746 | goto out; |
7747 | } |
7748 | |
7749 | if (ISP_NVRAM_VERSION(nvram_data) < minversion) { |
7750 | isp_prt(isp, ISP_LOGWARN, "version %d NVRAM not understood" , |
7751 | ISP_NVRAM_VERSION(nvram_data)); |
7752 | retval = -1; |
7753 | goto out; |
7754 | } |
7755 | |
7756 | if (IS_ULTRA3(isp)) { |
7757 | isp_parse_nvram_12160(isp, bus, nvram_data); |
7758 | } else if (IS_1080(isp)) { |
7759 | isp_parse_nvram_1080(isp, bus, nvram_data); |
7760 | } else if (IS_1280(isp) || IS_1240(isp)) { |
7761 | isp_parse_nvram_1080(isp, bus, nvram_data); |
7762 | } else if (IS_SCSI(isp)) { |
7763 | isp_parse_nvram_1020(isp, nvram_data); |
7764 | } else { |
7765 | isp_parse_nvram_2100(isp, nvram_data); |
7766 | } |
7767 | retval = 0; |
7768 | out: |
7769 | return (retval); |
7770 | #undef nvram_data |
7771 | #undef nvram_words |
7772 | } |
7773 | |
7774 | static int |
7775 | isp_read_nvram_2400(ispsoftc_t *isp, uint8_t *nvram_data) |
7776 | { |
7777 | int retval = 0; |
7778 | uint32_t addr, csum, lwrds, *dptr; |
7779 | |
7780 | if (isp->isp_port) { |
7781 | addr = ISP2400_NVRAM_PORT1_ADDR; |
7782 | } else { |
7783 | addr = ISP2400_NVRAM_PORT0_ADDR; |
7784 | } |
7785 | |
7786 | dptr = (uint32_t *) nvram_data; |
7787 | for (lwrds = 0; lwrds < ISP2400_NVRAM_SIZE >> 2; lwrds++) { |
7788 | isp_rd_2400_nvram(isp, addr++, dptr++); |
7789 | } |
7790 | if (nvram_data[0] != 'I' || nvram_data[1] != 'S' || |
7791 | nvram_data[2] != 'P') { |
7792 | isp_prt(isp, ISP_LOGWARN, "invalid NVRAM header (%x %x %x)" , |
7793 | nvram_data[0], nvram_data[1], nvram_data[2]); |
7794 | retval = -1; |
7795 | goto out; |
7796 | } |
7797 | dptr = (uint32_t *) nvram_data; |
7798 | for (csum = 0, lwrds = 0; lwrds < ISP2400_NVRAM_SIZE >> 2; lwrds++) { |
7799 | uint32_t tmp; |
7800 | ISP_IOXGET_32(isp, &dptr[lwrds], tmp); |
7801 | csum += tmp; |
7802 | } |
7803 | if (csum != 0) { |
7804 | isp_prt(isp, ISP_LOGWARN, "invalid NVRAM checksum" ); |
7805 | retval = -1; |
7806 | goto out; |
7807 | } |
7808 | isp_parse_nvram_2400(isp, nvram_data); |
7809 | out: |
7810 | return (retval); |
7811 | } |
7812 | |
7813 | static void |
7814 | isp_rdnvram_word(ispsoftc_t *isp, int wo, uint16_t *rp) |
7815 | { |
7816 | int i, cbits; |
7817 | uint16_t bit, rqst; |
7818 | |
7819 | ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT); |
7820 | ISP_DELAY(10); |
7821 | ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT|BIU_NVRAM_CLOCK); |
7822 | ISP_DELAY(10); |
7823 | |
7824 | if (IS_FC(isp)) { |
7825 | wo &= ((ISP2100_NVRAM_SIZE >> 1) - 1); |
7826 | if (IS_2312(isp) && isp->isp_port) { |
7827 | wo += 128; |
7828 | } |
7829 | rqst = (ISP_NVRAM_READ << 8) | wo; |
7830 | cbits = 10; |
7831 | } else if (IS_ULTRA2(isp)) { |
7832 | wo &= ((ISP1080_NVRAM_SIZE >> 1) - 1); |
7833 | rqst = (ISP_NVRAM_READ << 8) | wo; |
7834 | cbits = 10; |
7835 | } else { |
7836 | wo &= ((ISP_NVRAM_SIZE >> 1) - 1); |
7837 | rqst = (ISP_NVRAM_READ << 6) | wo; |
7838 | cbits = 8; |
7839 | } |
7840 | |
7841 | /* |
7842 | * Clock the word select request out... |
7843 | */ |
7844 | for (i = cbits; i >= 0; i--) { |
7845 | if ((rqst >> i) & 1) { |
7846 | bit = BIU_NVRAM_SELECT | BIU_NVRAM_DATAOUT; |
7847 | } else { |
7848 | bit = BIU_NVRAM_SELECT; |
7849 | } |
7850 | ISP_WRITE(isp, BIU_NVRAM, bit); |
7851 | ISP_DELAY(10); |
7852 | (void)ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ |
7853 | ISP_WRITE(isp, BIU_NVRAM, bit | BIU_NVRAM_CLOCK); |
7854 | ISP_DELAY(10); |
7855 | (void)ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ |
7856 | ISP_WRITE(isp, BIU_NVRAM, bit); |
7857 | ISP_DELAY(10); |
7858 | (void)ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ |
7859 | } |
7860 | /* |
7861 | * Now read the result back in (bits come back in MSB format). |
7862 | */ |
7863 | *rp = 0; |
7864 | for (i = 0; i < 16; i++) { |
7865 | uint16_t rv; |
7866 | *rp <<= 1; |
7867 | ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT|BIU_NVRAM_CLOCK); |
7868 | ISP_DELAY(10); |
7869 | rv = ISP_READ(isp, BIU_NVRAM); |
7870 | if (rv & BIU_NVRAM_DATAIN) { |
7871 | *rp |= 1; |
7872 | } |
7873 | ISP_DELAY(10); |
7874 | ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT); |
7875 | ISP_DELAY(10); |
7876 | (void)ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ |
7877 | } |
7878 | ISP_WRITE(isp, BIU_NVRAM, 0); |
7879 | ISP_DELAY(10); |
7880 | (void)ISP_READ(isp, BIU_NVRAM); /* force PCI flush */ |
7881 | ISP_SWIZZLE_NVRAM_WORD(isp, rp); |
7882 | } |
7883 | |
7884 | static void |
7885 | isp_rd_2400_nvram(ispsoftc_t *isp, uint32_t addr, uint32_t *rp) |
7886 | { |
7887 | int loops = 0; |
7888 | uint32_t base = 0x7ffe0000; |
7889 | uint32_t tmp = 0; |
7890 | |
7891 | if (IS_25XX(isp)) { |
7892 | base = 0x7ff00000 | 0x48000; |
7893 | } |
7894 | ISP_WRITE(isp, BIU2400_FLASH_ADDR, base | addr); |
7895 | for (loops = 0; loops < 5000; loops++) { |
7896 | ISP_DELAY(10); |
7897 | tmp = ISP_READ(isp, BIU2400_FLASH_ADDR); |
7898 | if ((tmp & (1U << 31)) != 0) { |
7899 | break; |
7900 | } |
7901 | } |
7902 | if (tmp & (1U << 31)) { |
7903 | *rp = ISP_READ(isp, BIU2400_FLASH_DATA); |
7904 | ISP_SWIZZLE_NVRAM_LONG(isp, rp); |
7905 | } else { |
7906 | *rp = 0xffffffff; |
7907 | } |
7908 | } |
7909 | |
7910 | static void |
7911 | isp_parse_nvram_1020(ispsoftc_t *isp, uint8_t *nvram_data) |
7912 | { |
7913 | sdparam *sdp = SDPARAM(isp, 0); |
7914 | int tgt; |
7915 | |
7916 | sdp->isp_fifo_threshold = |
7917 | ISP_NVRAM_FIFO_THRESHOLD(nvram_data) | |
7918 | (ISP_NVRAM_FIFO_THRESHOLD_128(nvram_data) << 2); |
7919 | |
7920 | if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) |
7921 | sdp->isp_initiator_id = |
7922 | ISP_NVRAM_INITIATOR_ID(nvram_data); |
7923 | |
7924 | sdp->isp_bus_reset_delay = |
7925 | ISP_NVRAM_BUS_RESET_DELAY(nvram_data); |
7926 | |
7927 | sdp->isp_retry_count = |
7928 | ISP_NVRAM_BUS_RETRY_COUNT(nvram_data); |
7929 | |
7930 | sdp->isp_retry_delay = |
7931 | ISP_NVRAM_BUS_RETRY_DELAY(nvram_data); |
7932 | |
7933 | sdp->isp_async_data_setup = |
7934 | ISP_NVRAM_ASYNC_DATA_SETUP_TIME(nvram_data); |
7935 | |
7936 | if (isp->isp_type >= ISP_HA_SCSI_1040) { |
7937 | if (sdp->isp_async_data_setup < 9) { |
7938 | sdp->isp_async_data_setup = 9; |
7939 | } |
7940 | } else { |
7941 | if (sdp->isp_async_data_setup != 6) { |
7942 | sdp->isp_async_data_setup = 6; |
7943 | } |
7944 | } |
7945 | |
7946 | sdp->isp_req_ack_active_neg = |
7947 | ISP_NVRAM_REQ_ACK_ACTIVE_NEGATION(nvram_data); |
7948 | |
7949 | sdp->isp_data_line_active_neg = |
7950 | ISP_NVRAM_DATA_LINE_ACTIVE_NEGATION(nvram_data); |
7951 | |
7952 | sdp->isp_data_dma_burst_enabl = |
7953 | ISP_NVRAM_DATA_DMA_BURST_ENABLE(nvram_data); |
7954 | |
7955 | sdp->isp_cmd_dma_burst_enable = |
7956 | ISP_NVRAM_CMD_DMA_BURST_ENABLE(nvram_data); |
7957 | |
7958 | sdp->isp_tag_aging = |
7959 | ISP_NVRAM_TAG_AGE_LIMIT(nvram_data); |
7960 | |
7961 | sdp->isp_selection_timeout = |
7962 | ISP_NVRAM_SELECTION_TIMEOUT(nvram_data); |
7963 | |
7964 | sdp->isp_max_queue_depth = |
7965 | ISP_NVRAM_MAX_QUEUE_DEPTH(nvram_data); |
7966 | |
7967 | sdp->isp_fast_mttr = ISP_NVRAM_FAST_MTTR_ENABLE(nvram_data); |
7968 | |
7969 | for (tgt = 0; tgt < MAX_TARGETS; tgt++) { |
7970 | sdp->isp_devparam[tgt].dev_enable = |
7971 | ISP_NVRAM_TGT_DEVICE_ENABLE(nvram_data, tgt); |
7972 | sdp->isp_devparam[tgt].exc_throttle = |
7973 | ISP_NVRAM_TGT_EXEC_THROTTLE(nvram_data, tgt); |
7974 | sdp->isp_devparam[tgt].nvrm_offset = |
7975 | ISP_NVRAM_TGT_SYNC_OFFSET(nvram_data, tgt); |
7976 | sdp->isp_devparam[tgt].nvrm_period = |
7977 | ISP_NVRAM_TGT_SYNC_PERIOD(nvram_data, tgt); |
7978 | /* |
7979 | * We probably shouldn't lie about this, but it |
7980 | * it makes it much safer if we limit NVRAM values |
7981 | * to sanity. |
7982 | */ |
7983 | if (isp->isp_type < ISP_HA_SCSI_1040) { |
7984 | /* |
7985 | * If we're not ultra, we can't possibly |
7986 | * be a shorter period than this. |
7987 | */ |
7988 | if (sdp->isp_devparam[tgt].nvrm_period < 0x19) { |
7989 | sdp->isp_devparam[tgt].nvrm_period = 0x19; |
7990 | } |
7991 | if (sdp->isp_devparam[tgt].nvrm_offset > 0xc) { |
7992 | sdp->isp_devparam[tgt].nvrm_offset = 0x0c; |
7993 | } |
7994 | } else { |
7995 | if (sdp->isp_devparam[tgt].nvrm_offset > 0x8) { |
7996 | sdp->isp_devparam[tgt].nvrm_offset = 0x8; |
7997 | } |
7998 | } |
7999 | sdp->isp_devparam[tgt].nvrm_flags = 0; |
8000 | if (ISP_NVRAM_TGT_RENEG(nvram_data, tgt)) |
8001 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_RENEG; |
8002 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_ARQ; |
8003 | if (ISP_NVRAM_TGT_TQING(nvram_data, tgt)) |
8004 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_TQING; |
8005 | if (ISP_NVRAM_TGT_SYNC(nvram_data, tgt)) |
8006 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_SYNC; |
8007 | if (ISP_NVRAM_TGT_WIDE(nvram_data, tgt)) |
8008 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_WIDE; |
8009 | if (ISP_NVRAM_TGT_PARITY(nvram_data, tgt)) |
8010 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_PARITY; |
8011 | if (ISP_NVRAM_TGT_DISC(nvram_data, tgt)) |
8012 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_DISC; |
8013 | sdp->isp_devparam[tgt].actv_flags = 0; /* we don't know */ |
8014 | sdp->isp_devparam[tgt].goal_offset = |
8015 | sdp->isp_devparam[tgt].nvrm_offset; |
8016 | sdp->isp_devparam[tgt].goal_period = |
8017 | sdp->isp_devparam[tgt].nvrm_period; |
8018 | sdp->isp_devparam[tgt].goal_flags = |
8019 | sdp->isp_devparam[tgt].nvrm_flags; |
8020 | } |
8021 | } |
8022 | |
8023 | static void |
8024 | isp_parse_nvram_1080(ispsoftc_t *isp, int bus, uint8_t *nvram_data) |
8025 | { |
8026 | sdparam *sdp = SDPARAM(isp, bus); |
8027 | int tgt; |
8028 | |
8029 | sdp->isp_fifo_threshold = |
8030 | ISP1080_NVRAM_FIFO_THRESHOLD(nvram_data); |
8031 | |
8032 | if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) |
8033 | sdp->isp_initiator_id = |
8034 | ISP1080_NVRAM_INITIATOR_ID(nvram_data, bus); |
8035 | |
8036 | sdp->isp_bus_reset_delay = |
8037 | ISP1080_NVRAM_BUS_RESET_DELAY(nvram_data, bus); |
8038 | |
8039 | sdp->isp_retry_count = |
8040 | ISP1080_NVRAM_BUS_RETRY_COUNT(nvram_data, bus); |
8041 | |
8042 | sdp->isp_retry_delay = |
8043 | ISP1080_NVRAM_BUS_RETRY_DELAY(nvram_data, bus); |
8044 | |
8045 | sdp->isp_async_data_setup = |
8046 | ISP1080_NVRAM_ASYNC_DATA_SETUP_TIME(nvram_data, bus); |
8047 | |
8048 | sdp->isp_req_ack_active_neg = |
8049 | ISP1080_NVRAM_REQ_ACK_ACTIVE_NEGATION(nvram_data, bus); |
8050 | |
8051 | sdp->isp_data_line_active_neg = |
8052 | ISP1080_NVRAM_DATA_LINE_ACTIVE_NEGATION(nvram_data, bus); |
8053 | |
8054 | sdp->isp_data_dma_burst_enabl = |
8055 | ISP1080_NVRAM_BURST_ENABLE(nvram_data); |
8056 | |
8057 | sdp->isp_cmd_dma_burst_enable = |
8058 | ISP1080_NVRAM_BURST_ENABLE(nvram_data); |
8059 | |
8060 | sdp->isp_selection_timeout = |
8061 | ISP1080_NVRAM_SELECTION_TIMEOUT(nvram_data, bus); |
8062 | |
8063 | sdp->isp_max_queue_depth = |
8064 | ISP1080_NVRAM_MAX_QUEUE_DEPTH(nvram_data, bus); |
8065 | |
8066 | for (tgt = 0; tgt < MAX_TARGETS; tgt++) { |
8067 | sdp->isp_devparam[tgt].dev_enable = |
8068 | ISP1080_NVRAM_TGT_DEVICE_ENABLE(nvram_data, tgt, bus); |
8069 | sdp->isp_devparam[tgt].exc_throttle = |
8070 | ISP1080_NVRAM_TGT_EXEC_THROTTLE(nvram_data, tgt, bus); |
8071 | sdp->isp_devparam[tgt].nvrm_offset = |
8072 | ISP1080_NVRAM_TGT_SYNC_OFFSET(nvram_data, tgt, bus); |
8073 | sdp->isp_devparam[tgt].nvrm_period = |
8074 | ISP1080_NVRAM_TGT_SYNC_PERIOD(nvram_data, tgt, bus); |
8075 | sdp->isp_devparam[tgt].nvrm_flags = 0; |
8076 | if (ISP1080_NVRAM_TGT_RENEG(nvram_data, tgt, bus)) |
8077 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_RENEG; |
8078 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_ARQ; |
8079 | if (ISP1080_NVRAM_TGT_TQING(nvram_data, tgt, bus)) |
8080 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_TQING; |
8081 | if (ISP1080_NVRAM_TGT_SYNC(nvram_data, tgt, bus)) |
8082 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_SYNC; |
8083 | if (ISP1080_NVRAM_TGT_WIDE(nvram_data, tgt, bus)) |
8084 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_WIDE; |
8085 | if (ISP1080_NVRAM_TGT_PARITY(nvram_data, tgt, bus)) |
8086 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_PARITY; |
8087 | if (ISP1080_NVRAM_TGT_DISC(nvram_data, tgt, bus)) |
8088 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_DISC; |
8089 | sdp->isp_devparam[tgt].actv_flags = 0; |
8090 | sdp->isp_devparam[tgt].goal_offset = |
8091 | sdp->isp_devparam[tgt].nvrm_offset; |
8092 | sdp->isp_devparam[tgt].goal_period = |
8093 | sdp->isp_devparam[tgt].nvrm_period; |
8094 | sdp->isp_devparam[tgt].goal_flags = |
8095 | sdp->isp_devparam[tgt].nvrm_flags; |
8096 | } |
8097 | } |
8098 | |
8099 | static void |
8100 | isp_parse_nvram_12160(ispsoftc_t *isp, int bus, uint8_t *nvram_data) |
8101 | { |
8102 | sdparam *sdp = SDPARAM(isp, bus); |
8103 | int tgt; |
8104 | |
8105 | sdp->isp_fifo_threshold = |
8106 | ISP12160_NVRAM_FIFO_THRESHOLD(nvram_data); |
8107 | |
8108 | if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) |
8109 | sdp->isp_initiator_id = |
8110 | ISP12160_NVRAM_INITIATOR_ID(nvram_data, bus); |
8111 | |
8112 | sdp->isp_bus_reset_delay = |
8113 | ISP12160_NVRAM_BUS_RESET_DELAY(nvram_data, bus); |
8114 | |
8115 | sdp->isp_retry_count = |
8116 | ISP12160_NVRAM_BUS_RETRY_COUNT(nvram_data, bus); |
8117 | |
8118 | sdp->isp_retry_delay = |
8119 | ISP12160_NVRAM_BUS_RETRY_DELAY(nvram_data, bus); |
8120 | |
8121 | sdp->isp_async_data_setup = |
8122 | ISP12160_NVRAM_ASYNC_DATA_SETUP_TIME(nvram_data, bus); |
8123 | |
8124 | sdp->isp_req_ack_active_neg = |
8125 | ISP12160_NVRAM_REQ_ACK_ACTIVE_NEGATION(nvram_data, bus); |
8126 | |
8127 | sdp->isp_data_line_active_neg = |
8128 | ISP12160_NVRAM_DATA_LINE_ACTIVE_NEGATION(nvram_data, bus); |
8129 | |
8130 | sdp->isp_data_dma_burst_enabl = |
8131 | ISP12160_NVRAM_BURST_ENABLE(nvram_data); |
8132 | |
8133 | sdp->isp_cmd_dma_burst_enable = |
8134 | ISP12160_NVRAM_BURST_ENABLE(nvram_data); |
8135 | |
8136 | sdp->isp_selection_timeout = |
8137 | ISP12160_NVRAM_SELECTION_TIMEOUT(nvram_data, bus); |
8138 | |
8139 | sdp->isp_max_queue_depth = |
8140 | ISP12160_NVRAM_MAX_QUEUE_DEPTH(nvram_data, bus); |
8141 | |
8142 | for (tgt = 0; tgt < MAX_TARGETS; tgt++) { |
8143 | sdp->isp_devparam[tgt].dev_enable = |
8144 | ISP12160_NVRAM_TGT_DEVICE_ENABLE(nvram_data, tgt, bus); |
8145 | sdp->isp_devparam[tgt].exc_throttle = |
8146 | ISP12160_NVRAM_TGT_EXEC_THROTTLE(nvram_data, tgt, bus); |
8147 | sdp->isp_devparam[tgt].nvrm_offset = |
8148 | ISP12160_NVRAM_TGT_SYNC_OFFSET(nvram_data, tgt, bus); |
8149 | sdp->isp_devparam[tgt].nvrm_period = |
8150 | ISP12160_NVRAM_TGT_SYNC_PERIOD(nvram_data, tgt, bus); |
8151 | sdp->isp_devparam[tgt].nvrm_flags = 0; |
8152 | if (ISP12160_NVRAM_TGT_RENEG(nvram_data, tgt, bus)) |
8153 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_RENEG; |
8154 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_ARQ; |
8155 | if (ISP12160_NVRAM_TGT_TQING(nvram_data, tgt, bus)) |
8156 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_TQING; |
8157 | if (ISP12160_NVRAM_TGT_SYNC(nvram_data, tgt, bus)) |
8158 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_SYNC; |
8159 | if (ISP12160_NVRAM_TGT_WIDE(nvram_data, tgt, bus)) |
8160 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_WIDE; |
8161 | if (ISP12160_NVRAM_TGT_PARITY(nvram_data, tgt, bus)) |
8162 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_PARITY; |
8163 | if (ISP12160_NVRAM_TGT_DISC(nvram_data, tgt, bus)) |
8164 | sdp->isp_devparam[tgt].nvrm_flags |= DPARM_DISC; |
8165 | sdp->isp_devparam[tgt].actv_flags = 0; |
8166 | sdp->isp_devparam[tgt].goal_offset = |
8167 | sdp->isp_devparam[tgt].nvrm_offset; |
8168 | sdp->isp_devparam[tgt].goal_period = |
8169 | sdp->isp_devparam[tgt].nvrm_period; |
8170 | sdp->isp_devparam[tgt].goal_flags = |
8171 | sdp->isp_devparam[tgt].nvrm_flags; |
8172 | } |
8173 | } |
8174 | |
8175 | static void |
8176 | isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) |
8177 | { |
8178 | fcparam *fcp = FCPARAM(isp, 0); |
8179 | uint64_t wwn; |
8180 | |
8181 | /* |
8182 | * There is NVRAM storage for both Port and Node entities- |
8183 | * but the Node entity appears to be unused on all the cards |
8184 | * I can find. However, we should account for this being set |
8185 | * at some point in the future. |
8186 | * |
8187 | * Qlogic WWNs have an NAA of 2, but usually nothing shows up in |
8188 | * bits 48..60. In the case of the 2202, it appears that they do |
8189 | * use bit 48 to distinguish between the two instances on the card. |
8190 | * The 2204, which I've never seen, *probably* extends this method. |
8191 | */ |
8192 | wwn = ISP2100_NVRAM_PORT_NAME(nvram_data); |
8193 | if (wwn) { |
8194 | isp_prt(isp, ISP_LOGCONFIG, "NVRAM Port WWN 0x%08x%08x" , |
8195 | (uint32_t) (wwn >> 32), (uint32_t) (wwn)); |
8196 | if ((wwn >> 60) == 0) { |
8197 | wwn |= (((uint64_t) 2)<< 60); |
8198 | } |
8199 | } |
8200 | fcp->isp_wwpn_nvram = wwn; |
8201 | if (IS_2200(isp) || IS_23XX(isp)) { |
8202 | wwn = ISP2100_NVRAM_NODE_NAME(nvram_data); |
8203 | if (wwn) { |
8204 | isp_prt(isp, ISP_LOGCONFIG, "NVRAM Node WWN 0x%08x%08x" , |
8205 | (uint32_t) (wwn >> 32), |
8206 | (uint32_t) (wwn)); |
8207 | if ((wwn >> 60) == 0) { |
8208 | wwn |= (((uint64_t) 2)<< 60); |
8209 | } |
8210 | } else { |
8211 | wwn = fcp->isp_wwpn_nvram & ~((uint64_t) 0xfff << 48); |
8212 | } |
8213 | } else { |
8214 | wwn &= ~((uint64_t) 0xfff << 48); |
8215 | } |
8216 | fcp->isp_wwnn_nvram = wwn; |
8217 | |
8218 | fcp->isp_maxalloc = ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data); |
8219 | if ((isp->isp_confopts & ISP_CFG_OWNFSZ) == 0) { |
8220 | DEFAULT_FRAMESIZE(isp) = |
8221 | ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data); |
8222 | } |
8223 | fcp->isp_retry_delay = ISP2100_NVRAM_RETRY_DELAY(nvram_data); |
8224 | fcp->isp_retry_count = ISP2100_NVRAM_RETRY_COUNT(nvram_data); |
8225 | if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) { |
8226 | fcp->isp_loopid = ISP2100_NVRAM_HARDLOOPID(nvram_data); |
8227 | } |
8228 | if ((isp->isp_confopts & ISP_CFG_OWNEXCTHROTTLE) == 0) { |
8229 | DEFAULT_EXEC_THROTTLE(isp) = |
8230 | ISP2100_NVRAM_EXECUTION_THROTTLE(nvram_data); |
8231 | } |
8232 | fcp->isp_fwoptions = ISP2100_NVRAM_OPTIONS(nvram_data); |
8233 | isp_prt(isp, ISP_LOGDEBUG0, |
8234 | "NVRAM 0x%08x%08x 0x%08x%08x maxalloc %d maxframelen %d" , |
8235 | (uint32_t) (fcp->isp_wwnn_nvram >> 32), |
8236 | (uint32_t) fcp->isp_wwnn_nvram, |
8237 | (uint32_t) (fcp->isp_wwpn_nvram >> 32), |
8238 | (uint32_t) fcp->isp_wwpn_nvram, |
8239 | ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data), |
8240 | ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data)); |
8241 | isp_prt(isp, ISP_LOGDEBUG0, |
8242 | "execthrottle %d fwoptions 0x%x hardloop %d tov %d" , |
8243 | ISP2100_NVRAM_EXECUTION_THROTTLE(nvram_data), |
8244 | ISP2100_NVRAM_OPTIONS(nvram_data), |
8245 | ISP2100_NVRAM_HARDLOOPID(nvram_data), |
8246 | ISP2100_NVRAM_TOV(nvram_data)); |
8247 | fcp->isp_xfwoptions = ISP2100_XFW_OPTIONS(nvram_data); |
8248 | fcp->isp_zfwoptions = ISP2100_ZFW_OPTIONS(nvram_data); |
8249 | isp_prt(isp, ISP_LOGDEBUG0, "xfwoptions 0x%x zfw options 0x%x" , |
8250 | ISP2100_XFW_OPTIONS(nvram_data), ISP2100_ZFW_OPTIONS(nvram_data)); |
8251 | } |
8252 | |
8253 | static void |
8254 | isp_parse_nvram_2400(ispsoftc_t *isp, uint8_t *nvram_data) |
8255 | { |
8256 | fcparam *fcp = FCPARAM(isp, 0); |
8257 | uint64_t wwn; |
8258 | |
8259 | isp_prt(isp, ISP_LOGDEBUG0, |
8260 | "NVRAM 0x%08x%08x 0x%08x%08x exchg_cnt %d maxframelen %d" , |
8261 | (uint32_t) (ISP2400_NVRAM_NODE_NAME(nvram_data) >> 32), |
8262 | (uint32_t) (ISP2400_NVRAM_NODE_NAME(nvram_data)), |
8263 | (uint32_t) (ISP2400_NVRAM_PORT_NAME(nvram_data) >> 32), |
8264 | (uint32_t) (ISP2400_NVRAM_PORT_NAME(nvram_data)), |
8265 | ISP2400_NVRAM_EXCHANGE_COUNT(nvram_data), |
8266 | ISP2400_NVRAM_MAXFRAMELENGTH(nvram_data)); |
8267 | isp_prt(isp, ISP_LOGDEBUG0, |
8268 | "NVRAM execthr %d loopid %d fwopt1 0x%x fwopt2 0x%x fwopt3 0x%x" , |
8269 | ISP2400_NVRAM_EXECUTION_THROTTLE(nvram_data), |
8270 | ISP2400_NVRAM_HARDLOOPID(nvram_data), |
8271 | ISP2400_NVRAM_FIRMWARE_OPTIONS1(nvram_data), |
8272 | ISP2400_NVRAM_FIRMWARE_OPTIONS2(nvram_data), |
8273 | ISP2400_NVRAM_FIRMWARE_OPTIONS3(nvram_data)); |
8274 | |
8275 | wwn = ISP2400_NVRAM_PORT_NAME(nvram_data); |
8276 | fcp->isp_wwpn_nvram = wwn; |
8277 | |
8278 | wwn = ISP2400_NVRAM_NODE_NAME(nvram_data); |
8279 | if (wwn) { |
8280 | if ((wwn >> 60) != 2 && (wwn >> 60) != 5) { |
8281 | wwn = 0; |
8282 | } |
8283 | } |
8284 | if (wwn == 0 && (fcp->isp_wwpn_nvram >> 60) == 2) { |
8285 | wwn = fcp->isp_wwpn_nvram; |
8286 | wwn &= ~((uint64_t) 0xfff << 48); |
8287 | } |
8288 | fcp->isp_wwnn_nvram = wwn; |
8289 | |
8290 | if (ISP2400_NVRAM_EXCHANGE_COUNT(nvram_data)) { |
8291 | fcp->isp_maxalloc = ISP2400_NVRAM_EXCHANGE_COUNT(nvram_data); |
8292 | } |
8293 | if ((isp->isp_confopts & ISP_CFG_OWNFSZ) == 0) { |
8294 | DEFAULT_FRAMESIZE(isp) = |
8295 | ISP2400_NVRAM_MAXFRAMELENGTH(nvram_data); |
8296 | } |
8297 | if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) { |
8298 | fcp->isp_loopid = ISP2400_NVRAM_HARDLOOPID(nvram_data); |
8299 | } |
8300 | if ((isp->isp_confopts & ISP_CFG_OWNEXCTHROTTLE) == 0) { |
8301 | DEFAULT_EXEC_THROTTLE(isp) = |
8302 | ISP2400_NVRAM_EXECUTION_THROTTLE(nvram_data); |
8303 | } |
8304 | fcp->isp_fwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS1(nvram_data); |
8305 | fcp->isp_xfwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS2(nvram_data); |
8306 | fcp->isp_zfwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS3(nvram_data); |
8307 | } |
8308 | |