Print this page
NEX-10223 Return of Fibre Channel ports stuck in offline state and unable to clear
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-4532 STC comstar FC test causes panic on 5.0
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
NEX-3856 panic is occurred in module "fct" due to a NULL pointer dereference
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
NEX-3277 Panic of both nodes in failover time (FC clients)
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-2787 Multiple comstar / fibre channel / qlt threads stuck waiting on locks with a spinning interrupt thread
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Approved by: Jean McCormack <jean.mccormack@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/comstar/port/fct/discovery.c
+++ new/usr/src/uts/common/io/comstar/port/fct/discovery.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
23 24 */
24 25
25 26 #include <sys/sysmacros.h>
26 27 #include <sys/conf.h>
27 28 #include <sys/file.h>
28 29 #include <sys/ddi.h>
29 30 #include <sys/sunddi.h>
30 31 #include <sys/modctl.h>
31 32 #include <sys/scsi/scsi.h>
32 33 #include <sys/scsi/impl/scsi_reset_notify.h>
33 34 #include <sys/disp.h>
34 35 #include <sys/byteorder.h>
35 36 #include <sys/varargs.h>
36 37 #include <sys/atomic.h>
37 38 #include <sys/sdt.h>
38 39
39 40 #include <sys/stmf.h>
40 41 #include <sys/stmf_ioctl.h>
41 42 #include <sys/portif.h>
42 43 #include <sys/fct.h>
43 44 #include <sys/fctio.h>
44 45
45 46 #include "fct_impl.h"
46 47 #include "discovery.h"
47 48
48 49 disc_action_t fct_handle_local_port_event(fct_i_local_port_t *iport);
49 50 disc_action_t fct_walk_discovery_queue(fct_i_local_port_t *iport);
50 51 disc_action_t fct_process_els(fct_i_local_port_t *iport,
51 52 fct_i_remote_port_t *irp);
52 53 fct_status_t fct_send_accrjt(fct_cmd_t *cmd, uint8_t accrjt,
53 54 uint8_t reason, uint8_t expl);
54 55 disc_action_t fct_link_init_complete(fct_i_local_port_t *iport);
55 56 fct_status_t fct_complete_previous_li_cmd(fct_i_local_port_t *iport);
56 57 fct_status_t fct_sol_plogi(fct_i_local_port_t *iport, uint32_t id,
57 58 fct_cmd_t **ret_ppcmd, int implicit);
58 59 fct_status_t fct_sol_ct(fct_i_local_port_t *iport, uint32_t id,
59 60 fct_cmd_t **ret_ppcmd, uint16_t opcode);
60 61 fct_status_t fct_ns_scr(fct_i_local_port_t *iport, uint32_t id,
61 62 fct_cmd_t **ret_ppcmd);
62 63 static disc_action_t fct_check_cmdlist(fct_i_local_port_t *iport);
63 64 static disc_action_t fct_check_solcmd_queue(fct_i_local_port_t *iport);
64 65 static void fct_rscn_verify(fct_i_local_port_t *iport,
65 66 uint8_t *rscn_req_payload, uint32_t rscn_req_size);
66 67 void fct_gid_cb(fct_i_cmd_t *icmd);
67 68
68 69 char *fct_els_names[] = { 0, "LS_RJT", "ACC", "PLOGI", "FLOGI", "LOGO",
69 70 "ABTX", "RCS", "RES", "RSS", "RSI", "ESTS",
70 71 "ESTC", "ADVC", "RTV", "RLS",
71 72 /* 0x10 */ "ECHO", "TEST", "RRQ", "REC", "SRR", 0, 0,
72 73 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 74 /* 0x20 */ "PRLI", "PRLO", "SCN", "TPLS",
74 75 "TPRLO", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75 76 /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76 77 /* 0x40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77 78 /* 0x50 */ "PDISC", "FDISC", "ADISC", "RNC", "FARP",
78 79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79 80 /* 0x60 */ "FAN", "RSCN", "SCR", 0, 0, 0, 0, 0, 0, 0, 0,
80 81 0, 0, 0, 0, 0,
81 82 /* 0x70 */ "LINIT", "LPC", "LSTS", 0, 0, 0, 0, 0,
82 83 "RNID", "RLIR", "LIRR", 0, 0, 0, 0, 0
83 84 };
84 85
85 86 extern uint32_t fct_rscn_options;
86 87
87 88 /*
88 89 * NOTE: if anybody drops the iport_worker_lock then they should not return
89 90 * DISC_ACTION_NO_WORK. Which also means, dont drop the lock if you have
90 91 * nothing to do. Or else return DISC_ACTION_RESCAN or DISC_ACTION_DELAY_RESCAN.
91 92 * But you cannot be infinitly returning those so have some logic to
92 93 * determine that there is nothing to do without dropping the lock.
93 94 */
94 95 void
95 96 fct_port_worker(void *arg)
96 97 {
97 98 fct_local_port_t *port = (fct_local_port_t *)arg;
98 99 fct_i_local_port_t *iport = (fct_i_local_port_t *)
99 100 port->port_fct_private;
100 101 disc_action_t suggested_action;
101 102 clock_t dl, short_delay, long_delay;
102 103 int64_t tmp_delay;
103 104
104 105 iport->iport_cmdcheck_clock = ddi_get_lbolt() +
105 106 drv_usectohz(FCT_CMDLIST_CHECK_SECONDS * 1000000);
106 107 short_delay = drv_usectohz(10000);
107 108 long_delay = drv_usectohz(1000000);
108 109
109 110 stmf_trace(iport->iport_alias, "iport is %p", iport);
110 111 /* Discovery loop */
111 112 mutex_enter(&iport->iport_worker_lock);
112 113 atomic_or_32(&iport->iport_flags, IPORT_WORKER_RUNNING);
113 114 while ((iport->iport_flags & IPORT_TERMINATE_WORKER) == 0) {
114 115 suggested_action = DISC_ACTION_NO_WORK;
115 116 /*
116 117 * Local port events are of the highest prioriy
117 118 */
118 119 if (iport->iport_event_head) {
119 120 suggested_action |= fct_handle_local_port_event(iport);
120 121 }
121 122
122 123 /*
123 124 * We could post solicited ELSes to discovery queue.
124 125 * solicited CT will be processed inside fct_check_solcmd_queue
125 126 */
126 127 if (iport->iport_solcmd_queue) {
127 128 suggested_action |= fct_check_solcmd_queue(iport);
128 129 }
129 130
130 131 /*
131 132 * All solicited and unsolicited ELS will be handled here
132 133 */
133 134 if (iport->iport_rpwe_head) {
134 135 suggested_action |= fct_walk_discovery_queue(iport);
135 136 }
136 137
137 138 /*
138 139 * We only process it when there's no outstanding link init CMD
|
↓ open down ↓ |
106 lines elided |
↑ open up ↑ |
139 140 */
140 141 if ((iport->iport_link_state == PORT_STATE_LINK_INIT_START) &&
141 142 !(iport->iport_li_state & (LI_STATE_FLAG_CMD_WAITING |
142 143 LI_STATE_FLAG_NO_LI_YET))) {
143 144 suggested_action |= fct_process_link_init(iport);
144 145 }
145 146
146 147 /*
147 148 * We process cmd aborting in the end
148 149 */
149 - if (iport->iport_abort_queue) {
150 + if (!list_is_empty(&iport->iport_abort_queue)) {
150 151 suggested_action |= fct_cmd_terminator(iport);
151 152 }
152 153
153 154 /*
154 155 * Check cmd max/free
155 156 */
156 157 if (iport->iport_cmdcheck_clock <= ddi_get_lbolt()) {
157 158 suggested_action |= fct_check_cmdlist(iport);
158 159 iport->iport_cmdcheck_clock = ddi_get_lbolt() +
159 160 drv_usectohz(FCT_CMDLIST_CHECK_SECONDS * 1000000);
160 161 iport->iport_max_active_ncmds = 0;
161 162 }
162 163
163 164 if (iport->iport_offline_prstate != FCT_OPR_DONE) {
164 165 suggested_action |= fct_handle_port_offline(iport);
165 166 }
166 167
167 168 if (suggested_action & DISC_ACTION_RESCAN) {
168 169 continue;
169 170 } else if (suggested_action & DISC_ACTION_DELAY_RESCAN) {
170 171 /*
171 172 * This is not very optimum as whoever returned
172 173 * DISC_ACTION_DELAY_RESCAN must have dropped the lock
173 174 * and more things might have queued up. But since
174 175 * we are only doing small delays, it only delays
175 176 * things by a few ms, which is okey.
176 177 */
177 178 if (suggested_action & DISC_ACTION_USE_SHORT_DELAY) {
178 179 dl = short_delay;
179 180 } else {
180 181 dl = long_delay;
181 182 }
182 183 atomic_or_32(&iport->iport_flags,
183 184 IPORT_WORKER_DOING_TIMEDWAIT);
184 185 (void) cv_reltimedwait(&iport->iport_worker_cv,
185 186 &iport->iport_worker_lock, dl, TR_CLOCK_TICK);
186 187 atomic_and_32(&iport->iport_flags,
187 188 ~IPORT_WORKER_DOING_TIMEDWAIT);
188 189 } else {
189 190 atomic_or_32(&iport->iport_flags,
190 191 IPORT_WORKER_DOING_WAIT);
191 192 tmp_delay = (int64_t)(iport->iport_cmdcheck_clock -
192 193 ddi_get_lbolt());
193 194 if (tmp_delay < 0) {
194 195 tmp_delay = (int64_t)short_delay;
195 196 }
196 197 (void) cv_reltimedwait(&iport->iport_worker_cv,
197 198 &iport->iport_worker_lock, (clock_t)tmp_delay,
198 199 TR_CLOCK_TICK);
199 200 atomic_and_32(&iport->iport_flags,
200 201 ~IPORT_WORKER_DOING_WAIT);
201 202 }
202 203 }
203 204
204 205 atomic_and_32(&iport->iport_flags, ~IPORT_WORKER_RUNNING);
205 206 mutex_exit(&iport->iport_worker_lock);
206 207 }
207 208
208 209 static char *topologies[] = { "Unknown", "Direct Pt-to-Pt", "Private Loop",
209 210 "Unknown", "Unknown", "Fabric Pt-to-Pt",
210 211 "Public Loop" };
211 212
212 213 void
213 214 fct_li_to_txt(fct_link_info_t *li, char *topology, char *speed)
214 215 {
215 216 uint8_t s = li->port_speed;
216 217
217 218 if (li->port_topology > PORT_TOPOLOGY_PUBLIC_LOOP) {
218 219 (void) sprintf(topology, "Invalid %02x", li->port_topology);
219 220 } else {
220 221 (void) strcpy(topology, topologies[li->port_topology]);
221 222 }
222 223
223 224 if ((s == 0) || ((s & 0xf00) != 0) || !ISP2(s)) {
224 225 speed[0] = '?';
225 226 } else if (s == PORT_SPEED_10G) {
226 227 speed[0] = '1';
227 228 speed[1] = '0';
228 229 speed[2] = 'G';
229 230 speed[3] = 0;
230 231 } else {
231 232 speed[0] = '0' + li->port_speed;
232 233 speed[1] = 'G';
233 234 speed[2] = 0;
234 235 }
235 236 }
236 237
237 238 /*
238 239 * discovery lock held.
239 240 * XXX: Implement command cleanup upon Link down.
240 241 * XXX: Implement a clean start and FC-GS registrations upon Link up.
241 242 *
242 243 * ================ Local Port State Machine ============
243 244 * <hba fatal> <Link up>---|
244 245 * | v
245 246 * | <Start>--->[LINK_DOWN]--->[LINK_INIT_START]--->[LINK_INIT_DONE]
246 247 * | ^ ^ ^ | |
247 248 * | |---| | |--<Link down> |-| |---><Link Reset><--|
248 249 * | | | v | v
249 250 * |->[FATAL_CLEANING] [LINK_DOWN_CLEANING]--->[LINK_UP_CLEANING]
250 251 * ^
251 252 * |--<Link up>
252 253 * =======================================================
253 254 * An explicit port_online() is only allowed in LINK_DOWN state.
254 255 * An explicit port_offline() is only allowed in LINKDOWN and
255 256 * LINK_INIT_DONE state.
256 257 */
257 258 disc_action_t
258 259 fct_handle_local_port_event(fct_i_local_port_t *iport)
259 260 {
260 261 disc_action_t ret = DISC_ACTION_RESCAN;
261 262 fct_i_event_t *in;
262 263 uint16_t old_state, new_state, new_bits;
263 264 int dqueue_and_free = 1;
264 265 int retry_implicit_logo = 0;
265 266
266 267 if (iport->iport_event_head == NULL)
267 268 return (DISC_ACTION_NO_WORK);
268 269 in = iport->iport_event_head;
269 270 mutex_exit(&iport->iport_worker_lock);
270 271
271 272 rw_enter(&iport->iport_lock, RW_WRITER);
272 273
273 274 if (in->event_type == FCT_EVENT_LINK_UP) {
274 275 DTRACE_FC_1(link__up, fct_i_local_port_t, iport);
275 276 } else if (in->event_type == FCT_EVENT_LINK_DOWN) {
276 277 DTRACE_FC_1(link__down, fct_i_local_port_t, iport);
277 278 }
278 279
279 280 /* Calculate new state */
280 281 new_state = iport->iport_link_state;
281 282
282 283 if (in->event_type == FCT_EVENT_LINK_DOWN) {
283 284 new_state = PORT_STATE_LINK_DOWN_CLEANING;
284 285 } else if (in->event_type == FCT_EVENT_LINK_UP) {
285 286 if (iport->iport_link_state == PORT_STATE_LINK_DOWN_CLEANING)
286 287 new_state = PORT_STATE_LINK_UP_CLEANING;
287 288 else if (iport->iport_link_state == PORT_STATE_LINK_DOWN)
288 289 new_state = PORT_STATE_LINK_INIT_START;
289 290 else { /* This should not happen */
290 291 stmf_trace(iport->iport_alias,
291 292 "Link up received when link state was"
292 293 "%x, Ignoring...", iport->iport_link_state);
293 294 }
294 295 } else if (in->event_type == FCT_I_EVENT_CLEANUP_POLL) {
295 296 if (!fct_local_port_cleanup_done(iport)) {
296 297 if (iport->iport_link_cleanup_retry >= 3) {
297 298 iport->iport_link_cleanup_retry = 0;
298 299 retry_implicit_logo = 1;
299 300 } else {
300 301 iport->iport_link_cleanup_retry++;
301 302 }
302 303 dqueue_and_free = 0;
303 304 ret = DISC_ACTION_DELAY_RESCAN;
304 305 } else {
305 306 if (iport->iport_link_state ==
306 307 PORT_STATE_LINK_DOWN_CLEANING) {
307 308 new_state = PORT_STATE_LINK_DOWN;
308 309 } else if (iport->iport_link_state ==
309 310 PORT_STATE_LINK_UP_CLEANING) {
310 311 new_state = PORT_STATE_LINK_INIT_START;
311 312 } else { /* This should not have happened */
312 313 cmn_err(CE_WARN, "port state changed to %x "
313 314 "during cleanup", iport->iport_link_state);
314 315 new_state = PORT_STATE_LINK_DOWN;
315 316 }
316 317 }
317 318 } else if (in->event_type == FCT_EVENT_LINK_RESET) {
318 319 /* Link reset is only allowed when we are Online */
319 320 if (iport->iport_link_state & S_LINK_ONLINE) {
320 321 new_state = PORT_STATE_LINK_UP_CLEANING;
321 322 }
322 323 } else if (in->event_type == FCT_I_EVENT_LINK_INIT_DONE) {
323 324 if (iport->iport_link_state == PORT_STATE_LINK_INIT_START) {
324 325 new_state = PORT_STATE_LINK_INIT_DONE;
325 326 iport->iport_li_state = LI_STATE_START;
326 327 }
327 328 } else {
328 329 ASSERT(0);
329 330 }
330 331 new_bits = iport->iport_link_state ^
331 332 (iport->iport_link_state | new_state);
332 333 old_state = iport->iport_link_state;
333 334 iport->iport_link_state = new_state;
334 335 rw_exit(&iport->iport_lock);
335 336
336 337 stmf_trace(iport->iport_alias, "port state change from %x to %x",
337 338 old_state, new_state);
338 339
339 340 if (new_bits & S_PORT_CLEANUP) {
340 341 (void) fct_implicitly_logo_all(iport, 0);
341 342 fct_handle_event(iport->iport_port,
342 343 FCT_I_EVENT_CLEANUP_POLL, 0, 0);
343 344 }
344 345 if (retry_implicit_logo) {
345 346 (void) fct_implicitly_logo_all(iport, 1);
346 347 }
347 348 if (new_bits & S_INIT_LINK) {
348 349 fct_link_info_t *li = &iport->iport_link_info;
349 350 fct_status_t li_ret;
350 351 iport->iport_li_state |= LI_STATE_FLAG_NO_LI_YET;
351 352 bzero(li, sizeof (*li));
352 353 if ((li_ret = iport->iport_port->port_get_link_info(
353 354 iport->iport_port, li)) != FCT_SUCCESS) {
354 355 stmf_trace(iport->iport_alias, "iport-%p: "
355 356 "port_get_link_info failed, ret %llx, forcing "
356 357 "link down.", iport, li_ret);
357 358 fct_handle_event(iport->iport_port,
358 359 FCT_EVENT_LINK_DOWN, 0, 0);
359 360 } else {
360 361 iport->iport_login_retry = 0;
361 362 /* This will reset LI_STATE_FLAG_NO_LI_YET */
362 363 iport->iport_li_state = LI_STATE_START;
363 364 atomic_or_32(&iport->iport_flags,
364 365 IPORT_ALLOW_UNSOL_FLOGI);
365 366 }
366 367 fct_log_local_port_event(iport->iport_port,
367 368 ESC_SUNFC_PORT_ONLINE);
368 369 } else if (new_bits & S_RCVD_LINK_DOWN) {
369 370 fct_log_local_port_event(iport->iport_port,
370 371 ESC_SUNFC_PORT_OFFLINE);
371 372 }
372 373
373 374 mutex_enter(&iport->iport_worker_lock);
374 375 if (in && dqueue_and_free) {
375 376 iport->iport_event_head = in->event_next;
376 377 if (iport->iport_event_head == NULL)
377 378 iport->iport_event_tail = NULL;
378 379 kmem_free(in, sizeof (*in));
379 380 }
380 381 return (ret);
381 382 }
382 383
383 384 int
384 385 fct_lport_has_bigger_wwn(fct_i_local_port_t *iport)
385 386 {
386 387 uint8_t *l, *r;
387 388 int i;
388 389 uint64_t wl, wr;
389 390
390 391 l = iport->iport_port->port_pwwn;
391 392 r = iport->iport_link_info.port_rpwwn;
392 393
393 394 for (i = 0, wl = 0; i < 8; i++) {
394 395 wl <<= 8;
395 396 wl |= l[i];
396 397 }
397 398 for (i = 0, wr = 0; i < 8; i++) {
398 399 wr <<= 8;
399 400 wr |= r[i];
400 401 }
401 402
402 403 if (wl > wr) {
403 404 return (1);
404 405 }
405 406
406 407 return (0);
407 408 }
408 409
409 410 void
410 411 fct_do_flogi(fct_i_local_port_t *iport)
411 412 {
412 413 fct_flogi_xchg_t fx;
413 414 fct_status_t ret;
414 415 int force_link_down = 0;
415 416 int do_retry = 0;
416 417
417 418 DTRACE_FC_1(fabric__login__start, fct_i_local_port_t, iport);
418 419
419 420 bzero(&fx, sizeof (fx));
420 421 fx.fx_op = ELS_OP_FLOGI;
421 422 if (iport->iport_login_retry == 0) {
422 423 fx.fx_sec_timeout = 2;
423 424 } else {
424 425 fx.fx_sec_timeout = 5;
425 426 }
426 427 if (iport->iport_link_info.port_topology & PORT_TOPOLOGY_PRIVATE_LOOP) {
427 428 fx.fx_sid = iport->iport_link_info.portid & 0xFF;
428 429 }
429 430 fx.fx_did = 0xFFFFFE;
430 431 bcopy(iport->iport_port->port_nwwn, fx.fx_nwwn, 8);
431 432 bcopy(iport->iport_port->port_pwwn, fx.fx_pwwn, 8);
432 433 mutex_exit(&iport->iport_worker_lock);
433 434 ret = iport->iport_port->port_flogi_xchg(iport->iport_port, &fx);
434 435 mutex_enter(&iport->iport_worker_lock);
435 436 if (IPORT_FLOGI_DONE(iport)) {
436 437 /* The unsolicited path finished it. */
437 438 goto done;
438 439 }
439 440 if (ret == FCT_NOT_FOUND) {
440 441 if (iport->iport_link_info.port_topology &
441 442 PORT_TOPOLOGY_PRIVATE_LOOP) {
442 443 /* This is a private loop. There is no switch. */
443 444 iport->iport_link_info.port_no_fct_flogi = 1;
444 445 goto done;
445 446 }
446 447 /*
447 448 * This is really an error. This means we cannot init the
448 449 * link. Lets force the link to go down.
449 450 */
450 451 force_link_down = 1;
451 452 } else if ((ret == FCT_SUCCESS) && (fx.fx_op == ELS_OP_LSRJT)) {
452 453 if ((fx.fx_rjt_reason == 5) || (fx.fx_rjt_reason == 0xe) ||
453 454 ((fx.fx_rjt_reason == 9) && (fx.fx_rjt_expl == 0x29))) {
454 455 do_retry = 1;
455 456 } else {
456 457 force_link_down = 1;
457 458 }
458 459 } else if (ret == STMF_TIMEOUT) {
459 460 do_retry = 1;
460 461 } else if (ret != FCT_SUCCESS) {
461 462 force_link_down = 1;
462 463 }
463 464
464 465 if (do_retry) {
465 466 iport->iport_login_retry++;
466 467 if (iport->iport_login_retry >= 5)
467 468 force_link_down = 1;
468 469 goto done;
469 470 }
470 471
471 472 if (force_link_down) {
472 473 stmf_trace(iport->iport_alias, "iport-%p: flogi xchg failed. "
473 474 "Forcing link down, ret=%llx login_retry=%d ret_op=%d "
474 475 "reason=%d expl=%d", iport, ret, iport->iport_login_retry,
475 476 fx.fx_op, fx.fx_rjt_reason, fx.fx_rjt_expl);
476 477 mutex_exit(&iport->iport_worker_lock);
477 478 fct_handle_event(iport->iport_port, FCT_EVENT_LINK_DOWN, 0, 0);
478 479 mutex_enter(&iport->iport_worker_lock);
479 480 goto done;
480 481 }
481 482
482 483 /* FLOGI succeeded. Update local port state */
483 484 ASSERT(fx.fx_op == ELS_OP_ACC);
484 485 bcopy(fx.fx_nwwn, iport->iport_link_info.port_rnwwn, 8);
485 486 bcopy(fx.fx_pwwn, iport->iport_link_info.port_rpwwn, 8);
486 487 if (fx.fx_fport) {
487 488 iport->iport_link_info.port_topology |=
488 489 PORT_TOPOLOGY_FABRIC_BIT;
489 490 iport->iport_link_info.portid = fx.fx_did;
490 491 }
491 492 iport->iport_link_info.port_fct_flogi_done = 1;
492 493
493 494 done:
494 495 DTRACE_FC_1(fabric__login__end,
495 496 fct_i_local_port_t, iport);
496 497 }
497 498
498 499 /*
499 500 * Called by FCAs to handle unsolicited FLOGIs.
500 501 */
501 502 fct_status_t
502 503 fct_handle_rcvd_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx)
503 504 {
504 505 fct_i_local_port_t *iport;
505 506 uint32_t t;
506 507
507 508 iport = (fct_i_local_port_t *)port->port_fct_private;
508 509 if ((iport->iport_flags & IPORT_ALLOW_UNSOL_FLOGI) == 0) {
509 510 return (FCT_FAILURE);
510 511 }
511 512
512 513 mutex_enter(&iport->iport_worker_lock);
513 514 if (((iport->iport_flags & IPORT_ALLOW_UNSOL_FLOGI) == 0) ||
514 515 (iport->iport_link_state != PORT_STATE_LINK_INIT_START) ||
515 516 ((iport->iport_li_state & LI_STATE_MASK) > LI_STATE_N2N_PLOGI)) {
516 517 mutex_exit(&iport->iport_worker_lock);
517 518 return (FCT_FAILURE);
518 519 }
519 520
520 521 if (iport->iport_link_info.port_fct_flogi_done == 0) {
521 522 iport->iport_link_info.port_fct_flogi_done = 1;
522 523 bcopy(fx->fx_pwwn, iport->iport_link_info.port_rpwwn, 8);
523 524 bcopy(fx->fx_nwwn, iport->iport_link_info.port_rnwwn, 8);
524 525 }
525 526
526 527 fx->fx_op = ELS_OP_ACC;
527 528 t = fx->fx_sid;
528 529 fx->fx_sid = fx->fx_did;
529 530 fx->fx_did = t;
530 531 bcopy(iport->iport_port->port_pwwn, fx->fx_pwwn, 8);
531 532 bcopy(iport->iport_port->port_nwwn, fx->fx_nwwn, 8);
532 533 mutex_exit(&iport->iport_worker_lock);
533 534
534 535 return (FCT_SUCCESS);
535 536 }
536 537
537 538 /*
538 539 * iport_li_state can only be changed here and local_event
539 540 */
540 541 disc_action_t
541 542 fct_process_link_init(fct_i_local_port_t *iport)
542 543 {
543 544 fct_cmd_t *cmd = NULL;
544 545 char *pname = NULL;
545 546 uint8_t elsop = 0;
546 547 uint16_t ctop = 0;
547 548 uint32_t wkdid = 0;
548 549 int implicit = 0;
549 550 int force_login = 0;
550 551 disc_action_t ret = DISC_ACTION_RESCAN;
551 552 fct_link_info_t *li = &iport->iport_link_info;
552 553 char topo[24], speed[4];
553 554
554 555 ASSERT(MUTEX_HELD(&iport->iport_worker_lock));
555 556
556 557 check_state_again:
557 558 switch (iport->iport_li_state & LI_STATE_MASK) {
558 559 case LI_STATE_DO_FLOGI:
559 560 /* Is FLOGI even needed or already done ? */
560 561 if ((iport->iport_link_info.port_no_fct_flogi) ||
561 562 (IPORT_FLOGI_DONE(iport))) {
562 563 iport->iport_li_state++;
563 564 goto check_state_again;
564 565 }
565 566 fct_do_flogi(iport);
566 567 break;
567 568
568 569 case LI_STATE_FINI_TOPOLOGY:
569 570 fct_li_to_txt(li, topo, speed);
570 571 cmn_err(CE_NOTE, "%s LINK UP, portid %x, topology %s,"
571 572 "speed %s", iport->iport_alias, li->portid,
572 573 topo, speed);
573 574 if (li->port_topology !=
574 575 iport->iport_link_old_topology) {
575 576 if (iport->iport_nrps) {
576 577 /*
577 578 * rehash it if change from fabric to
578 579 * none fabric, vice versa
579 580 */
580 581 if ((li->port_topology ^
581 582 iport->iport_link_old_topology) &
582 583 PORT_TOPOLOGY_FABRIC_BIT) {
583 584 mutex_exit(&iport->iport_worker_lock);
584 585 fct_rehash(iport);
585 586 mutex_enter(&iport->iport_worker_lock);
586 587 }
587 588 }
588 589 iport->iport_link_old_topology = li->port_topology;
589 590 }
590 591 /* Skip next level if topo is not N2N */
591 592 if (li->port_topology != PORT_TOPOLOGY_PT_TO_PT) {
592 593 iport->iport_li_state += 2;
593 594 atomic_and_32(&iport->iport_flags,
594 595 ~IPORT_ALLOW_UNSOL_FLOGI);
595 596 } else {
596 597 iport->iport_li_state++;
597 598 iport->iport_login_retry = 0;
598 599 iport->iport_li_cmd_timeout = ddi_get_lbolt() +
599 600 drv_usectohz(25 * 1000000);
600 601 }
601 602 goto check_state_again;
602 603
603 604 case LI_STATE_N2N_PLOGI:
604 605 ASSERT(IPORT_FLOGI_DONE(iport));
605 606 ASSERT(iport->iport_link_info.port_topology ==
606 607 PORT_TOPOLOGY_PT_TO_PT);
607 608 if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) {
608 609 iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK;
609 610 if (iport->iport_li_comp_status != FCT_SUCCESS) {
610 611 iport->iport_login_retry++;
611 612 if (iport->iport_login_retry >= 3) {
612 613 stmf_trace(iport->iport_alias, "Failing"
613 614 " to PLOGI to remote port in N2N "
|
↓ open down ↓ |
454 lines elided |
↑ open up ↑ |
614 615 " ret=%llx, forcing link down",
615 616 iport->iport_li_comp_status);
616 617 mutex_exit(&iport->iport_worker_lock);
617 618 fct_handle_event(iport->iport_port,
618 619 FCT_EVENT_LINK_DOWN, 0, 0);
619 620 mutex_enter(&iport->iport_worker_lock);
620 621 }
621 622 }
622 623 }
623 624 /* Find out if we need to do PLOGI at all */
625 + rw_enter(&iport->iport_lock, RW_READER);
624 626 if (iport->iport_nrps_login) {
625 627 iport->iport_li_state++;
626 628 atomic_and_32(&iport->iport_flags,
627 629 ~IPORT_ALLOW_UNSOL_FLOGI);
630 + rw_exit(&iport->iport_lock);
628 631 goto check_state_again;
632 + } else {
633 + rw_exit(&iport->iport_lock);
629 634 }
630 635 if ((ddi_get_lbolt() >= iport->iport_li_cmd_timeout) &&
631 636 (!fct_lport_has_bigger_wwn(iport))) {
632 637 /* Cant wait forever */
633 638 stmf_trace(iport->iport_alias, "N2N: Remote port is "
634 639 "not logging in, forcing from our side");
635 640 force_login = 1;
636 641 } else {
637 642 force_login = 0;
638 643 }
639 644 if (force_login || fct_lport_has_bigger_wwn(iport)) {
640 645 elsop = ELS_OP_PLOGI;
641 646 wkdid = 1;
642 647 iport->iport_link_info.portid = 0xEF;
643 648 implicit = 0;
644 649 iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK;
645 650 } else {
646 651 ret = DISC_ACTION_DELAY_RESCAN;
647 652 }
648 653 break;
649 654
650 655 case LI_STATE_DO_FCLOGIN:
651 656 if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) {
652 657 iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK;
653 658 if (iport->iport_li_comp_status != FCT_SUCCESS) {
654 659 /*
655 660 * Fabric controller login failed. Just skip all
656 661 * the fabric controller related cmds.
657 662 */
658 663 iport->iport_li_state = LI_STATE_DO_SCR + 1;
659 664 } else {
660 665 /*
661 666 * Good. Now lets go to next state
662 667 */
663 668 iport->iport_li_state++;
664 669 }
665 670 goto check_state_again;
666 671 }
667 672 if (!IPORT_IN_NS_TOPO(iport)) {
668 673 iport->iport_li_state = LI_STATE_DO_SCR + 1;
669 674 goto check_state_again;
670 675 }
671 676
672 677 elsop = ELS_OP_PLOGI;
673 678 wkdid = FS_FABRIC_CONTROLLER;
674 679 implicit = 1;
675 680
676 681 /*
677 682 * We want to come back in the same state and check its ret
678 683 * We can't modify the state here
679 684 */
680 685 iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK;
681 686 break;
682 687
683 688 case LI_STATE_DO_SCR:
684 689 elsop = ELS_OP_SCR;
685 690 wkdid = FS_FABRIC_CONTROLLER;
686 691
687 692 /*
688 693 * We dont care about success of this state. Just go to
689 694 * next state upon completion.
690 695 */
691 696 iport->iport_li_state++;
692 697 break;
693 698
694 699 case LI_STATE_DO_NSLOGIN:
695 700 if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) {
696 701 iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK;
697 702 if (iport->iport_li_comp_status != FCT_SUCCESS) {
698 703 iport->iport_li_state = LI_STATE_DO_RSNN + 1;
699 704 } else {
700 705 iport->iport_li_state++;
701 706 }
702 707 goto check_state_again;
703 708 }
704 709
705 710 if (!IPORT_IN_NS_TOPO(iport)) {
706 711 iport->iport_li_state = LI_STATE_DO_RSNN + 1;
707 712 goto check_state_again;
708 713 }
709 714
710 715 elsop = ELS_OP_PLOGI;
711 716 wkdid = FS_NAME_SERVER;
712 717 iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK;
713 718 break;
714 719
715 720 /*
716 721 * CT state
717 722 */
718 723 case LI_STATE_DO_RNN:
719 724 ctop = NS_RNN_ID;
720 725 iport->iport_li_state++;
721 726 break;
722 727
723 728 case LI_STATE_DO_RCS:
724 729 ctop = NS_RCS_ID;
725 730 iport->iport_li_state++;
726 731 break;
727 732
728 733 case LI_STATE_DO_RFT:
729 734 ctop = NS_RFT_ID;
730 735 iport->iport_li_state++;
731 736 break;
732 737
733 738 case LI_STATE_DO_RSPN:
734 739 /*
735 740 * Check if we need skip the state
736 741 */
737 742 pname = iport->iport_port->port_sym_port_name !=
738 743 NULL ? iport->iport_port->port_sym_port_name : NULL;
739 744 if (pname == NULL) {
740 745 pname = iport->iport_port->port_default_alias !=
741 746 NULL ? iport->iport_port->port_default_alias : NULL;
742 747 iport->iport_port->port_sym_port_name = pname;
743 748 }
744 749
745 750 if (pname == NULL) {
746 751 iport->iport_li_state++;
747 752 goto check_state_again;
748 753 }
749 754
750 755 ctop = NS_RSPN_ID;
751 756 iport->iport_li_state++;
752 757 break;
753 758
754 759 case LI_STATE_DO_RSNN:
755 760 ctop = NS_RSNN_NN;
756 761 iport->iport_li_state++;
757 762 break;
758 763
759 764 case LI_STATE_MAX:
760 765 mutex_exit(&iport->iport_worker_lock);
761 766
762 767 fct_handle_event(iport->iport_port,
763 768 FCT_I_EVENT_LINK_INIT_DONE, 0, 0);
764 769
765 770 mutex_enter(&iport->iport_worker_lock);
766 771 break;
767 772
768 773 default:
769 774 ASSERT(0);
770 775 }
771 776
772 777 if (elsop != 0) {
773 778 cmd = fct_create_solels(iport->iport_port, NULL, implicit,
774 779 elsop, wkdid, fct_link_init_cb);
775 780 } else if (ctop != 0) {
776 781 cmd = fct_create_solct(iport->iport_port, NULL, ctop,
777 782 fct_link_init_cb);
778 783 }
779 784
780 785 if (cmd) {
781 786 iport->iport_li_state |= LI_STATE_FLAG_CMD_WAITING;
782 787 mutex_exit(&iport->iport_worker_lock);
783 788
784 789 fct_post_to_solcmd_queue(iport->iport_port, cmd);
785 790
786 791 mutex_enter(&iport->iport_worker_lock);
787 792 }
788 793
789 794 return (ret);
790 795 }
791 796
792 797 /*
793 798 * Handles both solicited and unsolicited elses. Can be called inside
794 799 * interrupt context.
795 800 */
796 801 void
797 802 fct_handle_els(fct_cmd_t *cmd)
798 803 {
799 804 fct_local_port_t *port = cmd->cmd_port;
800 805 fct_i_local_port_t *iport =
801 806 (fct_i_local_port_t *)port->port_fct_private;
802 807 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
803 808 fct_els_t *els = (fct_els_t *)cmd->cmd_specific;
804 809 fct_remote_port_t *rp;
805 810 fct_i_remote_port_t *irp;
806 811 uint16_t cmd_slot;
807 812 uint8_t op;
808 813
809 814 op = els->els_req_payload[0];
810 815 icmd->icmd_start_time = ddi_get_lbolt();
811 816 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
812 817 icmd->icmd_flags |= ICMD_KNOWN_TO_FCA;
813 818 }
814 819 stmf_trace(iport->iport_alias, "Posting %ssol ELS %x (%s) rp_id=%x"
815 820 " lp_id=%x", (cmd->cmd_type == FCT_CMD_RCVD_ELS) ? "un" : "",
816 821 op, FCT_ELS_NAME(op), cmd->cmd_rportid,
817 822 cmd->cmd_lportid);
818 823
819 824 rw_enter(&iport->iport_lock, RW_READER);
820 825 start_els_posting:;
821 826 /* Make sure local port is sane */
822 827 if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
823 828 rw_exit(&iport->iport_lock);
824 829 stmf_trace(iport->iport_alias, "ELS %x not posted becasue"
825 830 "port state was %x", els->els_req_payload[0],
826 831 iport->iport_link_state);
827 832 fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
828 833 return;
829 834 }
830 835
831 836 /* Weed out any bad initiators in case of N2N topology */
832 837 if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
833 838 (els->els_req_payload[0] == ELS_OP_PLOGI) &&
834 839 (iport->iport_link_state == PORT_STATE_LINK_INIT_START) &&
835 840 (iport->iport_link_info.port_topology == PORT_TOPOLOGY_PT_TO_PT)) {
836 841 int state;
837 842 int killit = 0;
838 843
839 844 mutex_enter(&iport->iport_worker_lock);
840 845 state = iport->iport_li_state & LI_STATE_MASK;
841 846 /*
842 847 * We dont allow remote port to plogi in N2N if we have not yet
843 848 * resolved the topology.
844 849 */
845 850 if (state <= LI_STATE_FINI_TOPOLOGY) {
846 851 killit = 1;
847 852 stmf_trace(iport->iport_alias, "port %x is trying to "
848 853 "PLOGI in N2N topology, While we have not resolved"
849 854 " the topology. Dropping...", cmd->cmd_rportid);
850 855 } else if (state <= LI_STATE_N2N_PLOGI) {
851 856 if (fct_lport_has_bigger_wwn(iport)) {
852 857 killit = 1;
853 858 stmf_trace(iport->iport_alias, "port %x is "
854 859 "trying to PLOGI in N2N topology, even "
855 860 "though it has smaller PWWN",
856 861 cmd->cmd_rportid);
857 862 } else {
858 863 /*
859 864 * Remote port is assigning us a PORTID as
860 865 * a part of PLOGI.
861 866 */
862 867 iport->iport_link_info.portid =
863 868 cmd->cmd_lportid;
864 869 }
865 870 }
866 871 mutex_exit(&iport->iport_worker_lock);
867 872 if (killit) {
868 873 rw_exit(&iport->iport_lock);
869 874 fct_queue_cmd_for_termination(cmd,
870 875 FCT_LOCAL_PORT_OFFLINE);
871 876 return;
872 877 }
873 878 }
874 879
875 880 /*
876 881 * For all unsolicited ELSes that are not FLOGIs, our portid
877 882 * has been established by now. Sometimes port IDs change due to
878 883 * link resets but remote ports may still send ELSes using the
879 884 * old IDs. Kill those right here.
880 885 */
881 886 if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
882 887 (els->els_req_payload[0] != ELS_OP_FLOGI)) {
883 888 if (cmd->cmd_lportid != iport->iport_link_info.portid) {
884 889 rw_exit(&iport->iport_lock);
885 890 stmf_trace(iport->iport_alias, "Rcvd %s with "
886 891 "wrong lportid %x, expecting %x. Killing ELS.",
887 892 FCT_ELS_NAME(op), cmd->cmd_lportid,
888 893 iport->iport_link_info.portid);
889 894 fct_queue_cmd_for_termination(cmd,
890 895 FCT_NOT_FOUND);
891 896 return;
892 897 }
893 898 }
894 899
895 900 /*
896 901 * We always lookup by portid. port handles are too
897 902 * unreliable at this stage.
898 903 */
899 904 irp = fct_portid_to_portptr(iport, cmd->cmd_rportid);
900 905 if (els->els_req_payload[0] == ELS_OP_PLOGI) {
901 906 if (irp == NULL) {
|
↓ open down ↓ |
263 lines elided |
↑ open up ↑ |
902 907 /* drop the lock while we do allocations */
903 908 rw_exit(&iport->iport_lock);
904 909 rp = fct_alloc(FCT_STRUCT_REMOTE_PORT,
905 910 port->port_fca_rp_private_size, 0);
906 911 if (rp == NULL) {
907 912 fct_queue_cmd_for_termination(cmd,
908 913 FCT_ALLOC_FAILURE);
909 914 return;
910 915 }
911 916 irp = (fct_i_remote_port_t *)rp->rp_fct_private;
917 + list_create(&irp->irp_els_list, sizeof (fct_i_cmd_t),
918 + offsetof(fct_i_cmd_t, icmd_node));
912 919 rw_init(&irp->irp_lock, 0, RW_DRIVER, 0);
913 920 irp->irp_rp = rp;
914 921 irp->irp_portid = cmd->cmd_rportid;
915 922 rp->rp_port = port;
916 923 rp->rp_id = cmd->cmd_rportid;
917 924 rp->rp_handle = FCT_HANDLE_NONE;
918 925 /*
919 926 * Grab port lock as writer since we are going
920 927 * to modify the local port struct.
921 928 */
922 929 rw_enter(&iport->iport_lock, RW_WRITER);
923 930 /* Make sure nobody created the struct except us */
924 931 if (fct_portid_to_portptr(iport, cmd->cmd_rportid)) {
925 932 /* Oh well, free it */
926 933 fct_free(rp);
927 934 } else {
928 935 fct_queue_rp(iport, irp);
929 936 }
930 937 rw_downgrade(&iport->iport_lock);
931 938 /* Start over becasue we dropped the lock */
932 939 goto start_els_posting;
933 940 }
934 941
935 942 /* A PLOGI is by default a logout of previous session */
936 943 irp->irp_deregister_timer = ddi_get_lbolt() +
937 944 drv_usectohz(USEC_DEREG_RP_TIMEOUT);
938 945 irp->irp_dereg_count = 0;
939 946 fct_post_to_discovery_queue(iport, irp, NULL);
940 947
941 948 /* A PLOGI also invalidates any RSCNs related to this rp */
942 949 atomic_inc_32(&irp->irp_rscn_counter);
943 950 } else {
944 951 /*
945 952 * For everything else, we have (or be able to lookup) a
946 953 * valid port pointer.
947 954 */
948 955 if (irp == NULL) {
949 956 rw_exit(&iport->iport_lock);
950 957 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
951 958 /* XXX Throw a logout to the initiator */
952 959 stmf_trace(iport->iport_alias, "ELS %x "
953 960 "received from %x without a session",
954 961 els->els_req_payload[0], cmd->cmd_rportid);
955 962 } else {
956 963 stmf_trace(iport->iport_alias, "Sending ELS %x "
957 964 "to %x without a session",
958 965 els->els_req_payload[0], cmd->cmd_rportid);
959 966 }
960 967 fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
961 968 return;
962 969 }
963 970 }
964 971 cmd->cmd_rp = rp = irp->irp_rp;
965 972
966 973 /*
967 974 * Lets get a slot for this els
968 975 */
969 976 if (!(icmd->icmd_flags & ICMD_IMPLICIT)) {
970 977 cmd_slot = fct_alloc_cmd_slot(iport, cmd);
971 978 if (cmd_slot == FCT_SLOT_EOL) {
972 979 /* This should not have happened */
973 980 rw_exit(&iport->iport_lock);
974 981 stmf_trace(iport->iport_alias,
975 982 "ran out of xchg resources");
976 983 fct_queue_cmd_for_termination(cmd,
977 984 FCT_NO_XCHG_RESOURCE);
978 985 return;
979 986 }
|
↓ open down ↓ |
58 lines elided |
↑ open up ↑ |
980 987 } else {
981 988 /*
982 989 * Tell the framework that fct_cmd_free() can decrement the
983 990 * irp_nonfcp_xchg_count variable.
984 991 */
985 992 atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE);
986 993 }
987 994 atomic_inc_16(&irp->irp_nonfcp_xchg_count);
988 995
989 996 /*
997 + * The iport_lock is currently held as a Reader lock, protocol
998 + * dictates that to modify iport_nrps_login the lock must be held
999 + * as a Writer.
1000 + */
1001 + rw_exit(&iport->iport_lock);
1002 + rw_enter(&iport->iport_lock, RW_WRITER);
1003 +
1004 + /*
990 1005 * Grab the remote port lock while we modify the port state.
991 1006 * we should not drop the fca port lock (as a reader) until we
992 1007 * modify the remote port state.
993 1008 */
994 1009 rw_enter(&irp->irp_lock, RW_WRITER);
995 1010 if ((op == ELS_OP_PLOGI) || (op == ELS_OP_PRLI) ||
996 1011 (op == ELS_OP_LOGO) || (op == ELS_OP_PRLO) ||
997 1012 (op == ELS_OP_TPRLO)) {
998 1013 uint32_t rf = IRP_PRLI_DONE;
999 1014 if ((op == ELS_OP_PLOGI) || (op == ELS_OP_LOGO)) {
1000 1015 rf |= IRP_PLOGI_DONE;
1001 1016 if (irp->irp_flags & IRP_PLOGI_DONE)
1002 1017 atomic_dec_32(&iport->iport_nrps_login);
1003 1018 }
1004 1019 atomic_inc_16(&irp->irp_sa_elses_count);
1005 1020 atomic_and_32(&irp->irp_flags, ~rf);
1006 1021 atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING);
1007 1022 } else {
1008 1023 atomic_inc_16(&irp->irp_nsa_elses_count);
1009 1024 }
1010 1025
1011 1026 fct_post_to_discovery_queue(iport, irp, icmd);
1012 1027
1013 1028 rw_exit(&irp->irp_lock);
1014 1029 rw_exit(&iport->iport_lock);
1015 1030 }
1016 1031
1017 1032 /*
1018 1033 * Cleanup I/Os for a rport. ttc is a bit Mask of cmd types to clean.
1019 1034 * No locks held.
1020 1035 */
1021 1036 int
1022 1037 fct_trigger_rport_cleanup(fct_i_remote_port_t *irp, int ttc)
1023 1038 {
1024 1039 fct_remote_port_t *rp = irp->irp_rp;
1025 1040 fct_local_port_t *port = rp->rp_port;
1026 1041 fct_i_local_port_t *iport =
1027 1042 (fct_i_local_port_t *)port->port_fct_private;
1028 1043 fct_cmd_t *cmd;
1029 1044 fct_i_cmd_t *icmd;
1030 1045 int i;
1031 1046 int ret;
1032 1047 uint16_t total, cleaned, skipped, unhandled;
1033 1048
1034 1049 rw_enter(&iport->iport_lock, RW_WRITER);
1035 1050 rw_enter(&irp->irp_lock, RW_WRITER);
1036 1051 mutex_enter(&iport->iport_worker_lock);
1037 1052 total = port->port_max_xchges - iport->iport_nslots_free;
1038 1053 cleaned = skipped = unhandled = 0;
1039 1054
1040 1055 for (i = 0; i < port->port_max_xchges; i++) {
1041 1056 if (iport->iport_cmd_slots[i].slot_cmd == NULL)
1042 1057 continue;
1043 1058 icmd = iport->iport_cmd_slots[i].slot_cmd;
1044 1059 if (icmd->icmd_flags & ICMD_IN_TRANSITION) {
1045 1060 unhandled++;
1046 1061 continue;
1047 1062 }
1048 1063
1049 1064 if (icmd->icmd_flags & ICMD_CMD_COMPLETE) {
|
↓ open down ↓ |
50 lines elided |
↑ open up ↑ |
1050 1065 unhandled++;
1051 1066 continue;
1052 1067 }
1053 1068
1054 1069 cmd = icmd->icmd_cmd;
1055 1070 if (cmd->cmd_rp != rp) {
1056 1071 skipped++;
1057 1072 continue;
1058 1073 }
1059 1074 if (cmd->cmd_type & ttc) {
1060 - if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
1075 + if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
1061 1076 fct_queue_scsi_task_for_termination(cmd,
1062 1077 FCT_ABORTED);
1063 - else
1078 + } else {
1079 + fct_cmd_unlink_els(irp, icmd);
1064 1080 fct_q_for_termination_lock_held(iport, icmd,
1065 1081 FCT_ABORTED);
1082 + }
1066 1083 cleaned++;
1067 1084 } else {
1068 1085 skipped++;
1069 1086 }
1070 1087 }
1071 1088 if (((cleaned + skipped) == total) && (unhandled == 0)) {
1072 1089 ret = 1;
1073 1090 } else {
1074 1091 /*
1075 1092 * XXX: handle this situation.
1076 1093 */
1077 1094 stmf_trace(iport->iport_alias, "Clean up trouble for irp"
1078 1095 " %p, c/s/u/t = %d/%d/%d/%d", irp, cleaned, skipped,
1079 1096 unhandled, total);
1080 1097 ret = 0;
1081 1098 }
1082 1099 if ((cleaned) && IS_WORKER_SLEEPING(iport))
1083 1100 cv_signal(&iport->iport_worker_cv);
1084 1101 mutex_exit(&iport->iport_worker_lock);
1085 1102 rw_exit(&irp->irp_lock);
|
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
1086 1103 rw_exit(&iport->iport_lock);
1087 1104 return (ret);
1088 1105 }
1089 1106
1090 1107 void
1091 1108 fct_dequeue_els(fct_i_remote_port_t *irp)
1092 1109 {
1093 1110 fct_i_cmd_t *icmd;
1094 1111
1095 1112 rw_enter(&irp->irp_lock, RW_WRITER);
1096 - icmd = irp->irp_els_list;
1097 - irp->irp_els_list = icmd->icmd_next;
1113 + icmd = list_remove_head(&irp->irp_els_list);
1098 1114 atomic_and_32(&icmd->icmd_flags, ~ICMD_IN_IRP_QUEUE);
1099 1115 rw_exit(&irp->irp_lock);
1100 1116 }
1101 1117
1102 1118 fct_status_t
1103 1119 fct_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp,
1104 1120 fct_cmd_t *cmd)
1105 1121 {
1106 1122 fct_status_t ret;
1107 1123 fct_i_local_port_t *iport;
1108 1124 fct_i_remote_port_t *irp;
1109 1125 int i;
1110 1126 char info[FCT_INFO_LEN];
1111 1127
1112 1128 iport = (fct_i_local_port_t *)port->port_fct_private;
1113 1129 irp = (fct_i_remote_port_t *)rp->rp_fct_private;
1114 1130
1115 1131 if ((ret = port->port_register_remote_port(port, rp, cmd)) !=
1116 1132 FCT_SUCCESS)
1117 1133 return (ret);
1118 1134
1119 1135 rw_enter(&iport->iport_lock, RW_WRITER);
1120 1136 rw_enter(&irp->irp_lock, RW_WRITER);
1121 1137 if (rp->rp_handle != FCT_HANDLE_NONE) {
1122 1138 if (rp->rp_handle >= port->port_max_logins) {
1123 1139 (void) snprintf(info, sizeof (info),
1124 1140 "fct_register_remote_port: FCA "
1125 1141 "returned a handle (%d) for portid %x which is "
1126 1142 "out of range (max logins = %d)", rp->rp_handle,
1127 1143 rp->rp_id, port->port_max_logins);
1128 1144 goto hba_fatal_err;
1129 1145 }
1130 1146 if ((iport->iport_rp_slots[rp->rp_handle] != NULL) &&
1131 1147 (iport->iport_rp_slots[rp->rp_handle] != irp)) {
1132 1148 fct_i_remote_port_t *t_irp =
1133 1149 iport->iport_rp_slots[rp->rp_handle];
1134 1150 (void) snprintf(info, sizeof (info),
1135 1151 "fct_register_remote_port: "
1136 1152 "FCA returned a handle %d for portid %x "
1137 1153 "which was already in use for a different "
1138 1154 "portid (%x)", rp->rp_handle, rp->rp_id,
1139 1155 t_irp->irp_rp->rp_id);
1140 1156 goto hba_fatal_err;
1141 1157 }
1142 1158 } else {
1143 1159 /* Pick a handle for this port */
1144 1160 for (i = 0; i < port->port_max_logins; i++) {
1145 1161 if (iport->iport_rp_slots[i] == NULL) {
1146 1162 break;
1147 1163 }
1148 1164 }
1149 1165 if (i == port->port_max_logins) {
1150 1166 /* This is really pushing it. */
1151 1167 (void) snprintf(info, sizeof (info),
1152 1168 "fct_register_remote_port "
1153 1169 "Cannot register portid %x because all the "
1154 1170 "handles are used up", rp->rp_id);
1155 1171 goto hba_fatal_err;
1156 1172 }
1157 1173 rp->rp_handle = i;
1158 1174 }
1159 1175 /* By this time rport_handle is valid */
1160 1176 if ((irp->irp_flags & IRP_HANDLE_OPENED) == 0) {
1161 1177 iport->iport_rp_slots[rp->rp_handle] = irp;
1162 1178 atomic_or_32(&irp->irp_flags, IRP_HANDLE_OPENED);
1163 1179 }
1164 1180 atomic_inc_64(&iport->iport_last_change);
1165 1181 fct_log_remote_port_event(port, ESC_SUNFC_TARGET_ADD,
1166 1182 rp->rp_pwwn, rp->rp_id);
1167 1183
1168 1184 register_rp_done:;
1169 1185 rw_exit(&irp->irp_lock);
1170 1186 rw_exit(&iport->iport_lock);
1171 1187 return (FCT_SUCCESS);
1172 1188
1173 1189 hba_fatal_err:;
1174 1190 rw_exit(&irp->irp_lock);
1175 1191 rw_exit(&iport->iport_lock);
1176 1192 /*
1177 1193 * XXX Throw HBA fatal error event
1178 1194 */
1179 1195 (void) fct_port_shutdown(iport->iport_port,
1180 1196 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1181 1197 return (FCT_FAILURE);
|
↓ open down ↓ |
74 lines elided |
↑ open up ↑ |
1182 1198 }
1183 1199
1184 1200 fct_status_t
1185 1201 fct_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp)
1186 1202 {
1187 1203 fct_status_t ret = FCT_SUCCESS;
1188 1204 fct_i_local_port_t *iport = PORT_TO_IPORT(port);
1189 1205 fct_i_remote_port_t *irp = RP_TO_IRP(rp);
1190 1206
1191 1207 if (irp->irp_snn) {
1192 - kmem_free(irp->irp_snn, strlen(irp->irp_snn) + 1);
1208 + kmem_free(irp->irp_snn, irp->irp_snn_len);
1193 1209 irp->irp_snn = NULL;
1210 + irp->irp_snn_len = 0;
1194 1211 }
1195 1212 if (irp->irp_spn) {
1196 - kmem_free(irp->irp_spn, strlen(irp->irp_spn) + 1);
1213 + kmem_free(irp->irp_spn, irp->irp_spn_len);
1197 1214 irp->irp_spn = NULL;
1215 + irp->irp_spn_len = 0;
1198 1216 }
1199 1217
1200 1218 if ((ret = port->port_deregister_remote_port(port, rp)) !=
1201 1219 FCT_SUCCESS) {
1202 1220 return (ret);
1203 1221 }
1204 1222
1205 1223 if (irp->irp_flags & IRP_HANDLE_OPENED) {
1206 1224 atomic_and_32(&irp->irp_flags, ~IRP_HANDLE_OPENED);
1207 1225 iport->iport_rp_slots[rp->rp_handle] = NULL;
1208 1226 }
1209 1227 atomic_inc_64(&iport->iport_last_change);
1210 1228 fct_log_remote_port_event(port, ESC_SUNFC_TARGET_REMOVE,
1211 1229 rp->rp_pwwn, rp->rp_id);
1212 1230
1213 1231 return (FCT_SUCCESS);
1214 1232 }
1215 1233
1216 1234 fct_status_t
1217 1235 fct_send_accrjt(fct_cmd_t *cmd, uint8_t accrjt, uint8_t reason, uint8_t expl)
1218 1236 {
1219 1237 fct_local_port_t *port = (fct_local_port_t *)cmd->cmd_port;
1220 1238 fct_els_t *els = (fct_els_t *)cmd->cmd_specific;
1221 1239
1222 1240 els->els_resp_size = els->els_resp_alloc_size = 8;
1223 1241 els->els_resp_payload = (uint8_t *)kmem_zalloc(8, KM_SLEEP);
1224 1242 els->els_resp_payload[0] = accrjt;
1225 1243 if (accrjt == 1) {
1226 1244 els->els_resp_payload[5] = reason;
1227 1245 els->els_resp_payload[6] = expl;
1228 1246 } else {
1229 1247 els->els_resp_size = 4;
1230 1248 }
1231 1249
1232 1250 return (port->port_send_cmd_response(cmd, 0));
1233 1251 }
1234 1252
1235 1253
1236 1254 disc_action_t
1237 1255 fct_walk_discovery_queue(fct_i_local_port_t *iport)
1238 1256 {
1239 1257 char info[FCT_INFO_LEN];
1240 1258 fct_i_remote_port_t **pirp;
1241 1259 fct_i_remote_port_t *prev_irp = NULL;
|
↓ open down ↓ |
34 lines elided |
↑ open up ↑ |
1242 1260 disc_action_t suggested_action = DISC_ACTION_NO_WORK;
1243 1261 fct_i_remote_port_t *irp_dereg_list = NULL;
1244 1262 fct_i_remote_port_t *irp_cur_item = NULL;
1245 1263
1246 1264 for (pirp = &iport->iport_rpwe_head; *pirp != NULL; ) {
1247 1265 fct_i_remote_port_t *irp = *pirp;
1248 1266 disc_action_t ret = DISC_ACTION_NO_WORK;
1249 1267 int do_deregister = 0;
1250 1268 int irp_deregister_timer = 0;
1251 1269
1252 - if (irp->irp_els_list) {
1270 + if (!list_is_empty(&irp->irp_els_list)) {
1253 1271 ret |= fct_process_els(iport, irp);
1254 1272 }
1255 1273
1256 1274 irp_deregister_timer = irp->irp_deregister_timer;
1257 1275 if (irp_deregister_timer) {
1258 1276 if (ddi_get_lbolt() >= irp_deregister_timer) {
1259 1277 do_deregister = 1;
1260 1278 } else {
1261 1279 ret |= DISC_ACTION_DELAY_RESCAN;
1262 1280 }
1263 1281 }
1264 1282 suggested_action |= ret;
1265 1283
1266 - if (irp->irp_els_list == NULL) {
1284 + if (list_is_empty(&irp->irp_els_list)) {
1267 1285 mutex_exit(&iport->iport_worker_lock);
1268 1286 rw_enter(&iport->iport_lock, RW_WRITER);
1269 1287 rw_enter(&irp->irp_lock, RW_WRITER);
1270 1288 mutex_enter(&iport->iport_worker_lock);
1271 - if (irp->irp_els_list == NULL) {
1289 + if (list_is_empty(&irp->irp_els_list)) {
1272 1290 if (!irp_deregister_timer ||
1273 1291 (do_deregister &&
1274 1292 !irp->irp_sa_elses_count &&
1275 1293 !irp->irp_nsa_elses_count &&
1276 1294 !irp->irp_fcp_xchg_count &&
1277 1295 !irp->irp_nonfcp_xchg_count)) {
1278 1296 /* dequeue irp from discovery queue */
1279 1297 atomic_and_32(&irp->irp_flags,
1280 1298 ~IRP_IN_DISCOVERY_QUEUE);
1281 1299 *pirp = irp->irp_discovery_next;
1282 1300 if (iport->iport_rpwe_head == NULL)
1283 1301 iport->iport_rpwe_tail = NULL;
1284 1302 else if (irp == iport->iport_rpwe_tail)
1285 1303 iport->iport_rpwe_tail =
1286 1304 prev_irp;
1287 1305
1288 1306 irp->irp_discovery_next = NULL;
1289 1307 if (do_deregister) {
1290 1308 fct_deque_rp(iport, irp);
1291 1309 rw_exit(&irp->irp_lock);
1292 1310 /* queue irp for deregister */
1293 1311 irp->irp_next = NULL;
1294 1312 if (!irp_dereg_list) {
1295 1313 irp_dereg_list =
1296 1314 irp_cur_item = irp;
1297 1315 } else {
1298 1316 irp_cur_item->irp_next =
1299 1317 irp;
1300 1318 irp_cur_item = irp;
1301 1319 }
1302 1320 } else {
1303 1321 rw_exit(&irp->irp_lock);
1304 1322 }
1305 1323 rw_exit(&iport->iport_lock);
1306 1324 if ((irp = *pirp) == NULL)
1307 1325 break;
1308 1326 } else {
1309 1327 /*
1310 1328 * wait for another scan until
1311 1329 * deregister timeout
1312 1330 */
1313 1331 rw_exit(&irp->irp_lock);
1314 1332 rw_exit(&iport->iport_lock);
1315 1333 }
1316 1334 } else {
1317 1335 rw_exit(&irp->irp_lock);
1318 1336 rw_exit(&iport->iport_lock);
1319 1337 /*
1320 1338 * When we dropped the lock,
1321 1339 * something went in.
1322 1340 */
1323 1341 suggested_action |= DISC_ACTION_RESCAN;
1324 1342 }
1325 1343 }
1326 1344 pirp = &(irp->irp_discovery_next);
1327 1345 prev_irp = irp;
1328 1346 }
1329 1347 /* do deregister */
1330 1348 if (irp_dereg_list) {
1331 1349 fct_i_remote_port_t *irp_next_item;
1332 1350 /* drop the lock */
1333 1351 mutex_exit(&iport->iport_worker_lock);
1334 1352
1335 1353 for (irp_cur_item = irp_dereg_list; irp_cur_item != NULL; ) {
1336 1354 irp_next_item = irp_cur_item->irp_next;
1337 1355 if (fct_deregister_remote_port(iport->iport_port,
1338 1356 irp_cur_item->irp_rp) == FCT_SUCCESS) {
1339 1357 fct_free(irp_cur_item->irp_rp);
1340 1358 } else if (++irp_cur_item->irp_dereg_count >= 5) {
1341 1359 irp_cur_item->irp_deregister_timer = 0;
1342 1360 irp_cur_item->irp_dereg_count = 0;
1343 1361
1344 1362 /*
1345 1363 * It looks like we can't deregister it in the
1346 1364 * normal way, so we have to use extrem way
1347 1365 */
1348 1366 (void) snprintf(info, sizeof (info),
1349 1367 "fct_walk_discovery_queue: "
1350 1368 "iport-%p, can't deregister irp-%p after "
1351 1369 "trying 5 times", (void *)iport,
1352 1370 (void *)irp_cur_item);
1353 1371 (void) fct_port_shutdown(iport->iport_port,
1354 1372 STMF_RFLAG_FATAL_ERROR |
1355 1373 STMF_RFLAG_RESET, info);
1356 1374 suggested_action |= DISC_ACTION_RESCAN;
1357 1375 break;
1358 1376 } else {
1359 1377 /* grab the iport_lock */
1360 1378 rw_enter(&iport->iport_lock, RW_WRITER);
1361 1379 /* recover */
1362 1380 irp_cur_item->irp_deregister_timer =
1363 1381 ddi_get_lbolt() +
1364 1382 drv_usectohz(USEC_DEREG_RP_INTERVAL);
1365 1383 fct_post_to_discovery_queue(iport,
1366 1384 irp_cur_item, NULL);
1367 1385 fct_queue_rp(iport, irp_cur_item);
1368 1386 rw_exit(&iport->iport_lock);
1369 1387 suggested_action |= DISC_ACTION_DELAY_RESCAN;
1370 1388 }
1371 1389 irp_cur_item = irp_next_item;
1372 1390 }
1373 1391 mutex_enter(&iport->iport_worker_lock);
1374 1392 }
1375 1393 return (suggested_action);
1376 1394 }
1377 1395
1378 1396 disc_action_t
1379 1397 fct_process_plogi(fct_i_cmd_t *icmd)
1380 1398 {
1381 1399 fct_cmd_t *cmd = icmd->icmd_cmd;
1382 1400 fct_remote_port_t *rp = cmd->cmd_rp;
1383 1401 fct_local_port_t *port = cmd->cmd_port;
1384 1402 fct_i_local_port_t *iport = (fct_i_local_port_t *)
1385 1403 port->port_fct_private;
1386 1404 fct_els_t *els = (fct_els_t *)
1387 1405 cmd->cmd_specific;
1388 1406 fct_i_remote_port_t *irp = (fct_i_remote_port_t *)
1389 1407 rp->rp_fct_private;
1390 1408 uint8_t *p;
1391 1409 fct_status_t ret;
1392 1410 uint8_t cmd_type = cmd->cmd_type;
1393 1411 uint32_t icmd_flags = icmd->icmd_flags;
1394 1412 clock_t end_time;
1395 1413 char info[FCT_INFO_LEN];
1396 1414
1397 1415 DTRACE_FC_4(rport__login__start,
1398 1416 fct_cmd_t, cmd,
1399 1417 fct_local_port_t, port,
1400 1418 fct_i_remote_port_t, irp,
1401 1419 int, (cmd_type != FCT_CMD_RCVD_ELS));
1402 1420
1403 1421 /* Drain I/Os */
1404 1422 if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) {
1405 1423 /* Trigger cleanup if necessary */
1406 1424 if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) {
1407 1425 stmf_trace(iport->iport_alias, "handling PLOGI rp_id"
1408 1426 " %x. Triggering cleanup", cmd->cmd_rportid);
1409 1427 /* Cleanup everything except elses */
1410 1428 if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) {
1411 1429 atomic_or_32(&irp->irp_flags,
1412 1430 IRP_SESSION_CLEANUP);
1413 1431 } else {
1414 1432 /* XXX: handle this */
1415 1433 /* EMPTY */
1416 1434 }
1417 1435 }
1418 1436
1419 1437 end_time = icmd->icmd_start_time +
1420 1438 drv_usectohz(USEC_ELS_TIMEOUT);
1421 1439 if (ddi_get_lbolt() > end_time) {
1422 1440 (void) snprintf(info, sizeof (info),
1423 1441 "fct_process_plogi: unable to "
1424 1442 "clean up I/O. iport-%p, icmd-%p", (void *)iport,
1425 1443 (void *)icmd);
1426 1444 (void) fct_port_shutdown(iport->iport_port,
1427 1445 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1428 1446
1429 1447 return (DISC_ACTION_DELAY_RESCAN);
1430 1448 }
1431 1449
1432 1450 if ((ddi_get_lbolt() & 0x7f) == 0) {
1433 1451 stmf_trace(iport->iport_alias, "handling"
1434 1452 " PLOGI rp_id %x, waiting for cmds to"
1435 1453 " drain", cmd->cmd_rportid);
1436 1454 }
1437 1455 return (DISC_ACTION_DELAY_RESCAN);
1438 1456 }
1439 1457 atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP);
1440 1458
1441 1459 /* Session can only be terminated after all the I/Os have drained */
1442 1460 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
1443 1461 stmf_deregister_scsi_session(iport->iport_port->port_lport,
1444 1462 irp->irp_session);
1445 1463 stmf_free(irp->irp_session);
1446 1464 irp->irp_session = NULL;
1447 1465 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
1448 1466 }
1449 1467
1450 1468 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1451 1469 els->els_resp_size = els->els_req_size;
1452 1470 p = els->els_resp_payload = (uint8_t *)kmem_zalloc(
1453 1471 els->els_resp_size, KM_SLEEP);
1454 1472 els->els_resp_alloc_size = els->els_resp_size;
1455 1473 bcopy(els->els_req_payload, p, els->els_resp_size);
1456 1474 p[0] = ELS_OP_ACC;
1457 1475 bcopy(p+20, rp->rp_pwwn, 8);
1458 1476 bcopy(p+28, rp->rp_nwwn, 8);
1459 1477 bcopy(port->port_pwwn, p+20, 8);
1460 1478 bcopy(port->port_nwwn, p+28, 8);
1461 1479 fct_wwn_to_str(rp->rp_pwwn_str, rp->rp_pwwn);
1462 1480 fct_wwn_to_str(rp->rp_nwwn_str, rp->rp_nwwn);
1463 1481 fct_wwn_to_str(port->port_pwwn_str, port->port_pwwn);
1464 1482 fct_wwn_to_str(port->port_nwwn_str, port->port_nwwn);
1465 1483
1466 1484 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id,
1467 1485 rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL);
1468 1486 }
1469 1487
1470 1488 ret = fct_register_remote_port(port, rp, cmd);
1471 1489 fct_dequeue_els(irp);
1472 1490 if ((ret == FCT_SUCCESS) && !(icmd->icmd_flags & ICMD_IMPLICIT)) {
1473 1491 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1474 1492 ret = port->port_send_cmd_response(cmd, 0);
1475 1493 if ((ret == FCT_SUCCESS) && IPORT_IN_NS_TOPO(iport) &&
1476 1494 !FC_WELL_KNOWN_ADDR(irp->irp_portid)) {
1477 1495 fct_cmd_t *ct_cmd = fct_create_solct(port,
1478 1496 rp, NS_GSNN_NN, fct_gsnn_cb);
1479 1497 if (ct_cmd) {
1480 1498 fct_post_to_solcmd_queue(port, ct_cmd);
1481 1499 }
1482 1500 ct_cmd = fct_create_solct(port, rp,
1483 1501 NS_GSPN_ID, fct_gspn_cb);
1484 1502 if (ct_cmd)
1485 1503 fct_post_to_solcmd_queue(port, ct_cmd);
1486 1504 ct_cmd = fct_create_solct(port, rp,
1487 1505 NS_GCS_ID, fct_gcs_cb);
1488 1506 if (ct_cmd)
1489 1507 fct_post_to_solcmd_queue(port, ct_cmd);
1490 1508 ct_cmd = fct_create_solct(port, rp,
1491 1509 NS_GFT_ID, fct_gft_cb);
1492 1510 if (ct_cmd)
1493 1511 fct_post_to_solcmd_queue(port, ct_cmd);
1494 1512 }
1495 1513 } else {
1496 1514 /*
1497 1515 * The reason we set this flag is to prevent
1498 1516 * killing a PRLI while we have not yet processed
1499 1517 * a response to PLOGI. Because the initiator
1500 1518 * will send a PRLI as soon as it responds to PLOGI.
1501 1519 * Check fct_process_els() for more info.
1502 1520 */
1503 1521 atomic_or_32(&irp->irp_flags,
1504 1522 IRP_SOL_PLOGI_IN_PROGRESS);
1505 1523 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
1506 1524 ret = port->port_send_cmd(cmd);
1507 1525 if (ret != FCT_SUCCESS) {
1508 1526 atomic_and_32(&icmd->icmd_flags,
|
↓ open down ↓ |
227 lines elided |
↑ open up ↑ |
1509 1527 ~ICMD_KNOWN_TO_FCA);
1510 1528 atomic_and_32(&irp->irp_flags,
1511 1529 ~IRP_SOL_PLOGI_IN_PROGRESS);
1512 1530 }
1513 1531 }
1514 1532 }
1515 1533 atomic_dec_16(&irp->irp_sa_elses_count);
1516 1534
1517 1535 if (ret == FCT_SUCCESS) {
1518 1536 if (cmd_type == FCT_CMD_RCVD_ELS) {
1537 + rw_enter(&iport->iport_lock, RW_WRITER);
1538 + rw_enter(&irp->irp_lock, RW_WRITER);
1519 1539 atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE);
1520 1540 atomic_inc_32(&iport->iport_nrps_login);
1521 1541 if (irp->irp_deregister_timer)
1522 1542 irp->irp_deregister_timer = 0;
1543 + rw_exit(&irp->irp_lock);
1544 + rw_exit(&iport->iport_lock);
1523 1545 }
1524 1546 if (icmd_flags & ICMD_IMPLICIT) {
1525 1547 DTRACE_FC_5(rport__login__end,
1526 1548 fct_cmd_t, cmd,
1527 1549 fct_local_port_t, port,
1528 1550 fct_i_remote_port_t, irp,
1529 1551 int, (cmd_type != FCT_CMD_RCVD_ELS),
1530 1552 int, FCT_SUCCESS);
1531 1553
1532 1554 p = els->els_resp_payload;
1533 1555 p[0] = ELS_OP_ACC;
1534 1556 cmd->cmd_comp_status = FCT_SUCCESS;
1535 1557 fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE);
1536 1558 }
1537 1559 } else {
1538 1560 DTRACE_FC_5(rport__login__end,
1539 1561 fct_cmd_t, cmd,
1540 1562 fct_local_port_t, port,
1541 1563 fct_i_remote_port_t, irp,
1542 1564 int, (cmd_type != FCT_CMD_RCVD_ELS),
1543 1565 int, ret);
1544 1566
1545 1567 fct_queue_cmd_for_termination(cmd, ret);
1546 1568 }
1547 1569
1548 1570 /* Do not touch cmd here as it may have been freed */
1549 1571
1550 1572 return (DISC_ACTION_RESCAN);
1551 1573 }
1552 1574
1553 1575 uint8_t fct_prli_temp[] = { 0x20, 0x10, 0, 0x14, 8, 0, 0x20, 0, 0, 0, 0, 0,
1554 1576 0, 0, 0, 0 };
1555 1577
1556 1578 disc_action_t
1557 1579 fct_process_prli(fct_i_cmd_t *icmd)
1558 1580 {
1559 1581 fct_cmd_t *cmd = icmd->icmd_cmd;
1560 1582 fct_remote_port_t *rp = cmd->cmd_rp;
1561 1583 fct_local_port_t *port = cmd->cmd_port;
1562 1584 fct_i_local_port_t *iport = (fct_i_local_port_t *)
1563 1585 port->port_fct_private;
1564 1586 fct_els_t *els = (fct_els_t *)
1565 1587 cmd->cmd_specific;
1566 1588 fct_i_remote_port_t *irp = (fct_i_remote_port_t *)
1567 1589 rp->rp_fct_private;
1568 1590 stmf_scsi_session_t *ses = NULL;
1569 1591 fct_status_t ret;
1570 1592 clock_t end_time;
1571 1593 char info[FCT_INFO_LEN];
1572 1594
1573 1595 /* We dont support solicited PRLIs yet */
1574 1596 ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
1575 1597
1576 1598 if (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS) {
1577 1599 /*
1578 1600 * Dont process the PRLI yet. Let the framework process the
1579 1601 * PLOGI completion 1st. This should be very quick because
1580 1602 * the reason we got the PRLI is because the initiator
1581 1603 * has responded to PLOGI already.
1582 1604 */
1583 1605 /* XXX: Probably need a timeout here */
1584 1606 return (DISC_ACTION_DELAY_RESCAN);
1585 1607 }
1586 1608 /* The caller has made sure that login is done */
1587 1609
1588 1610 /* Make sure the process is fcp in this case */
1589 1611 if ((els->els_req_size != 20) || (bcmp(els->els_req_payload,
1590 1612 fct_prli_temp, 16))) {
1591 1613 if (els->els_req_payload[4] != 0x08)
1592 1614 stmf_trace(iport->iport_alias, "PRLI received from"
1593 1615 " %x for unknown FC-4 type %x", cmd->cmd_rportid,
1594 1616 els->els_req_payload[4]);
1595 1617 else
1596 1618 stmf_trace(iport->iport_alias, "Rejecting PRLI from %x "
1597 1619 " pld sz %d, prli_flags %x", cmd->cmd_rportid,
1598 1620 els->els_req_size, els->els_req_payload[6]);
1599 1621
1600 1622 fct_dequeue_els(irp);
1601 1623 atomic_dec_16(&irp->irp_sa_elses_count);
1602 1624 ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0x2c);
1603 1625 goto prli_end;
1604 1626 }
1605 1627
1606 1628 if (irp->irp_fcp_xchg_count) {
1607 1629 /* Trigger cleanup if necessary */
1608 1630 if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) {
1609 1631 stmf_trace(iport->iport_alias, "handling PRLI from"
1610 1632 " %x. Triggering cleanup", cmd->cmd_rportid);
1611 1633 if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) {
1612 1634 atomic_or_32(&irp->irp_flags, IRP_FCP_CLEANUP);
1613 1635 } else {
1614 1636 /* XXX: handle this */
1615 1637 /* EMPTY */
1616 1638 }
1617 1639 }
1618 1640
1619 1641 end_time = icmd->icmd_start_time +
1620 1642 drv_usectohz(USEC_ELS_TIMEOUT);
1621 1643 if (ddi_get_lbolt() > end_time) {
1622 1644 (void) snprintf(info, sizeof (info),
1623 1645 "fct_process_prli: unable to clean "
1624 1646 "up I/O. iport-%p, icmd-%p", (void *)iport,
1625 1647 (void *)icmd);
1626 1648 (void) fct_port_shutdown(iport->iport_port,
1627 1649 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1628 1650
1629 1651 return (DISC_ACTION_DELAY_RESCAN);
1630 1652 }
1631 1653
1632 1654 if ((ddi_get_lbolt() & 0x7f) == 0) {
1633 1655 stmf_trace(iport->iport_alias, "handling"
1634 1656 " PRLI from %x, waiting for cmds to"
1635 1657 " drain", cmd->cmd_rportid);
1636 1658 }
1637 1659 return (DISC_ACTION_DELAY_RESCAN);
1638 1660 }
1639 1661 atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP);
1640 1662
1641 1663 /* Session can only be terminated after all the I/Os have drained */
1642 1664 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
1643 1665 stmf_deregister_scsi_session(iport->iport_port->port_lport,
1644 1666 irp->irp_session);
1645 1667 stmf_free(irp->irp_session);
1646 1668 irp->irp_session = NULL;
1647 1669 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
1648 1670 }
1649 1671
1650 1672 /* All good, lets start a session */
1651 1673 ses = (stmf_scsi_session_t *)stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0, 0);
1652 1674 if (ses) {
1653 1675 ses->ss_port_private = irp;
1654 1676 ses->ss_rport_id = (scsi_devid_desc_t *)irp->irp_id;
1655 1677 ses->ss_lport = port->port_lport;
1656 1678 if (stmf_register_scsi_session(port->port_lport, ses) !=
1657 1679 STMF_SUCCESS) {
1658 1680 stmf_free(ses);
1659 1681 ses = NULL;
1660 1682 } else {
1661 1683 irp->irp_session = ses;
1662 1684 irp->irp_session->ss_rport_alias = irp->irp_snn;
1663 1685
1664 1686 /*
1665 1687 * The reason IRP_SCSI_SESSION_STARTED is different
1666 1688 * from IRP_PRLI_DONE is that we clear IRP_PRLI_DONE
1667 1689 * inside interrupt context. We dont want to deregister
1668 1690 * the session from an interrupt.
1669 1691 */
1670 1692 atomic_or_32(&irp->irp_flags, IRP_SCSI_SESSION_STARTED);
1671 1693 }
1672 1694 }
1673 1695
1674 1696 fct_dequeue_els(irp);
1675 1697 atomic_dec_16(&irp->irp_sa_elses_count);
1676 1698 if (ses == NULL) {
1677 1699 /* fail PRLI */
1678 1700 ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0);
1679 1701 } else {
1680 1702 /* accept PRLI */
1681 1703 els->els_resp_payload = (uint8_t *)kmem_zalloc(20, KM_SLEEP);
1682 1704 bcopy(fct_prli_temp, els->els_resp_payload, 20);
1683 1705 els->els_resp_payload[0] = 2;
1684 1706 els->els_resp_payload[6] = 0x21;
1685 1707
1686 1708 /* XXX the two bytes below need to set as per capabilities */
1687 1709 els->els_resp_payload[18] = 0;
1688 1710 els->els_resp_payload[19] = 0x12;
1689 1711
1690 1712 els->els_resp_size = els->els_resp_alloc_size = 20;
1691 1713 if ((ret = port->port_send_cmd_response(cmd, 0)) !=
1692 1714 FCT_SUCCESS) {
1693 1715 stmf_deregister_scsi_session(port->port_lport, ses);
1694 1716 stmf_free(irp->irp_session);
1695 1717 irp->irp_session = NULL;
1696 1718 atomic_and_32(&irp->irp_flags,
1697 1719 ~IRP_SCSI_SESSION_STARTED);
1698 1720 } else {
1699 1721 /* Mark that PRLI is done */
1700 1722 atomic_or_32(&irp->irp_flags, IRP_PRLI_DONE);
1701 1723 }
1702 1724 }
1703 1725
1704 1726 prli_end:;
1705 1727 if (ret != FCT_SUCCESS)
1706 1728 fct_queue_cmd_for_termination(cmd, ret);
1707 1729
1708 1730 return (DISC_ACTION_RESCAN);
1709 1731 }
1710 1732
1711 1733 disc_action_t
1712 1734 fct_process_logo(fct_i_cmd_t *icmd)
1713 1735 {
1714 1736 fct_cmd_t *cmd = icmd->icmd_cmd;
1715 1737 fct_remote_port_t *rp = cmd->cmd_rp;
1716 1738 fct_local_port_t *port = cmd->cmd_port;
1717 1739 fct_i_local_port_t *iport = (fct_i_local_port_t *)
1718 1740 port->port_fct_private;
1719 1741 fct_i_remote_port_t *irp = (fct_i_remote_port_t *)
1720 1742 rp->rp_fct_private;
1721 1743 fct_status_t ret;
1722 1744 char info[FCT_INFO_LEN];
1723 1745 clock_t end_time;
1724 1746
1725 1747 DTRACE_FC_4(rport__logout__start,
1726 1748 fct_cmd_t, cmd,
1727 1749 fct_local_port_t, port,
1728 1750 fct_i_remote_port_t, irp,
1729 1751 int, (cmd->cmd_type != FCT_CMD_RCVD_ELS));
1730 1752
1731 1753 /* Drain I/Os */
1732 1754 if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) {
1733 1755 /* Trigger cleanup if necessary */
1734 1756 if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) {
1735 1757 stmf_trace(iport->iport_alias, "handling LOGO rp_id"
1736 1758 " %x. Triggering cleanup", cmd->cmd_rportid);
1737 1759 /* Cleanup everything except elses */
1738 1760 if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) {
1739 1761 atomic_or_32(&irp->irp_flags,
1740 1762 IRP_SESSION_CLEANUP);
1741 1763 } else {
1742 1764 /* XXX: need more handling */
1743 1765 return (DISC_ACTION_DELAY_RESCAN);
1744 1766 }
1745 1767 }
1746 1768
1747 1769 end_time = icmd->icmd_start_time +
1748 1770 drv_usectohz(USEC_ELS_TIMEOUT);
1749 1771 if (ddi_get_lbolt() > end_time) {
1750 1772 (void) snprintf(info, sizeof (info),
1751 1773 "fct_process_logo: unable to clean "
1752 1774 "up I/O. iport-%p, icmd-%p", (void *)iport,
1753 1775 (void *)icmd);
1754 1776 (void) fct_port_shutdown(iport->iport_port,
1755 1777 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1756 1778
1757 1779 return (DISC_ACTION_DELAY_RESCAN);
1758 1780 }
1759 1781
1760 1782 if ((ddi_get_lbolt() & 0x7f) == 0) {
1761 1783 stmf_trace(iport->iport_alias, "handling"
1762 1784 " LOGO rp_id %x, waiting for cmds to"
1763 1785 " drain", cmd->cmd_rportid);
1764 1786 }
1765 1787 return (DISC_ACTION_DELAY_RESCAN);
1766 1788 }
1767 1789 atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP);
1768 1790
1769 1791 /* Session can only be terminated after all the I/Os have drained */
1770 1792 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
1771 1793 stmf_deregister_scsi_session(iport->iport_port->port_lport,
1772 1794 irp->irp_session);
1773 1795 stmf_free(irp->irp_session);
1774 1796 irp->irp_session = NULL;
1775 1797 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
1776 1798 }
1777 1799
1778 1800 fct_dequeue_els(irp);
1779 1801 atomic_dec_16(&irp->irp_sa_elses_count);
1780 1802
1781 1803 /* don't send response if this is an implicit logout cmd */
1782 1804 if (!(icmd->icmd_flags & ICMD_IMPLICIT)) {
1783 1805 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1784 1806 ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0);
1785 1807 } else {
1786 1808 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
1787 1809 ret = port->port_send_cmd(cmd);
1788 1810 if (ret != FCT_SUCCESS) {
1789 1811 atomic_and_32(&icmd->icmd_flags,
1790 1812 ~ICMD_KNOWN_TO_FCA);
1791 1813 }
1792 1814 }
1793 1815
1794 1816 if (ret != FCT_SUCCESS) {
1795 1817 fct_queue_cmd_for_termination(cmd, ret);
1796 1818 }
1797 1819
1798 1820 DTRACE_FC_4(rport__logout__end,
1799 1821 fct_cmd_t, cmd,
1800 1822 fct_local_port_t, port,
1801 1823 fct_i_remote_port_t, irp,
1802 1824 int, (cmd->cmd_type != FCT_CMD_RCVD_ELS));
1803 1825
1804 1826 } else {
1805 1827 DTRACE_FC_4(rport__logout__end,
1806 1828 fct_cmd_t, cmd,
1807 1829 fct_local_port_t, port,
1808 1830 fct_i_remote_port_t, irp,
1809 1831 int, (cmd->cmd_type != FCT_CMD_RCVD_ELS));
1810 1832
1811 1833 fct_cmd_free(cmd);
1812 1834 }
1813 1835
1814 1836 irp->irp_deregister_timer = ddi_get_lbolt() +
1815 1837 drv_usectohz(USEC_DEREG_RP_TIMEOUT);
1816 1838 irp->irp_dereg_count = 0;
1817 1839
1818 1840 /* Do not touch cmd here as it may have been freed */
1819 1841
1820 1842 ASSERT(irp->irp_flags & IRP_IN_DISCOVERY_QUEUE);
1821 1843
1822 1844 return (DISC_ACTION_RESCAN);
1823 1845 }
1824 1846
1825 1847 disc_action_t
1826 1848 fct_process_prlo(fct_i_cmd_t *icmd)
1827 1849 {
1828 1850 fct_cmd_t *cmd = icmd->icmd_cmd;
1829 1851 fct_remote_port_t *rp = cmd->cmd_rp;
1830 1852 fct_local_port_t *port = cmd->cmd_port;
1831 1853 fct_i_local_port_t *iport = (fct_i_local_port_t *)
1832 1854 port->port_fct_private;
1833 1855 fct_i_remote_port_t *irp = (fct_i_remote_port_t *)
1834 1856 rp->rp_fct_private;
1835 1857 fct_status_t ret;
1836 1858 clock_t end_time;
1837 1859 char info[FCT_INFO_LEN];
1838 1860
1839 1861 /* We do not support solicited PRLOs yet */
1840 1862 ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
1841 1863
1842 1864 /* Drain I/Os */
1843 1865 if (irp->irp_fcp_xchg_count) {
1844 1866 /* Trigger cleanup if necessary */
1845 1867 if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) {
1846 1868 stmf_trace(iport->iport_alias, "handling LOGO from"
1847 1869 " %x. Triggering cleanup", cmd->cmd_rportid);
1848 1870 /* Cleanup everything except elses */
1849 1871 if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) {
1850 1872 atomic_or_32(&irp->irp_flags,
1851 1873 IRP_FCP_CLEANUP);
1852 1874 } else {
1853 1875 /* XXX: need more handling */
1854 1876 return (DISC_ACTION_DELAY_RESCAN);
1855 1877 }
1856 1878 }
1857 1879
1858 1880 end_time = icmd->icmd_start_time +
1859 1881 drv_usectohz(USEC_ELS_TIMEOUT);
1860 1882 if (ddi_get_lbolt() > end_time) {
1861 1883 (void) snprintf(info, sizeof (info),
1862 1884 "fct_process_prlo: unable to "
1863 1885 "clean up I/O. iport-%p, icmd-%p", (void *)iport,
1864 1886 (void *)icmd);
1865 1887 (void) fct_port_shutdown(iport->iport_port,
1866 1888 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1867 1889
1868 1890 return (DISC_ACTION_DELAY_RESCAN);
1869 1891 }
1870 1892
1871 1893 if ((ddi_get_lbolt() & 0x7f) == 0) {
1872 1894 stmf_trace(iport->iport_alias, "handling"
1873 1895 " PRLO from %x, waiting for cmds to"
1874 1896 " drain", cmd->cmd_rportid);
1875 1897 }
1876 1898 return (DISC_ACTION_DELAY_RESCAN);
1877 1899 }
1878 1900 atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP);
1879 1901
1880 1902 /* Session can only be terminated after all the I/Os have drained */
1881 1903 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
1882 1904 stmf_deregister_scsi_session(iport->iport_port->port_lport,
1883 1905 irp->irp_session);
1884 1906 stmf_free(irp->irp_session);
1885 1907 irp->irp_session = NULL;
1886 1908 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
1887 1909 }
1888 1910
1889 1911 fct_dequeue_els(irp);
1890 1912 atomic_dec_16(&irp->irp_sa_elses_count);
1891 1913 ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0);
1892 1914 if (ret != FCT_SUCCESS)
1893 1915 fct_queue_cmd_for_termination(cmd, ret);
1894 1916
1895 1917 return (DISC_ACTION_RESCAN);
1896 1918 }
1897 1919
1898 1920 disc_action_t
1899 1921 fct_process_rcvd_adisc(fct_i_cmd_t *icmd)
1900 1922 {
1901 1923 fct_cmd_t *cmd = icmd->icmd_cmd;
1902 1924 fct_remote_port_t *rp = cmd->cmd_rp;
1903 1925 fct_local_port_t *port = cmd->cmd_port;
1904 1926 fct_i_local_port_t *iport = (fct_i_local_port_t *)
1905 1927 port->port_fct_private;
1906 1928 fct_els_t *els = (fct_els_t *)
1907 1929 cmd->cmd_specific;
1908 1930 fct_i_remote_port_t *irp = (fct_i_remote_port_t *)
1909 1931 rp->rp_fct_private;
1910 1932 uint8_t *p;
1911 1933 uint32_t *q;
1912 1934 fct_status_t ret;
1913 1935
1914 1936 fct_dequeue_els(irp);
1915 1937 atomic_dec_16(&irp->irp_nsa_elses_count);
1916 1938
1917 1939 /* Validate the adisc request */
1918 1940 p = els->els_req_payload;
1919 1941 q = (uint32_t *)p;
1920 1942 if ((els->els_req_size != 28) || (bcmp(rp->rp_pwwn, p + 8, 8)) ||
1921 1943 (bcmp(rp->rp_nwwn, p + 16, 8))) {
1922 1944 ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0);
1923 1945 } else {
1924 1946 rp->rp_hard_address = BE_32(q[1]);
1925 1947 els->els_resp_size = els->els_resp_alloc_size = 28;
1926 1948 els->els_resp_payload = (uint8_t *)kmem_zalloc(28, KM_SLEEP);
1927 1949 bcopy(p, els->els_resp_payload, 28);
1928 1950 p = els->els_resp_payload;
1929 1951 q = (uint32_t *)p;
1930 1952 p[0] = ELS_OP_ACC;
1931 1953 q[1] = BE_32(port->port_hard_address);
1932 1954 bcopy(port->port_pwwn, p + 8, 8);
1933 1955 bcopy(port->port_nwwn, p + 16, 8);
1934 1956 q[6] = BE_32(iport->iport_link_info.portid);
1935 1957 ret = port->port_send_cmd_response(cmd, 0);
1936 1958 }
1937 1959 if (ret != FCT_SUCCESS) {
1938 1960 fct_queue_cmd_for_termination(cmd, ret);
1939 1961 }
1940 1962
1941 1963 return (DISC_ACTION_RESCAN);
1942 1964 }
1943 1965
1944 1966 disc_action_t
1945 1967 fct_process_unknown_els(fct_i_cmd_t *icmd)
1946 1968 {
1947 1969 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd);
1948 1970 fct_status_t ret = FCT_FAILURE;
1949 1971 uint8_t op = 0;
1950 1972
1951 1973 ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS);
1952 1974 fct_dequeue_els(ICMD_TO_IRP(icmd));
1953 1975 atomic_dec_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count);
1954 1976 op = ICMD_TO_ELS(icmd)->els_req_payload[0];
1955 1977 stmf_trace(iport->iport_alias, "Rejecting unknown unsol els %x (%s)",
1956 1978 op, FCT_ELS_NAME(op));
1957 1979 ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_LSRJT, 1, 0);
1958 1980 if (ret != FCT_SUCCESS) {
1959 1981 fct_queue_cmd_for_termination(icmd->icmd_cmd, ret);
1960 1982 }
1961 1983
1962 1984 return (DISC_ACTION_RESCAN);
1963 1985 }
1964 1986
1965 1987 disc_action_t
1966 1988 fct_process_rscn(fct_i_cmd_t *icmd)
1967 1989 {
1968 1990 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd);
1969 1991 fct_status_t ret = FCT_FAILURE;
1970 1992 uint8_t op = 0;
1971 1993 uint8_t *rscn_req_payload;
1972 1994 uint32_t rscn_req_size;
1973 1995
1974 1996 fct_dequeue_els(ICMD_TO_IRP(icmd));
1975 1997 atomic_dec_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count);
1976 1998 if (icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1977 1999 op = ICMD_TO_ELS(icmd)->els_req_payload[0];
1978 2000 stmf_trace(iport->iport_alias, "Accepting RSCN %x (%s)",
1979 2001 op, FCT_ELS_NAME(op));
1980 2002 rscn_req_size = ICMD_TO_ELS(icmd)->els_req_size;
1981 2003 rscn_req_payload = kmem_alloc(rscn_req_size, KM_SLEEP);
1982 2004 bcopy(ICMD_TO_ELS(icmd)->els_req_payload, rscn_req_payload,
1983 2005 rscn_req_size);
1984 2006 ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_ACC, 1, 0);
1985 2007 if (ret != FCT_SUCCESS) {
1986 2008 fct_queue_cmd_for_termination(icmd->icmd_cmd, ret);
1987 2009 } else {
1988 2010 if (fct_rscn_options & RSCN_OPTION_VERIFY) {
1989 2011 fct_rscn_verify(iport, rscn_req_payload,
1990 2012 rscn_req_size);
1991 2013 }
1992 2014 }
1993 2015
1994 2016 kmem_free(rscn_req_payload, rscn_req_size);
|
↓ open down ↓ |
462 lines elided |
↑ open up ↑ |
1995 2017 } else {
1996 2018 ASSERT(0);
1997 2019 }
1998 2020
1999 2021 return (DISC_ACTION_RESCAN);
2000 2022 }
2001 2023
2002 2024 disc_action_t
2003 2025 fct_process_els(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
2004 2026 {
2005 - fct_i_cmd_t *cmd_to_abort = NULL;
2006 - fct_i_cmd_t **ppcmd, *icmd;
2027 + list_t cmd_to_abort;
2028 + fct_i_cmd_t *next, *icmd;
2007 2029 fct_cmd_t *cmd;
2008 2030 fct_els_t *els;
2009 2031 int dq;
2010 2032 disc_action_t ret = DISC_ACTION_NO_WORK;
2011 2033 uint8_t op;
2012 2034
2013 2035 mutex_exit(&iport->iport_worker_lock);
2014 2036
2015 2037 /*
2016 2038 * Do some cleanup based on the following.
2017 2039 * - We can only have one session affecting els pending.
2018 2040 * - If any session affecting els is pending no other els is allowed.
2019 2041 * - If PLOGI is not done, nothing except PLOGI or LOGO is allowed.
2020 2042 * NOTE: If port is down the cleanup is done outside of this
2021 2043 * function.
2022 2044 * NOTE: There is a side effect, if a sa ELS (non PLOGI) is received
2023 2045 * while a PLOGI is pending, it will kill itself and the PLOGI.
2024 2046 * which is probably ok.
2025 2047 */
2026 2048 rw_enter(&irp->irp_lock, RW_WRITER);
2027 - ppcmd = &irp->irp_els_list;
2028 - while ((*ppcmd) != NULL) {
2049 + icmd = list_head(&irp->irp_els_list);
2050 + list_create(&cmd_to_abort, sizeof (fct_i_cmd_t),
2051 + offsetof(fct_i_cmd_t, icmd_node));
2052 + while (icmd != NULL) {
2029 2053 int special_prli_cond = 0;
2030 2054 dq = 0;
2031 2055
2032 - els = (fct_els_t *)((*ppcmd)->icmd_cmd)->cmd_specific;
2056 + els = (fct_els_t *)(icmd->icmd_cmd)->cmd_specific;
2033 2057
2034 - if (((*ppcmd)->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
2058 + if ((icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
2035 2059 (els->els_req_payload[0] == ELS_OP_PRLI) &&
2036 2060 (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS)) {
2037 2061 /*
2038 2062 * The initiator sent a PRLI right after responding
2039 2063 * to PLOGI and we have not yet finished processing
2040 2064 * the PLOGI completion. We should not kill the PRLI
2041 2065 * as the initiator may not retry it.
2042 2066 */
2043 2067 special_prli_cond = 1;
2044 2068 }
2045 2069
2046 - if ((*ppcmd)->icmd_flags & ICMD_BEING_ABORTED) {
2070 + if (icmd->icmd_flags & ICMD_BEING_ABORTED) {
2047 2071 dq = 1;
2048 2072 } else if (irp->irp_sa_elses_count > 1) {
2049 2073 dq = 1;
2050 2074 /* This els might have set the CLEANUP flag */
2051 2075 atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP);
2052 2076 stmf_trace(iport->iport_alias, "Killing ELS %x cond 1",
2053 2077 els->els_req_payload[0]);
2054 2078 } else if (irp->irp_sa_elses_count &&
2055 - (((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING) == 0)) {
2079 + ((icmd->icmd_flags & ICMD_SESSION_AFFECTING) == 0)) {
2056 2080 stmf_trace(iport->iport_alias, "Killing ELS %x cond 2",
2057 2081 els->els_req_payload[0]);
2058 2082 dq = 1;
2059 2083 } else if (((irp->irp_flags & IRP_PLOGI_DONE) == 0) &&
2060 2084 (els->els_req_payload[0] != ELS_OP_PLOGI) &&
2061 2085 (els->els_req_payload[0] != ELS_OP_LOGO) &&
2062 2086 (special_prli_cond == 0)) {
2063 2087 stmf_trace(iport->iport_alias, "Killing ELS %x cond 3",
2064 2088 els->els_req_payload[0]);
2065 2089 dq = 1;
2066 2090 }
2067 2091
2092 + next = list_next(&irp->irp_els_list, icmd);
2068 2093 if (dq) {
2069 - fct_i_cmd_t *c = (*ppcmd)->icmd_next;
2070 -
2071 - if ((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING)
2094 + list_remove(&irp->irp_els_list, icmd);
2095 + if (icmd->icmd_flags & ICMD_SESSION_AFFECTING)
2072 2096 atomic_dec_16(&irp->irp_sa_elses_count);
2073 2097 else
2074 2098 atomic_dec_16(&irp->irp_nsa_elses_count);
2075 - (*ppcmd)->icmd_next = cmd_to_abort;
2076 - cmd_to_abort = *ppcmd;
2077 - *ppcmd = c;
2078 - } else {
2079 - ppcmd = &((*ppcmd)->icmd_next);
2099 + list_insert_head(&cmd_to_abort, icmd);
2080 2100 }
2101 + icmd = next;
2081 2102 }
2082 2103 rw_exit(&irp->irp_lock);
2083 2104
2084 - while (cmd_to_abort) {
2085 - fct_i_cmd_t *c = cmd_to_abort->icmd_next;
2105 + while (!list_is_empty(&cmd_to_abort)) {
2106 + fct_i_cmd_t *c = list_remove_head(&cmd_to_abort);
2086 2107
2087 - atomic_and_32(&cmd_to_abort->icmd_flags, ~ICMD_IN_IRP_QUEUE);
2088 - fct_queue_cmd_for_termination(cmd_to_abort->icmd_cmd,
2089 - FCT_ABORTED);
2090 - cmd_to_abort = c;
2108 + atomic_and_32(&c->icmd_flags, ~ICMD_IN_IRP_QUEUE);
2109 + fct_queue_cmd_for_termination(c->icmd_cmd, FCT_ABORTED);
2091 2110 }
2092 2111
2093 2112 /*
2094 2113 * pick from the top of the queue
2095 2114 */
2096 - icmd = irp->irp_els_list;
2115 + icmd = list_head(&irp->irp_els_list);
2097 2116 if (icmd == NULL) {
2098 2117 /*
2099 2118 * The cleanup took care of everything.
2100 2119 */
2101 2120
2102 2121 mutex_enter(&iport->iport_worker_lock);
2103 2122 return (DISC_ACTION_RESCAN);
2104 2123 }
2105 2124
2106 2125 cmd = icmd->icmd_cmd;
2107 2126 els = ICMD_TO_ELS(icmd);
2108 2127 op = els->els_req_payload[0];
2109 2128 if ((icmd->icmd_flags & ICMD_ELS_PROCESSING_STARTED) == 0) {
2110 2129 stmf_trace(iport->iport_alias, "Processing %ssol ELS %x (%s) "
2111 2130 "rp_id=%x", (cmd->cmd_type == FCT_CMD_RCVD_ELS) ? "un" : "",
2112 2131 op, FCT_ELS_NAME(op), cmd->cmd_rportid);
2113 2132 atomic_or_32(&icmd->icmd_flags, ICMD_ELS_PROCESSING_STARTED);
2114 2133 }
2115 2134
2116 2135 if (op == ELS_OP_PLOGI) {
2117 2136 ret |= fct_process_plogi(icmd);
2118 2137 } else if (op == ELS_OP_PRLI) {
2119 2138 ret |= fct_process_prli(icmd);
2120 2139 } else if (op == ELS_OP_LOGO) {
2121 2140 ret |= fct_process_logo(icmd);
2122 2141 } else if ((op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) {
2123 2142 ret |= fct_process_prlo(icmd);
2124 2143 } else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
2125 2144 fct_status_t s;
2126 2145 fct_local_port_t *port = iport->iport_port;
2127 2146
2128 2147 fct_dequeue_els(irp);
2129 2148 atomic_dec_16(&irp->irp_nsa_elses_count);
2130 2149 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
2131 2150 if ((s = port->port_send_cmd(cmd)) != FCT_SUCCESS) {
2132 2151 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2133 2152 fct_queue_cmd_for_termination(cmd, s);
2134 2153 stmf_trace(iport->iport_alias, "Solicited els "
2135 2154 "transport failed, ret = %llx", s);
2136 2155 }
2137 2156 } else if (op == ELS_OP_ADISC) {
2138 2157 ret |= fct_process_rcvd_adisc(icmd);
2139 2158 } else if (op == ELS_OP_RSCN) {
2140 2159 (void) fct_process_rscn(icmd);
2141 2160 } else {
2142 2161 (void) fct_process_unknown_els(icmd);
2143 2162 }
2144 2163
2145 2164 /*
2146 2165 * This if condition will be false if a sa ELS trigged a cleanup
2147 2166 * and set the ret = DISC_ACTION_DELAY_RESCAN. In that case we should
2148 2167 * keep it that way.
2149 2168 */
2150 2169 if (ret == DISC_ACTION_NO_WORK) {
2151 2170 /*
2152 2171 * Since we dropped the lock, we will force a rescan. The
2153 2172 * only exception is if someone returned
2154 2173 * DISC_ACTION_DELAY_RESCAN, in which case that should be the
2155 2174 * return value.
2156 2175 */
2157 2176 ret = DISC_ACTION_RESCAN;
2158 2177 }
2159 2178
2160 2179 mutex_enter(&iport->iport_worker_lock);
2161 2180 return (ret);
2162 2181 }
2163 2182
2164 2183 void
2165 2184 fct_handle_sol_els_completion(fct_i_local_port_t *iport, fct_i_cmd_t *icmd)
2166 2185 {
2167 2186 fct_i_remote_port_t *irp = NULL;
2168 2187 fct_els_t *els = ICMD_TO_ELS(icmd);
2169 2188 uint8_t op = els->els_req_payload[0];
2170 2189
2171 2190 if (icmd->icmd_cmd->cmd_rp) {
|
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
2172 2191 irp = ICMD_TO_IRP(icmd);
2173 2192 }
2174 2193 if (icmd->icmd_cmd->cmd_rp &&
2175 2194 (icmd->icmd_cmd->cmd_comp_status == FCT_SUCCESS) &&
2176 2195 (els->els_req_payload[0] == ELS_OP_PLOGI)) {
2177 2196 bcopy(els->els_resp_payload + 20, irp->irp_rp->rp_pwwn, 8);
2178 2197 bcopy(els->els_resp_payload + 28, irp->irp_rp->rp_nwwn, 8);
2179 2198
2180 2199 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id,
2181 2200 irp->irp_rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL);
2201 + rw_enter(&iport->iport_lock, RW_WRITER);
2202 + rw_enter(&irp->irp_lock, RW_WRITER);
2182 2203 atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE);
2183 2204 atomic_inc_32(&iport->iport_nrps_login);
2184 2205 if (irp->irp_deregister_timer) {
2185 2206 irp->irp_deregister_timer = 0;
2186 2207 irp->irp_dereg_count = 0;
2187 2208 }
2209 + rw_exit(&irp->irp_lock);
2210 + rw_exit(&iport->iport_lock);
2188 2211 }
2189 2212
2190 2213 if (irp && (els->els_req_payload[0] == ELS_OP_PLOGI)) {
2214 + rw_enter(&irp->irp_lock, RW_WRITER);
2191 2215 atomic_and_32(&irp->irp_flags, ~IRP_SOL_PLOGI_IN_PROGRESS);
2216 + rw_exit(&irp->irp_lock);
2192 2217 }
2193 2218 atomic_or_32(&icmd->icmd_flags, ICMD_CMD_COMPLETE);
2194 2219 stmf_trace(iport->iport_alias, "Sol ELS %x (%s) completed with "
2195 2220 "status %llx, did/%x", op, FCT_ELS_NAME(op),
2196 2221 icmd->icmd_cmd->cmd_comp_status, icmd->icmd_cmd->cmd_rportid);
2197 2222 }
2198 2223
2199 2224 static disc_action_t
2200 2225 fct_check_cmdlist(fct_i_local_port_t *iport)
2201 2226 {
2202 2227 int num_to_release, ndx;
2203 2228 fct_i_cmd_t *icmd;
2204 2229 uint32_t total, max_active;
2205 2230
2206 2231 ASSERT(MUTEX_HELD(&iport->iport_worker_lock));
2207 2232
2208 2233 total = iport->iport_total_alloced_ncmds;
2209 2234 max_active = iport->iport_max_active_ncmds;
2210 2235
|
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
2211 2236 if (total <= max_active)
2212 2237 return (DISC_ACTION_NO_WORK);
2213 2238 /*
2214 2239 * Everytime, we release half of the difference
2215 2240 */
2216 2241 num_to_release = (total + 1 - max_active) / 2;
2217 2242
2218 2243 mutex_exit(&iport->iport_worker_lock);
2219 2244 for (ndx = 0; ndx < num_to_release; ndx++) {
2220 2245 mutex_enter(&iport->iport_cached_cmd_lock);
2221 - icmd = iport->iport_cached_cmdlist;
2222 - if (icmd == NULL) {
2246 + if (list_is_empty(&iport->iport_cached_cmdlist)) {
2223 2247 mutex_exit(&iport->iport_cached_cmd_lock);
2224 2248 break;
2225 2249 }
2226 - iport->iport_cached_cmdlist = icmd->icmd_next;
2250 + icmd = list_remove_head(&iport->iport_cached_cmdlist);
2227 2251 iport->iport_cached_ncmds--;
2228 2252 mutex_exit(&iport->iport_cached_cmd_lock);
2229 2253 atomic_dec_32(&iport->iport_total_alloced_ncmds);
2230 2254 fct_free(icmd->icmd_cmd);
2231 2255 }
2232 2256 mutex_enter(&iport->iport_worker_lock);
2233 2257 return (DISC_ACTION_RESCAN);
2234 2258 }
2235 2259
2236 2260 /*
2237 2261 * The efficiency of handling solicited commands is very low here. But
2238 2262 * fortunately, we seldom send solicited commands. So it will not hurt
2239 2263 * the system performance much.
2240 2264 */
2241 2265 static disc_action_t
2242 2266 fct_check_solcmd_queue(fct_i_local_port_t *iport)
2243 2267 {
2244 2268 fct_i_cmd_t *icmd = NULL;
2245 2269 fct_i_cmd_t *prev_icmd = NULL;
2246 2270 fct_i_cmd_t *next_icmd = NULL;
2247 2271
2248 2272 ASSERT(mutex_owned(&iport->iport_worker_lock));
2249 2273 for (icmd = iport->iport_solcmd_queue; icmd; icmd = next_icmd) {
2250 2274 ASSERT(icmd->icmd_flags | ICMD_IN_SOLCMD_QUEUE);
2251 2275 next_icmd = icmd->icmd_solcmd_next;
2252 2276 if (icmd->icmd_flags & ICMD_SOLCMD_NEW) {
2253 2277 /*
2254 2278 * This solicited cmd is new.
2255 2279 * Dispatch ELSes to discovery queue to make use of
2256 2280 * existent framework.
2257 2281 */
2258 2282 icmd->icmd_flags &= ~ICMD_SOLCMD_NEW;
2259 2283 mutex_exit(&iport->iport_worker_lock);
2260 2284
2261 2285 if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) {
2262 2286 fct_handle_els(icmd->icmd_cmd);
2263 2287 } else {
2264 2288 fct_handle_solct(icmd->icmd_cmd);
2265 2289 }
2266 2290
2267 2291 mutex_enter(&iport->iport_worker_lock);
2268 2292 } else if (icmd->icmd_flags & ICMD_CMD_COMPLETE) {
2269 2293 /*
2270 2294 * To make fct_check_solcmd simple and flexible,
2271 2295 * We need only call callback to finish post-handling.
2272 2296 */
2273 2297 if (icmd->icmd_cb) {
2274 2298 /*
2275 2299 * mutex ???
2276 2300 */
2277 2301 icmd->icmd_cb(icmd);
2278 2302 }
2279 2303
2280 2304
2281 2305 /*
2282 2306 * Release resources for this solicited cmd
2283 2307 */
2284 2308 if (iport->iport_solcmd_queue == icmd) {
|
↓ open down ↓ |
48 lines elided |
↑ open up ↑ |
2285 2309 iport->iport_solcmd_queue = next_icmd;
2286 2310 } else {
2287 2311 prev_icmd = iport->iport_solcmd_queue;
2288 2312 while (prev_icmd->icmd_solcmd_next != icmd) {
2289 2313 prev_icmd = prev_icmd->icmd_solcmd_next;
2290 2314 }
2291 2315 prev_icmd->icmd_solcmd_next = next_icmd;
2292 2316 }
2293 2317
2294 2318 icmd->icmd_cb = NULL;
2319 +
2320 + /*
2321 + * If the command has none-zero icmd_node pointers
2322 + * it means it's been linked onto the iport_abort_queue.
2323 + * Since the iport_worker_lock is held the command
2324 + * can be removed before it's freed.
2325 + */
2326 + if (icmd->icmd_node.list_next != NULL) {
2327 + list_remove(&iport->iport_abort_queue, icmd);
2328 + }
2329 +
2295 2330 mutex_exit(&iport->iport_worker_lock);
2296 2331 fct_cmd_free(icmd->icmd_cmd);
2297 2332 mutex_enter(&iport->iport_worker_lock);
2298 2333 } else {
2299 2334 /*
2300 2335 * This solicited cmd is still ongoing.
2301 2336 * We need check if it's time to abort this cmd
2302 2337 */
2303 2338 if (((icmd->icmd_start_time + drv_usectohz(
2304 2339 USEC_SOL_TIMEOUT)) < ddi_get_lbolt()) &&
2305 2340 !(icmd->icmd_flags & ICMD_BEING_ABORTED)) {
2306 2341 fct_q_for_termination_lock_held(iport,
2307 2342 icmd, FCT_ABORTED);
2308 2343 }
2309 2344 }
2310 2345 }
2311 2346
2312 2347 return (DISC_ACTION_DELAY_RESCAN);
2313 2348 }
2314 2349
2315 2350 void
2316 2351 fct_handle_solct(fct_cmd_t *cmd)
2317 2352 {
2318 2353 fct_status_t ret = FCT_SUCCESS;
2319 2354 fct_i_cmd_t *icmd = CMD_TO_ICMD(cmd);
2320 2355 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd);
2321 2356 fct_i_remote_port_t *irp = ICMD_TO_IRP(icmd);
2322 2357
2323 2358 ASSERT(cmd->cmd_type == FCT_CMD_SOL_CT);
2324 2359 rw_enter(&iport->iport_lock, RW_READER);
2325 2360 /*
2326 2361 * Let's make sure local port is sane
2327 2362 */
2328 2363 if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
2329 2364 rw_exit(&iport->iport_lock);
2330 2365
2331 2366 stmf_trace(iport->iport_alias, "fct_transport_solct: "
2332 2367 "solcmd-%p transport failed, becasue port state was %x",
2333 2368 cmd, iport->iport_link_state);
2334 2369 fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
2335 2370 return;
2336 2371 }
2337 2372
2338 2373 /*
2339 2374 * Let's make sure we have plogi-ed to name server
2340 2375 */
2341 2376 rw_enter(&irp->irp_lock, RW_READER);
2342 2377 if (!(irp->irp_flags & IRP_PLOGI_DONE)) {
2343 2378 rw_exit(&irp->irp_lock);
2344 2379 rw_exit(&iport->iport_lock);
2345 2380
2346 2381 stmf_trace(iport->iport_alias, "fct_transport_solct: "
2347 2382 "Must login to name server first - cmd-%p", cmd);
2348 2383 fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
2349 2384 return;
2350 2385 }
2351 2386
2352 2387 /*
2353 2388 * Let's get a slot for this solcmd
2354 2389 */
2355 2390 if (fct_alloc_cmd_slot(iport, cmd) == FCT_SLOT_EOL) {
2356 2391 rw_exit(&irp->irp_lock);
2357 2392 rw_exit(&iport->iport_lock);
2358 2393
2359 2394 stmf_trace(iport->iport_alias, "fct_transport_solcmd: "
2360 2395 "ran out of xchg resources - cmd-%p", cmd);
2361 2396 fct_queue_cmd_for_termination(cmd, FCT_NO_XCHG_RESOURCE);
2362 2397 return;
2363 2398 }
2364 2399
2365 2400 if (fct_netbuf_to_value(ICMD_TO_CT(icmd)->ct_req_payload + 8, 2) ==
2366 2401 NS_GID_PN) {
2367 2402 fct_i_remote_port_t *query_irp = NULL;
2368 2403
2369 2404 query_irp = fct_lookup_irp_by_portwwn(iport,
2370 2405 ICMD_TO_CT(icmd)->ct_req_payload + 16);
2371 2406 if (query_irp) {
2372 2407 atomic_and_32(&query_irp->irp_flags, ~IRP_RSCN_QUEUED);
2373 2408 }
2374 2409 }
2375 2410 rw_exit(&irp->irp_lock);
2376 2411 rw_exit(&iport->iport_lock);
2377 2412
2378 2413 atomic_inc_16(&irp->irp_nonfcp_xchg_count);
2379 2414 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
2380 2415 icmd->icmd_start_time = ddi_get_lbolt();
2381 2416 ret = iport->iport_port->port_send_cmd(cmd);
2382 2417 if (ret != FCT_SUCCESS) {
2383 2418 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2384 2419 fct_queue_cmd_for_termination(cmd, ret);
2385 2420 }
2386 2421 }
2387 2422
2388 2423 void
2389 2424 fct_logo_cb(fct_i_cmd_t *icmd)
2390 2425 {
2391 2426 ASSERT(!(icmd->icmd_flags & ICMD_IMPLICIT));
2392 2427 if (!FCT_IS_ELS_ACC(icmd)) {
2393 2428 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_logo_cb: "
2394 2429 "solicited LOGO is not accepted - icmd/%p", icmd);
2395 2430 }
2396 2431 }
2397 2432
2398 2433 void
2399 2434 fct_gsnn_cb(fct_i_cmd_t *icmd)
2400 2435 {
2401 2436 int snlen = 0;
2402 2437 char *sn = NULL;
2403 2438 fct_i_remote_port_t *query_irp = NULL;
2404 2439
2405 2440 if (!FCT_IS_CT_ACC(icmd)) {
2406 2441 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: "
2407 2442 "GSNN is not accepted by NS - icmd/%p", icmd);
2408 2443 return;
2409 2444 }
2410 2445 mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2411 2446
2412 2447 rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER);
2413 2448 mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2414 2449 query_irp = fct_lookup_irp_by_nodewwn(ICMD_TO_IPORT(icmd),
2415 2450 ICMD_TO_CT(icmd)->ct_req_payload + 16);
2416 2451
2417 2452 if (!query_irp) {
2418 2453 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: "
2419 2454 "can't get rp icmd-%p", icmd);
2420 2455 goto exit_gsnn_cb;
|
↓ open down ↓ |
116 lines elided |
↑ open up ↑ |
2421 2456 } else {
2422 2457 snlen = ICMD_TO_CT(icmd)->ct_resp_payload[16];
2423 2458 }
2424 2459
2425 2460 if (query_irp && snlen) {
2426 2461 /*
2427 2462 * Release previous resource, then allocate needed resource
2428 2463 */
2429 2464 sn = query_irp->irp_snn;
2430 2465 if (sn) {
2431 - kmem_free(sn, strlen(sn) + 1);
2466 + kmem_free(sn, query_irp->irp_snn_len);
2432 2467 }
2433 2468
2434 2469 query_irp->irp_snn = NULL;
2470 + query_irp->irp_snn_len = 0;
2435 2471 sn = kmem_zalloc(snlen + 1, KM_SLEEP);
2436 2472 (void) strncpy(sn, (char *)
2437 2473 ICMD_TO_CT(icmd)->ct_resp_payload + 17, snlen);
2438 2474 if (strlen(sn) != snlen) {
2439 2475 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias,
2440 2476 "fct_gsnn_cb: %s, but len=%d", sn, snlen);
2441 2477 kmem_free(sn, snlen + 1);
2442 2478 sn = NULL;
2443 2479 }
2444 2480
2445 2481 /*
2446 2482 * Update symbolic node name
2447 2483 */
2448 2484 query_irp->irp_snn = sn;
2485 + if (sn != NULL)
2486 + query_irp->irp_snn_len = snlen + 1;
2449 2487 if ((query_irp->irp_flags & IRP_SCSI_SESSION_STARTED) &&
2450 2488 (query_irp->irp_session)) {
2451 2489 query_irp->irp_session->ss_rport_alias =
2452 2490 query_irp->irp_snn;
2453 2491 }
2454 2492 } else {
2455 2493 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: "
2456 2494 "irp/%p, snlen/%d", query_irp, snlen);
2457 2495 }
2458 2496
2459 2497 exit_gsnn_cb:
2460 2498 rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock);
2461 2499 }
2462 2500
2463 2501 void
2464 2502 fct_link_init_cb(fct_i_cmd_t *icmd)
2465 2503 {
2466 2504 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd);
2467 2505
2468 2506 iport->iport_li_state &= ~LI_STATE_FLAG_CMD_WAITING;
2469 2507 if (icmd->icmd_cmd->cmd_comp_status != FCT_SUCCESS) {
2470 2508 stmf_trace(iport->iport_alias, "fct_link_init_cb: ELS-%x failed"
2471 2509 "comp_status- %llx", ICMD_TO_ELS(icmd)->els_req_payload[0],
2472 2510 icmd->icmd_cmd->cmd_comp_status);
2473 2511 iport->iport_li_comp_status = icmd->icmd_cmd->cmd_comp_status;
2474 2512 } else if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) {
2475 2513 if (!FCT_IS_ELS_ACC(icmd)) {
2476 2514 stmf_trace(iport->iport_alias,
2477 2515 "fct_link_init_cb: ELS-%x is rejected",
2478 2516 ICMD_TO_ELS(icmd)->els_req_payload[0]);
2479 2517 iport->iport_li_comp_status = FCT_REJECT_STATUS(
2480 2518 ICMD_TO_ELS(icmd)->els_resp_payload[1],
2481 2519 ICMD_TO_ELS(icmd)->els_resp_payload[2]);
2482 2520 } else {
2483 2521 iport->iport_li_comp_status = FCT_SUCCESS;
2484 2522 }
2485 2523 } else {
2486 2524 ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_CT);
2487 2525 if (!FCT_IS_CT_ACC(icmd)) {
2488 2526 stmf_trace(iport->iport_alias,
2489 2527 "fct_link_init_cb: CT-%02x%02x is rejected",
2490 2528 ICMD_TO_CT(icmd)->ct_req_payload[8],
2491 2529 ICMD_TO_CT(icmd)->ct_req_payload[9]);
2492 2530 iport->iport_li_comp_status = FCT_REJECT_STATUS(
2493 2531 ICMD_TO_CT(icmd)->ct_resp_payload[8],
2494 2532 ICMD_TO_CT(icmd)->ct_resp_payload[9]);
2495 2533 } else {
2496 2534 iport->iport_li_comp_status = FCT_SUCCESS;
2497 2535 }
2498 2536 }
2499 2537 }
2500 2538
2501 2539 void
2502 2540 fct_gcs_cb(fct_i_cmd_t *icmd)
2503 2541 {
2504 2542 fct_sol_ct_t *ct = ICMD_TO_CT(icmd);
2505 2543 fct_i_remote_port_t *query_irp = NULL;
2506 2544 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd);
2507 2545 uint32_t query_portid;
2508 2546 uint8_t *resp;
2509 2547 uint8_t *req;
2510 2548
2511 2549 if (!FCT_IS_CT_ACC(icmd)) {
2512 2550 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gcs_cb: "
2513 2551 "GCS_ID is not accepted by NS - icmd/%p", icmd);
2514 2552 return;
2515 2553 }
2516 2554 mutex_exit(&iport->iport_worker_lock);
2517 2555
2518 2556 resp = ct->ct_resp_payload;
2519 2557 req = ct->ct_req_payload;
2520 2558 query_portid = (req[17] << 16) | (req[18] << 8) | req[19];
2521 2559
2522 2560 rw_enter(&iport->iport_lock, RW_READER);
2523 2561 mutex_enter(&iport->iport_worker_lock);
2524 2562 query_irp = fct_portid_to_portptr(iport, query_portid);
2525 2563
2526 2564 if (query_irp) {
2527 2565 query_irp->irp_cos = (resp[16] << 27) | (resp[17] << 18) |
2528 2566 (resp[18] << 8) | resp[19];
2529 2567 }
2530 2568 rw_exit(&iport->iport_lock);
2531 2569 }
2532 2570
2533 2571 void
2534 2572 fct_gft_cb(fct_i_cmd_t *icmd)
2535 2573 {
2536 2574 fct_sol_ct_t *ct = ICMD_TO_CT(icmd);
2537 2575 fct_i_remote_port_t *query_irp = NULL;
2538 2576 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd);
2539 2577 uint32_t query_portid;
2540 2578 uint8_t *resp;
2541 2579 uint8_t *req;
2542 2580
2543 2581 if (!FCT_IS_CT_ACC(icmd)) {
2544 2582 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gft_cb: "
2545 2583 "GFT_ID is not accepted by NS - icmd/%p", icmd);
2546 2584 return;
2547 2585 }
2548 2586 mutex_exit(&iport->iport_worker_lock);
2549 2587
2550 2588 resp = ct->ct_resp_payload;
2551 2589 req = ct->ct_req_payload;
2552 2590 query_portid = (req[17] << 16) | (req[18] << 8) | req[19];
2553 2591
2554 2592 rw_enter(&iport->iport_lock, RW_READER);
2555 2593 mutex_enter(&iport->iport_worker_lock);
2556 2594 query_irp = fct_portid_to_portptr(iport, query_portid);
2557 2595
2558 2596 if (query_irp) {
2559 2597 (void) memcpy(query_irp->irp_fc4types, resp + 16, 32);
2560 2598 }
2561 2599 rw_exit(&iport->iport_lock);
2562 2600 }
2563 2601
2564 2602 void
2565 2603 fct_gid_cb(fct_i_cmd_t *icmd)
2566 2604 {
2567 2605 fct_cmd_t *cmd = NULL;
2568 2606 fct_i_remote_port_t *query_irp = NULL;
2569 2607 uint32_t nsportid = 0;
2570 2608 int do_logo = 0;
2571 2609
2572 2610 mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2573 2611
2574 2612 rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER);
2575 2613 mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2576 2614 query_irp = fct_lookup_irp_by_portwwn(ICMD_TO_IPORT(icmd),
2577 2615 ICMD_TO_CT(icmd)->ct_req_payload + 16);
2578 2616
2579 2617 if (!query_irp || (query_irp &&
2580 2618 (PTR2INT(icmd->icmd_cb_private, uint32_t) !=
2581 2619 query_irp->irp_rscn_counter))) {
2582 2620 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: "
2583 2621 "new RSCN arrived - query_irp/%p, private-%x", query_irp,
2584 2622 PTR2INT(icmd->icmd_cb_private, uint32_t));
2585 2623 goto exit_gid_cb;
2586 2624 }
2587 2625
2588 2626 if ((query_irp->irp_flags & IRP_RSCN_QUEUED) ||
2589 2627 (!(query_irp->irp_flags & IRP_PLOGI_DONE))) {
2590 2628 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: "
2591 2629 "not proper irp_flags - query_irp/%p", query_irp);
2592 2630 goto exit_gid_cb;
2593 2631 }
2594 2632
2595 2633 if (!FCT_IS_CT_ACC(icmd)) {
2596 2634 /*
2597 2635 * Check if it has disappeared
2598 2636 */
2599 2637 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: "
2600 2638 "GPN_ID is not accepted by NS - icmd/%p", icmd);
2601 2639 do_logo = 1;
2602 2640 } else {
2603 2641 /*
2604 2642 * Check if its portid has changed
2605 2643 */
2606 2644 nsportid = fct_netbuf_to_value(
2607 2645 ICMD_TO_CT(icmd)->ct_resp_payload + 17, 3);
2608 2646 if (nsportid != query_irp->irp_rp->rp_id) {
2609 2647 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias,
2610 2648 "portid has changed - query_irp/%p", query_irp);
2611 2649 do_logo = 1;
2612 2650 }
2613 2651 }
2614 2652
2615 2653 if (do_logo) {
2616 2654 cmd = fct_create_solels(ICMD_TO_PORT(icmd),
2617 2655 query_irp->irp_rp, 1, ELS_OP_LOGO, 0, fct_logo_cb);
2618 2656 if (cmd) {
2619 2657 mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2620 2658 fct_post_implicit_logo(cmd);
2621 2659 mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2622 2660 }
2623 2661 }
2624 2662
2625 2663 exit_gid_cb:
2626 2664 rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock);
2627 2665 }
2628 2666
2629 2667 void
2630 2668 fct_gspn_cb(fct_i_cmd_t *icmd)
2631 2669 {
2632 2670 fct_sol_ct_t *ct = ICMD_TO_CT(icmd);
2633 2671 fct_i_remote_port_t *query_irp = NULL;
2634 2672 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd);
2635 2673 uint32_t query_portid;
2636 2674 uint8_t *resp;
2637 2675 uint8_t *req;
2638 2676 uint8_t spnlen;
2639 2677
2640 2678 if (!FCT_IS_CT_ACC(icmd)) {
2641 2679 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gspn_cb: "
2642 2680 "GSPN_ID is not accepted by NS - icmd/%p", icmd);
2643 2681 return;
2644 2682 }
2645 2683 mutex_exit(&iport->iport_worker_lock);
2646 2684
2647 2685 resp = ct->ct_resp_payload;
2648 2686 req = ct->ct_req_payload;
|
↓ open down ↓ |
190 lines elided |
↑ open up ↑ |
2649 2687 query_portid = (req[17] << 16) | (req[18] << 8) | req[19];
2650 2688
2651 2689 rw_enter(&iport->iport_lock, RW_READER);
2652 2690 mutex_enter(&iport->iport_worker_lock);
2653 2691 query_irp = fct_portid_to_portptr(iport, query_portid);
2654 2692 if (query_irp) {
2655 2693 spnlen = resp[16];
2656 2694 if (spnlen > 0) {
2657 2695 if (query_irp->irp_spn) {
2658 2696 kmem_free(query_irp->irp_spn,
2659 - strlen(query_irp->irp_spn) + 1);
2697 + query_irp->irp_spn_len);
2660 2698 }
2661 - query_irp->irp_spn = kmem_zalloc(spnlen + 1, KM_SLEEP);
2699 + query_irp->irp_spn_len = spnlen + 1;
2700 + query_irp->irp_spn = kmem_zalloc(
2701 + query_irp->irp_spn_len, KM_SLEEP);
2662 2702 (void) strncpy(query_irp->irp_spn,
2663 2703 (char *)resp + 17, spnlen);
2664 2704 }
2665 2705 }
2666 2706 rw_exit(&iport->iport_lock);
2667 2707 }
2668 2708
2669 2709 void
2670 2710 fct_rls_cb(fct_i_cmd_t *icmd)
2671 2711 {
2672 2712 fct_els_t *els = ICMD_TO_ELS(icmd);
2673 2713 uint8_t *resp;
2674 2714 fct_rls_cb_data_t *rls_cb_data = NULL;
2675 2715 fct_port_link_status_t *rls_resp;
2676 2716 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd);
2677 2717
2678 2718 rls_cb_data = icmd->icmd_cb_private;
2679 2719
2680 2720 if (!FCT_IS_ELS_ACC(icmd)) {
2681 2721 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_rls_cb: "
2682 2722 "solicited RLS is not accepted - icmd/%p", icmd);
2683 2723 if (rls_cb_data) {
2684 2724 rls_cb_data->fct_els_res = FCT_FAILURE;
2685 2725 sema_v(&iport->iport_rls_sema);
2686 2726 }
2687 2727 return;
2688 2728 }
2689 2729
2690 2730 if (!rls_cb_data) {
2691 2731 sema_v(&iport->iport_rls_sema);
2692 2732 return;
2693 2733 }
2694 2734
2695 2735 resp = els->els_resp_payload;
2696 2736
2697 2737 rls_cb_data = icmd->icmd_cb_private;
2698 2738
2699 2739 /* Get the response and store it somewhere */
2700 2740 rls_resp = (fct_port_link_status_t *)rls_cb_data->fct_link_status;
2701 2741 rls_resp->LinkFailureCount = BE_32(*((uint32_t *)(resp + 4)));
2702 2742 rls_resp->LossOfSyncCount = BE_32(*((uint32_t *)(resp + 8)));
2703 2743 rls_resp->LossOfSignalsCount = BE_32(*((uint32_t *)(resp + 12)));
2704 2744 rls_resp->PrimitiveSeqProtocolErrorCount =
2705 2745 BE_32(*((uint32_t *)(resp + 16)));
2706 2746 rls_resp->InvalidTransmissionWordCount =
2707 2747 BE_32(*((uint32_t *)(resp + 20)));
2708 2748 rls_resp->InvalidCRCCount = BE_32(*((uint32_t *)(resp + 24)));
2709 2749
2710 2750 rls_cb_data->fct_els_res = FCT_SUCCESS;
2711 2751 sema_v(&iport->iport_rls_sema);
2712 2752 icmd->icmd_cb_private = NULL;
2713 2753 }
2714 2754
2715 2755 /*
2716 2756 * For lookup functions, we move locking up one level
2717 2757 */
2718 2758 fct_i_remote_port_t *
2719 2759 fct_lookup_irp_by_nodewwn(fct_i_local_port_t *iport, uint8_t *nodewwn)
2720 2760 {
2721 2761 fct_i_remote_port_t *irp = NULL;
2722 2762 int idx = 0;
2723 2763
2724 2764 for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) {
2725 2765 for (irp = iport->iport_rp_tb[idx]; irp;
2726 2766 irp = irp->irp_next) {
2727 2767 if (bcmp(irp->irp_rp->rp_nwwn, nodewwn, FC_WWN_LEN)) {
2728 2768 continue;
2729 2769 } else {
2730 2770 return (irp);
2731 2771 }
2732 2772 }
2733 2773 }
2734 2774
2735 2775 return (NULL);
2736 2776 }
2737 2777
2738 2778 fct_i_remote_port_t *
2739 2779 fct_lookup_irp_by_portwwn(fct_i_local_port_t *iport, uint8_t *portwwn)
2740 2780 {
2741 2781 fct_i_remote_port_t *irp = NULL;
2742 2782 int idx = 0;
2743 2783
2744 2784 for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) {
2745 2785 for (irp = iport->iport_rp_tb[idx]; irp;
2746 2786 irp = irp->irp_next) {
2747 2787 if (bcmp(irp->irp_rp->rp_pwwn, portwwn, FC_WWN_LEN)) {
2748 2788 continue;
2749 2789 } else {
2750 2790 return (irp);
2751 2791 }
2752 2792 }
2753 2793 }
2754 2794
2755 2795 return (NULL);
2756 2796 }
2757 2797
2758 2798 #ifdef lint
2759 2799 #define FCT_VERIFY_RSCN() _NOTE(EMPTY)
2760 2800 #else
2761 2801 #define FCT_VERIFY_RSCN() \
2762 2802 do { \
2763 2803 ct_cmd = fct_create_solct(port, irp->irp_rp, NS_GID_PN, \
2764 2804 fct_gid_cb); \
2765 2805 if (ct_cmd) { \
2766 2806 uint32_t cnt; \
2767 2807 cnt = atomic_inc_32_nv(&irp->irp_rscn_counter); \
2768 2808 CMD_TO_ICMD(ct_cmd)->icmd_cb_private = \
2769 2809 INT2PTR(cnt, void *); \
2770 2810 irp->irp_flags |= IRP_RSCN_QUEUED; \
2771 2811 fct_post_to_solcmd_queue(port, ct_cmd); \
2772 2812 } \
2773 2813 } while (0)
2774 2814 #endif
2775 2815
2776 2816 /* ARGSUSED */
2777 2817 static void
2778 2818 fct_rscn_verify(fct_i_local_port_t *iport, uint8_t *rscn_req_payload,
2779 2819 uint32_t rscn_req_size)
2780 2820 {
2781 2821 int idx = 0;
2782 2822 uint8_t page_format = 0;
2783 2823 uint32_t page_portid = 0;
2784 2824 uint8_t *page_buf = NULL;
2785 2825 uint8_t *last_page_buf = NULL;
2786 2826 #ifndef lint
2787 2827 fct_cmd_t *ct_cmd = NULL;
2788 2828 fct_local_port_t *port = NULL;
2789 2829 #endif
2790 2830 fct_i_remote_port_t *irp = NULL;
2791 2831
2792 2832 page_buf = rscn_req_payload + 4;
2793 2833 last_page_buf = rscn_req_payload +
2794 2834 fct_netbuf_to_value(rscn_req_payload + 2, 2) - 4;
2795 2835 #ifndef lint
2796 2836 port = iport->iport_port;
2797 2837 #endif
2798 2838 for (; page_buf <= last_page_buf; page_buf += 4) {
2799 2839 page_format = 0x03 & page_buf[0];
2800 2840 page_portid = fct_netbuf_to_value(page_buf + 1, 3);
2801 2841
2802 2842 DTRACE_FC_2(rscn__receive,
2803 2843 fct_i_local_port_t, iport,
2804 2844 int, page_portid);
2805 2845
2806 2846 rw_enter(&iport->iport_lock, RW_READER);
2807 2847 if (!page_format) {
2808 2848 irp = fct_portid_to_portptr(iport, page_portid);
2809 2849 if (!(irp && !(irp->irp_flags & IRP_RSCN_QUEUED))) {
2810 2850 rw_exit(&iport->iport_lock);
2811 2851
2812 2852 continue; /* try next page */
2813 2853 }
2814 2854
2815 2855 if (FC_WELL_KNOWN_ADDR(irp->irp_portid) ||
2816 2856 !(irp->irp_flags & IRP_PLOGI_DONE)) {
2817 2857 rw_exit(&iport->iport_lock);
2818 2858
2819 2859 continue; /* try next page */
2820 2860 }
2821 2861
2822 2862 FCT_VERIFY_RSCN();
2823 2863 } else {
2824 2864 for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) {
2825 2865 for (irp = iport->iport_rp_tb[idx];
2826 2866 irp; irp = irp->irp_next) {
2827 2867 if (FC_WELL_KNOWN_ADDR(irp->irp_portid))
2828 2868 continue; /* try next irp */
2829 2869
2830 2870 if (!(irp->irp_flags & IRP_PLOGI_DONE))
2831 2871 continue; /* try next irp */
2832 2872
2833 2873 if (irp->irp_flags & IRP_RSCN_QUEUED) {
2834 2874 continue; /* try next irp */
2835 2875 }
2836 2876 #ifndef lint
2837 2877 if (!((0xFFFFFF << (page_format * 8)) &
2838 2878 (page_portid ^ irp->irp_portid))) {
2839 2879 FCT_VERIFY_RSCN();
2840 2880 }
2841 2881 #endif
2842 2882 }
2843 2883 }
2844 2884 }
2845 2885 rw_exit(&iport->iport_lock);
2846 2886 }
2847 2887 }
|
↓ open down ↓ |
176 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX