Print this page
5045 use atomic_{inc,dec}_* instead of atomic_add_*
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_eth.c
+++ new/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_eth.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 *
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 /*
23 23 * The following notice accompanied the original version of this file:
24 24 *
25 25 * BSD LICENSE
26 26 *
27 27 * Copyright(c) 2007 Intel Corporation. All rights reserved.
28 28 * All rights reserved.
29 29 *
30 30 * Redistribution and use in source and binary forms, with or without
31 31 * modification, are permitted provided that the following conditions
32 32 * are met:
33 33 *
34 34 * * Redistributions of source code must retain the above copyright
35 35 * notice, this list of conditions and the following disclaimer.
36 36 * * Redistributions in binary form must reproduce the above copyright
37 37 * notice, this list of conditions and the following disclaimer in
38 38 * the documentation and/or other materials provided with the
39 39 * distribution.
40 40 * * Neither the name of Intel Corporation nor the names of its
41 41 * contributors may be used to endorse or promote products derived
42 42 * from this software without specific prior written permission.
43 43 *
44 44 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
45 45 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
46 46 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
47 47 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
48 48 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49 49 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
50 50 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51 51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52 52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53 53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
54 54 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 55 */
56 56
57 57 /*
58 58 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
59 59 */
60 60
61 61 /*
62 62 * This file defines interface functions between fcoe and fcoei driver.
63 63 */
64 64
65 65 #include <sys/conf.h>
66 66 #include <sys/ddi.h>
67 67 #include <sys/stat.h>
68 68 #include <sys/pci.h>
69 69 #include <sys/sunddi.h>
70 70 #include <sys/modctl.h>
71 71 #include <sys/file.h>
72 72 #include <sys/cred.h>
73 73 #include <sys/byteorder.h>
74 74 #include <sys/atomic.h>
75 75 #include <sys/scsi/scsi.h>
76 76 #include <sys/mac_client.h>
77 77 #include <sys/modhash.h>
78 78
79 79 /*
80 80 * LEADVILLE header files
81 81 */
82 82 #include <sys/fibre-channel/fc.h>
83 83 #include <sys/fibre-channel/impl/fc_fcaif.h>
84 84
85 85 /*
86 86 * COMSTAR header files
87 87 */
88 88 #include <sys/stmf_defines.h>
89 89
90 90 /*
91 91 * FCOE header files
92 92 */
93 93 #include <sys/fcoe/fcoe_common.h>
94 94
95 95 /*
96 96 * Driver's own header files
97 97 */
98 98 #include <fcoei.h>
99 99
100 100 /*
101 101 * Forward declaration of internal functions
102 102 */
103 103 static void fcoei_process_unsol_els_req(fcoe_frame_t *frm);
104 104 static void fcoei_process_sol_els_rsp(fcoe_frame_t *frm);
105 105 static void fcoei_process_unsol_abts_req(fcoe_frame_t *frame);
106 106 static void fcoei_process_sol_abts_acc(fcoe_frame_t *frame);
107 107 static void fcoei_process_sol_abts_rjt(fcoe_frame_t *frame);
108 108 static void fcoei_process_sol_ct_rsp(fcoe_frame_t *frame);
109 109 static void fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frame);
110 110 static void fcoei_process_sol_fcp_resp(fcoe_frame_t *frm);
111 111
112 112 static void fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size);
113 113 static void fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch,
114 114 int size);
115 115
116 116 /*
117 117 * fcoei_rx_frame
118 118 * Unsolicited frame is received
119 119 *
120 120 * Input:
121 121 * frame = unsolicited frame that is received
122 122 *
123 123 * Return:
124 124 * N/A
125 125 *
126 126 * Comment:
127 127 * N/A
128 128 */
129 129 static void
130 130 fcoei_rx_frame(fcoe_frame_t *frm)
131 131 {
132 132 if (!(FRM2SS(frm)->ss_flags & SS_FLAG_LV_BOUND)) {
133 133 /*
134 134 * Release the frame and netb
135 135 */
136 136 FCOEI_LOG(__FUNCTION__, "not bound now");
137 137 frm->frm_eport->eport_free_netb(frm->frm_netb);
138 138 frm->frm_eport->eport_release_frame(frm);
139 139 return;
140 140 }
141 141
142 142 FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_UNSOL_FRAME;
143 143 FRM2IFM(frm)->ifm_ae.ae_obj = frm;
144 144
145 145 mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex);
146 146 list_insert_tail(&FRM2SS(frm)->ss_event_list, &FRM2IFM(frm)->ifm_ae);
147 147 if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
148 148 cv_signal(&FRM2SS(frm)->ss_watchdog_cv);
149 149 }
150 150 mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex);
151 151 }
152 152
153 153 /*
154 154 * fcoei_release_sol_frame
155 155 * Release the solicited frame that has just been sent out
156 156 *
157 157 * Input:
158 158 * frame = solicited frame that has been sent out
159 159 *
160 160 * Returns:
161 161 * N/A
162 162 *
163 163 * Comments:
164 164 * After FCOE sends solicited frames out, it will call this to notify
165 165 * FCOEI of the completion.
166 166 */
167 167 static void
168 168 fcoei_release_sol_frame(fcoe_frame_t *frm)
169 169 {
170 170 /*
171 171 * For request-type frames, it's safe to be handled out of
172 172 * watchdog, because it needn't update anything
173 173 */
174 174 switch (FRM2IFM(frm)->ifm_rctl) {
175 175 case R_CTL_SOLICITED_DATA:
176 176 case R_CTL_COMMAND:
177 177 case R_CTL_ELS_REQ:
178 178 case R_CTL_UNSOL_CONTROL:
179 179 case R_CTL_LS_ABTS:
180 180 FRM2SS(frm)->ss_eport->eport_release_frame(frm);
181 181 break;
182 182
183 183 default:
184 184 FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_SOL_FRAME;
185 185 FRM2IFM(frm)->ifm_ae.ae_obj = frm;
186 186
187 187 mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex);
188 188 list_insert_tail(&FRM2SS(frm)->ss_event_list,
189 189 &FRM2IFM(frm)->ifm_ae);
190 190 if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
191 191 cv_signal(&FRM2SS(frm)->ss_watchdog_cv);
192 192 }
193 193 mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex);
194 194 break;
195 195 }
196 196 }
197 197
198 198 /*
199 199 * fcoei_process_unsol_xfer_rdy
200 200 * XFER_RDY is received
201 201 *
202 202 * Input:
203 203 * frm = XFER_RDY frame
204 204 *
205 205 * Returns:
206 206 * N/A
207 207 *
208 208 * Comments:
209 209 * N/A
210 210 */
211 211 static void
212 212 fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frm)
213 213 {
214 214 uint16_t sol_oxid;
215 215 fcoei_exchange_t *xch;
216 216 int rcv_buf_size;
217 217 int offset;
218 218 int left_size;
219 219 int data_size;
220 220 int frm_num;
221 221 int idx;
222 222 fcoe_frame_t *nfrm;
223 223
224 224 sol_oxid = FRM_OXID(frm);
225 225 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
226 226 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
227 227 return;
228 228 }
229 229
230 230 /*
231 231 * rcv_buf_size is the total size of data that should be transferred
232 232 * in this sequence.
233 233 * offset is based on the exchange not the sequence.
234 234 */
235 235 xch->xch_rxid = FRM_RXID(frm);
236 236 rcv_buf_size = FCOE_B2V_4(frm->frm_payload + 4);
237 237 offset = FCOE_B2V_4(frm->frm_payload);
238 238 ASSERT(xch->xch_resid >= rcv_buf_size);
239 239
240 240 /*
241 241 * Local variables initialization
242 242 */
243 243 left_size = rcv_buf_size;
244 244 data_size = FRM2SS(frm)->ss_fcp_data_payload_size;
245 245 frm_num = (rcv_buf_size + data_size - 1) / data_size;
246 246
247 247 for (idx = 0; idx < frm_num - 1; idx++) {
248 248 /*
249 249 * The first (frm_num -1) frames are always full
250 250 */
251 251 nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
252 252 FRM2SS(frm)->ss_eport, data_size + FCFH_SIZE, NULL);
253 253 if (nfrm == NULL) {
254 254 FCOEI_LOG(__FUNCTION__, "can't alloc frame");
255 255 return;
256 256 }
257 257
258 258 /*
259 259 * Copy the data payload that will be transferred
260 260 */
261 261 bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data,
262 262 nfrm->frm_payload, nfrm->frm_payload_size);
263 263
264 264 FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm);
265 265 FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm);
266 266 FFM_F_CTL(0x010008, nfrm);
267 267 FFM_OXID(xch->xch_oxid, nfrm);
268 268 FFM_RXID(xch->xch_rxid, nfrm);
269 269 FFM_S_ID(FRM_D_ID(frm), nfrm);
270 270 FFM_D_ID(FRM_S_ID(frm), nfrm);
271 271 FFM_SEQ_CNT(idx, nfrm);
272 272 FFM_PARAM(offset, nfrm);
273 273 fcoei_init_ifm(nfrm, xch);
274 274
275 275 /*
276 276 * Submit the frame
277 277 */
278 278 xch->xch_ss->ss_eport->eport_tx_frame(nfrm);
279 279
280 280 /*
281 281 * Update offset and left_size
282 282 */
283 283 offset += data_size;
284 284 left_size -= data_size;
285 285 }
286 286
287 287 /*
288 288 * Send the last data frame of this sequence
289 289 */
290 290 data_size = left_size;
291 291 nfrm = xch->xch_ss->ss_eport->eport_alloc_frame(
292 292 xch->xch_ss->ss_eport, data_size + FCFH_SIZE, NULL);
293 293 if (nfrm != NULL) {
294 294 fcoei_init_ifm(nfrm, xch);
295 295 } else {
296 296 ASSERT(0);
297 297 return;
298 298 }
299 299
300 300 /*
301 301 * Copy the data payload that will be transferred
302 302 */
303 303 bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data,
304 304 nfrm->frm_payload, nfrm->frm_payload_size);
305 305
306 306 /*
307 307 * Set ifm_rctl for fcoei_handle_sol_frame_done
308 308 */
309 309 FRM2IFM(nfrm)->ifm_rctl = R_CTL_SOLICITED_DATA;
310 310
311 311 /*
312 312 * FFM
313 313 */
314 314 FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm);
315 315 FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm);
316 316 FFM_F_CTL(0x090008, nfrm);
317 317 FFM_OXID(xch->xch_oxid, nfrm);
318 318 FFM_RXID(xch->xch_rxid, nfrm);
319 319 FFM_S_ID(FRM_D_ID(frm), nfrm);
320 320 FFM_D_ID(FRM_S_ID(frm), nfrm);
321 321 FFM_SEQ_CNT(idx, nfrm);
322 322 FFM_PARAM(offset, nfrm);
323 323
324 324 /*
325 325 * Submit the frame
326 326 */
327 327 xch->xch_ss->ss_eport->eport_tx_frame(nfrm);
328 328
329 329 /*
330 330 * Sequence is a transaction, so we need only update
331 331 * xch_remained_bytes in the end.
332 332 */
333 333 xch->xch_resid -= rcv_buf_size;
334 334 }
335 335
336 336 /*
337 337 * fcoei_process_unsol_els_req
338 338 * els req frame is received
339 339 *
340 340 * Input:
341 341 * frm = ELS request frame
342 342 *
343 343 * Returns:
344 344 * N/A
345 345 *
346 346 * Comments:
347 347 * We will not create exchange data structure at this time,
348 348 * and we should create unsolicited buffer, which will only
349 349 * contain the exchange's request payload.
350 350 */
351 351 static void
352 352 fcoei_process_unsol_els_req(fcoe_frame_t *frm)
353 353 {
354 354 fc_unsol_buf_t *ub;
355 355 fc_rscn_t *rscn;
356 356 uint32_t offset;
357 357 fcoei_exchange_t *xch_tmp;
358 358
359 359 /*
360 360 * Get the unsol rxid first
361 361 */
362 362 FCOEI_SET_UNSOL_FRM_RXID(frm, xch_tmp);
363 363
364 364 /*
365 365 * Do proper ub initialization
366 366 */
367 367 ub = (fc_unsol_buf_t *)kmem_zalloc(sizeof (fc_unsol_buf_t), KM_SLEEP);
368 368 ub->ub_class = FC_TRAN_CLASS3;
369 369 ub->ub_bufsize = frm->frm_payload_size;
370 370 ub->ub_buffer = kmem_alloc(frm->frm_payload_size, KM_SLEEP);
371 371 ub->ub_port_handle = FRM2SS(frm);
372 372 ub->ub_token = (uint64_t)(long)ub;
373 373
374 374 /*
375 375 * header conversion
376 376 * Caution: ub_buffer is big endian, but ub_frame should be host-format
377 377 * RSCN is one exception.
378 378 */
379 379 FCOEI_FRM2FHDR(frm, &ub->ub_frame);
380 380
381 381 /*
382 382 * If it's FLOGI, and our FLOGI failed last time,
383 383 * then we post online event
384 384 */
385 385 if ((FRM2SS(frm)->ss_flags & SS_FLAG_FLOGI_FAILED) &&
386 386 (frm->frm_payload[0] == LA_ELS_FLOGI)) {
387 387 frm->frm_eport->eport_flags |=
388 388 EPORT_FLAG_IS_DIRECT_P2P;
389 389 FRM2SS(frm)->ss_bind_info.port_statec_cb(FRM2SS(frm)->ss_port,
390 390 FC_STATE_ONLINE);
391 391 }
392 392
393 393 switch (frm->frm_payload[0]) {
394 394 case LA_ELS_RSCN:
395 395 /*
396 396 * Only RSCN need byte swapping
397 397 */
398 398 rscn = (fc_rscn_t *)(void *)ub->ub_buffer;
399 399 rscn->rscn_code = frm->frm_payload[0];
400 400 rscn->rscn_len = frm->frm_payload[1];
401 401 rscn->rscn_payload_len =
402 402 FCOE_B2V_2(frm->frm_payload + 2);
403 403
404 404 offset = 4;
405 405 for (int i = 0; i < rscn->rscn_payload_len - 4; i += 4) {
406 406 *(uint32_t *)((intptr_t)(uint8_t *)ub->ub_buffer +
407 407 offset) = FCOE_B2V_4(frm->frm_payload + offset);
408 408 offset += 4;
409 409 }
410 410 break;
411 411
412 412 default:
413 413 bcopy(frm->frm_payload, ub->ub_buffer, frm->frm_payload_size);
414 414 break;
415 415 }
416 416
417 417 /*
418 418 * Pass this unsol ELS up to Leadville
419 419 */
420 420 FRM2SS(frm)->ss_bind_info.port_unsol_cb(FRM2SS(frm)->ss_port, ub, 0);
421 421 }
422 422
423 423 /*
424 424 * fcoei_search_abort_xch
425 425 * Find the exchange that should be aborted
426 426 *
427 427 * Input:
428 428 * key = oxid of the exchange
429 429 * val = the exchange
430 430 * arg = the soft state
431 431 *
432 432 * Returns:
433 433 * MH_WALK_TERMINATE = found it, terminate the walk
434 434 * MH_WALK_CONTINUE = not found, continue the walk
435 435 *
436 436 * Comments:
437 437 * N/A
438 438 */
439 439 /* ARGSUSED */
440 440 static uint32_t
441 441 fcoei_search_abort_xch(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
442 442 {
443 443 fcoei_walk_arg_t *wa = (fcoei_walk_arg_t *)arg;
444 444 fcoei_exchange_t *xch = (fcoei_exchange_t *)val;
445 445
446 446 if (xch->xch_oxid == wa->wa_oxid) {
447 447 wa->wa_xch = xch;
448 448 ASSERT(xch->xch_oxid == CMHK(key));
449 449 return (MH_WALK_TERMINATE);
450 450 }
451 451
452 452 return (MH_WALK_CONTINUE);
453 453 }
454 454
455 455 /*
456 456 * fcoei_process_unsol_abts_req
457 457 * ABTS request is received
458 458 *
459 459 * Input:
460 460 * frm = ABTS request frame
461 461 *
462 462 * Returns:
463 463 * N/A
464 464 *
465 465 * Comments:
466 466 * The remote side wants to abort one unsolicited exchange.
467 467 */
468 468 static void
469 469 fcoei_process_unsol_abts_req(fcoe_frame_t *frm)
470 470 {
471 471 fcoei_exchange_t *xch = NULL;
472 472 fcoe_frame_t *nfrm;
473 473 int payload_size;
474 474 fcoei_walk_arg_t walk_arg;
475 475
476 476 /*
477 477 * According to spec, the responder could want to ABTS xch too
478 478 */
479 479 if (FRM_SENDER_IS_XCH_RESPONDER(frm)) {
480 480 uint16_t sol_oxid = FRM_OXID(frm);
481 481 (void) mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
482 482 FMHK(sol_oxid), (mod_hash_val_t *)&xch);
483 483 } else {
484 484 /*
485 485 * it's a unsolicited exchange, and we need find it out from
486 486 * unsolicited hash table. But at this time, RXID in frame could
487 487 * still be 0xFFFF in most cases, so we need do exaustive search
488 488 */
489 489 walk_arg.wa_xch = NULL;
490 490 walk_arg.wa_oxid = FRM_OXID(frm);
491 491 mod_hash_walk(FRM2SS(frm)->ss_unsol_rxid_hash,
492 492 fcoei_search_abort_xch, &walk_arg);
493 493 xch = walk_arg.wa_xch;
494 494 }
495 495
496 496 if (xch == NULL) {
497 497 payload_size = 4;
498 498 nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
499 499 FRM2SS(frm)->ss_eport,
500 500 payload_size + FCFH_SIZE, NULL);
501 501 if (nfrm == NULL) {
502 502 FCOEI_LOG(__FUNCTION__, "can't alloc frame");
503 503 return;
504 504 }
505 505
506 506 bzero(nfrm->frm_payload, nfrm->frm_payload_size);
507 507 nfrm->frm_payload[1] = 0x05;
508 508 nfrm->frm_payload[3] = 0xAA;
509 509 FFM_R_CTL(R_CTL_LS_BA_RJT, nfrm);
510 510 fcoei_init_ifm(nfrm, xch);
511 511 } else {
512 512 /*
513 513 * We should complete the exchange with frm as NULL,
514 514 * and we don't care its success or failure
515 515 */
516 516 fcoei_complete_xch(xch, NULL, FC_PKT_FAILURE, FC_REASON_ABTX);
517 517
518 518 /*
519 519 * Construct ABTS ACC frame
520 520 */
521 521 payload_size = 12;
522 522 nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
523 523 FRM2SS(frm)->ss_eport, payload_size + FCFH_SIZE, NULL);
524 524 if (nfrm == NULL) {
525 525 FCOEI_LOG(__FUNCTION__, "can't alloc frame");
526 526 return;
527 527 }
528 528
529 529 bzero(nfrm->frm_payload, nfrm->frm_payload_size);
530 530 nfrm->frm_payload[4] = 0xFF & (xch->xch_oxid >> 8);
531 531 nfrm->frm_payload[5] = 0xFF & (xch->xch_oxid);
532 532 nfrm->frm_payload[6] = 0xFF & (xch->xch_rxid >> 8);
533 533 nfrm->frm_payload[7] = 0xFF & (xch->xch_rxid);
534 534 nfrm->frm_payload[10] = 0xFF;
535 535 nfrm->frm_payload[11] = 0xFF;
536 536
537 537 FFM_R_CTL(R_CTL_LS_BA_ACC, nfrm);
538 538 fcoei_init_ifm(nfrm, xch);
539 539 }
540 540
541 541 FFM_D_ID(FRM_S_ID(frm), nfrm);
542 542 FFM_S_ID(FRM_D_ID(frm), nfrm);
543 543 FFM_TYPE(FRM_TYPE(frm), nfrm);
544 544 FFM_F_CTL(FRM_F_CTL(frm), nfrm);
545 545 FFM_OXID(FRM_OXID(frm), nfrm);
546 546 FFM_RXID(FRM_RXID(frm), nfrm);
547 547 FRM2SS(frm)->ss_eport->eport_tx_frame(nfrm);
548 548 }
549 549
550 550 /*
551 551 * fcoei_process_sol_fcp_resp
552 552 * FCP response is received
553 553 *
554 554 * Input:
555 555 * frm = FCP response frame
556 556 *
557 557 * Returns:
558 558 * N/A
559 559 *
560 560 * Comments:
561 561 * N/A
562 562 */
563 563 static void
564 564 fcoei_process_sol_fcp_resp(fcoe_frame_t *frm)
565 565 {
566 566 uint16_t sol_oxid;
567 567 uint32_t actual_size;
568 568 fcoei_exchange_t *xch = NULL;
569 569 fc_packet_t *fpkt = NULL;
570 570 mod_hash_val_t val;
571 571 uint32_t i_fcp_status;
572 572
573 573 /*
574 574 * Firstly, we search the related exchange
575 575 */
576 576 sol_oxid = FRM_OXID(frm);
577 577 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
578 578 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
579 579 PRT_FRM_HDR(__FUNCTION__, frm);
580 580 FCOEI_LOG(__FUNCTION__, "can't find the corresponding xch: "
581 581 "oxid/%x %lu - %lu", sol_oxid,
582 582 CURRENT_CLOCK, frm->frm_clock);
583 583 return;
584 584 } else {
585 585 fpkt = xch->xch_fpkt;
586 586 }
587 587
588 588 /*
589 589 * Decide the actual response length
590 590 */
591 591 actual_size = fpkt->pkt_rsplen;
592 592 if (actual_size > frm->frm_payload_size) {
593 593 actual_size = frm->frm_payload_size;
594 594 }
595 595
596 596 /*
597 597 * Update the exchange and hash table
598 598 */
599 599 (void) mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
600 600 FMHK(xch->xch_oxid), &val);
601 601 ASSERT((fcoei_exchange_t *)val == xch);
602 602 xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH;
603 603
604 604 /*
605 605 * Upate fpkt related elements
606 606 */
607 607 FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
608 608
609 609 /*
610 610 * we should set pkt_reason and pkt_state carefully
611 611 */
612 612 fpkt->pkt_state = FC_PKT_SUCCESS;
613 613 fpkt->pkt_reason = 0;
614 614
615 615 /*
616 616 * First we zero the first 12 byte of dest
617 617 */
618 618 bzero(xch->xch_fpkt->pkt_resp, 12);
619 619 i_fcp_status = BE_IN32(frm->frm_payload + 8);
620 620 if (i_fcp_status != 0) {
621 621 fcoei_fill_fcp_resp(frm->frm_payload,
622 622 (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size);
623 623 }
624 624
625 625 /*
626 626 * Update pkt_resp_resid
627 627 */
628 628 fpkt->pkt_data_resid = xch->xch_resid;
629 629 if ((xch->xch_resid != 0) && ((xch->xch_resid % 0x200) == 0) &&
630 630 ((xch->xch_fpkt->pkt_datalen % 0x200) == 0) &&
631 631 (i_fcp_status == 0)) {
632 632 FCOEI_LOG(__FUNCTION__, "frame lost no pause ? %x/%x",
633 633 xch->xch_resid, xch->xch_fpkt->pkt_datalen);
634 634 fpkt->pkt_state = FC_PKT_LOCAL_RJT;
635 635 fpkt->pkt_reason = FC_REASON_UNDERRUN;
636 636 }
637 637
638 638 /*
639 639 * Notify LV it's over
640 640 */
641 641 if (fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
642 642 FCOEI_LOG(__FUNCTION__, "BEFORE WAKEUP: %p-%p", fpkt, xch);
643 643 sema_v(&xch->xch_sema);
644 644 FCOEI_LOG(__FUNCTION__, "AFTERE WAKEUP: %p-%p", fpkt, xch);
645 645 } else {
646 646 xch->xch_fpkt->pkt_comp(xch->xch_fpkt);
647 647 }
648 648 }
649 649
650 650 /*
651 651 * fcoei_process_sol_els_rsp
652 652 * ELS response is received
653 653 *
654 654 * Input:
655 655 * frm = ELS response frame
656 656 *
657 657 * Returns:
658 658 * N/A
659 659 *
660 660 * Comments:
661 661 * N/A
662 662 */
663 663 static void
664 664 fcoei_process_sol_els_rsp(fcoe_frame_t *frm)
665 665 {
666 666 uint16_t sol_oxid = 0;
667 667 uint32_t actual_size = 0;
668 668 fcoei_exchange_t *xch;
669 669 fc_packet_t *fpkt;
670 670
671 671 /*
672 672 * Look for the related exchange
673 673 */
674 674 xch = NULL;
675 675 fpkt = NULL;
676 676 sol_oxid = FRM_OXID(frm);
677 677 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
678 678 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
679 679 PRT_FRM_HDR(__FUNCTION__, frm);
680 680 FCOEI_LOG(__FUNCTION__, "can't find the "
681 681 "corresponding xch: oxid/%x", sol_oxid);
682 682 return;
683 683 }
684 684
685 685 xch->xch_rxid = FRM_RXID(frm);
686 686 fpkt = xch->xch_fpkt;
687 687
688 688 /*
689 689 * Decide the actual response length
690 690 */
691 691 actual_size = frm->frm_payload_size;
692 692 if (actual_size > fpkt->pkt_rsplen) {
693 693 FCOEI_LOG(__FUNCTION__, "pkt_rsplen is smaller"
694 694 "0x(%x - %x)", actual_size, fpkt->pkt_rsplen);
695 695 actual_size = fpkt->pkt_rsplen;
696 696 }
697 697
698 698 /*
699 699 * Upate fpkt related elements
700 700 */
701 701 FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
702 702 fcoei_fill_els_fpkt_resp(frm, xch, actual_size);
703 703
704 704 /*
705 705 * we should set pkt_reason and pkt_state carefully now
706 706 * Need to analyze pkt_reason according to the response.
707 707 * Leave it untouched now.
708 708 */
709 709 if (((ls_code_t *)(void *)xch->xch_fpkt->pkt_resp)->ls_code ==
710 710 LA_ELS_RJT) {
711 711 fcoei_complete_xch(xch, NULL, FC_PKT_FABRIC_RJT,
712 712 FC_REASON_INVALID_PARAM);
713 713 } else {
714 714 fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
715 715 }
716 716 }
717 717
718 718 /*
719 719 * fcoei_process_sol_ct_rsp
720 720 * CT response is received
721 721 *
722 722 * Input:
723 723 * frm = CT response frame
724 724 *
725 725 * Returns:
726 726 * N/A
727 727 *
728 728 * Comments:
729 729 * N/A
730 730 */
731 731 static void
732 732 fcoei_process_sol_ct_rsp(fcoe_frame_t *frm)
733 733 {
734 734 uint16_t sol_oxid = 0;
735 735 uint32_t actual_size = 0;
736 736 fcoei_exchange_t *xch;
737 737 fc_packet_t *fpkt;
738 738
739 739 /*
740 740 * Look for the related exchange
741 741 */
742 742 xch = NULL;
743 743 fpkt = NULL;
744 744 sol_oxid = FRM_OXID(frm);
745 745 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
746 746 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
747 747 FCOEI_LOG(__FUNCTION__, "can't find the "
748 748 "corresponding xch: oxid/%x", sol_oxid);
749 749 return;
750 750 }
751 751
752 752 xch->xch_rxid = FRM_RXID(frm);
753 753 fpkt = xch->xch_fpkt;
754 754
755 755 /*
756 756 * Decide the actual response length
757 757 */
758 758 actual_size = fpkt->pkt_rsplen;
759 759 if (actual_size > frm->frm_payload_size) {
760 760 FCOEI_LOG(__FUNCTION__, "payload is smaller"
761 761 "0x(%x - %x)", actual_size, frm->frm_payload_size);
762 762 actual_size = frm->frm_payload_size;
763 763 }
764 764
765 765 /*
766 766 * Update fpkt related elements
767 767 * Caution: we needn't do byte swapping for CT response
768 768 */
769 769 FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
770 770 bcopy(FPLD, (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size);
771 771
772 772 /*
773 773 * Complete it with frm as NULL
774 774 */
775 775 fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
776 776 }
777 777
778 778 /*
779 779 * fcoei_process_sol_abts_acc
780 780 * ABTS accpet is received
781 781 *
782 782 * Input:
783 783 * frm = ABTS accept frame
784 784 *
785 785 * Returns:
786 786 * N/A
787 787 *
788 788 * Comments:
789 789 * We will always finish the abortion of solicited exchanges,
790 790 * so we will not depend on the response from the remote side.
791 791 * We just log one message.
792 792 */
793 793 static void
794 794 fcoei_process_sol_abts_acc(fcoe_frame_t *frm)
795 795 {
796 796 FCOEI_LOG(__FUNCTION__, "the remote side has agreed to "
797 797 "abort the exchange: oxid-%x, rxid-%x",
798 798 FCOE_B2V_2(frm->frm_payload + 4),
799 799 FCOE_B2V_2(frm->frm_payload + 6));
800 800 }
801 801
802 802 /*
803 803 * fcoei_process_sol_abts_rjt
804 804 * ABTS reject is received
805 805 *
806 806 * Input:
807 807 * frm = ABTS reject frame
808 808 *
809 809 * Returns:
810 810 * N/A
811 811 *
812 812 * Comments:
813 813 * We will alwayas finish the abortion of solicited exchanges,
814 814 * so we will not depend on the response from the remote side.
815 815 * We just log one message.
816 816 */
817 817 static void
818 818 fcoei_process_sol_abts_rjt(fcoe_frame_t *frm)
819 819 {
820 820 FCOEI_LOG(__FUNCTION__, "the remote side rejected "
821 821 "our request to abort one exchange.: %p", frm);
822 822 }
823 823
824 824 /*
825 825 * fcoei_fill_els_fpkt_resp
826 826 * Fill fpkt ELS response in host format according frm payload
827 827 *
828 828 * Input:
829 829 * src = frm payload in link format
830 830 * dest = fpkt ELS response in host format
831 831 * size = Maximum conversion size
832 832 * els_op = ELS opcode
833 833 *
834 834 * Returns:
835 835 * N/A
836 836 *
837 837 * Comments:
838 838 * fpkt->pkt_resp must be mapped to one data structure, and it's
839 839 * different from the content in the raw frame
840 840 */
841 841 static void
842 842 fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch, int size)
843 843 {
844 844 uint8_t *src = frm->frm_payload;
845 845 uint8_t *dest = (uint8_t *)xch->xch_fpkt->pkt_resp;
846 846 ls_code_t *els_code = (ls_code_t *)(void *)dest;
847 847 la_els_logi_t *els_logi = (la_els_logi_t *)(void *)dest;
848 848 la_els_adisc_t *els_adisc = (la_els_adisc_t *)(void *)dest;
849 849 la_els_rls_acc_t *els_rls;
850 850 la_els_rnid_acc_t *els_rnid;
851 851 struct fcp_prli_acc *prli_acc;
852 852 int offset;
853 853
854 854 els_code->ls_code = FCOE_B2V_1(src);
855 855 if (els_code->ls_code == LA_ELS_RJT) {
856 856 FCOEI_LOG(__FUNCTION__, "size :%d", size);
857 857 return;
858 858 }
859 859
860 860 switch (((ls_code_t *)(void *)xch->xch_fpkt->pkt_cmd)->ls_code) {
861 861 case LA_ELS_FLOGI:
862 862 bcopy((char *)frm->frm_hdr - 22,
863 863 frm->frm_eport->eport_efh_dst, ETHERADDRL);
864 864 if (frm->frm_payload[8] & 0x10) {
865 865 /*
866 866 * We are in fabric p2p mode
867 867 */
868 868 uint8_t src_addr[ETHERADDRL];
869 869 frm->frm_eport->eport_flags &=
870 870 ~EPORT_FLAG_IS_DIRECT_P2P;
871 871 FCOE_SET_DEFAULT_OUI(src_addr);
872 872 bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3);
873 873 frm->frm_eport->eport_set_mac_address(
874 874 frm->frm_eport, src_addr, 1);
875 875 } else {
876 876 /*
877 877 * We are in direct p2p mode
878 878 */
879 879 frm->frm_eport->eport_flags |=
880 880 EPORT_FLAG_IS_DIRECT_P2P;
881 881 }
882 882
883 883 if (!(FRM2SS(frm)->ss_eport->eport_flags &
884 884 EPORT_FLAG_IS_DIRECT_P2P)) {
885 885 FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm);
886 886 }
887 887
888 888 /* FALLTHROUGH */
889 889
890 890 case LA_ELS_PLOGI:
891 891 if (FRM2SS(frm)->ss_eport->eport_flags &
892 892 EPORT_FLAG_IS_DIRECT_P2P) {
893 893 FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm);
894 894 FRM2SS(frm)->ss_p2p_info.d_id = FRM_S_ID(frm);
895 895 }
896 896
897 897 offset = offsetof(la_els_logi_t, common_service);
898 898 els_logi->common_service.fcph_version = FCOE_B2V_2(src +
899 899 offset);
900 900 offset += 2;
901 901 els_logi->common_service.btob_credit = FCOE_B2V_2(src +
902 902 offset);
903 903 offset += 2;
904 904 els_logi->common_service.cmn_features = FCOE_B2V_2(src +
905 905 offset);
906 906 offset += 2;
907 907 els_logi->common_service.rx_bufsize = FCOE_B2V_2(src +
908 908 offset);
909 909 offset += 2;
910 910 els_logi->common_service.conc_sequences = FCOE_B2V_2(src +
911 911 offset);
912 912 offset += 2;
913 913 els_logi->common_service.relative_offset = FCOE_B2V_2(src +
914 914 offset);
915 915 offset += 2;
916 916 els_logi->common_service.e_d_tov = FCOE_B2V_4(src +
917 917 offset);
918 918
919 919 /*
920 920 * port/node WWN
921 921 */
922 922 offset = offsetof(la_els_logi_t, nport_ww_name);
923 923 bcopy(src + offset, &els_logi->nport_ww_name, 8);
924 924 offset = offsetof(la_els_logi_t, node_ww_name);
925 925 bcopy(src + offset, &els_logi->node_ww_name, 8);
926 926
927 927 /*
928 928 * class_3
929 929 */
930 930 offset = offsetof(la_els_logi_t, class_3);
931 931 els_logi->class_3.class_opt = FCOE_B2V_2(src + offset);
932 932 offset += 2;
933 933 els_logi->class_3.initiator_ctl = FCOE_B2V_2(src + offset);
934 934 offset += 2;
935 935 els_logi->class_3.recipient_ctl = FCOE_B2V_2(src + offset);
936 936 offset += 2;
937 937 els_logi->class_3.rcv_size = FCOE_B2V_2(src + offset);
938 938 offset += 2;
939 939 els_logi->class_3.conc_sequences = FCOE_B2V_2(src + offset);
940 940 offset += 2;
941 941 els_logi->class_3.n_port_e_to_e_credit = FCOE_B2V_2(src +
942 942 offset);
943 943 offset += 2;
944 944 els_logi->class_3.open_seq_per_xchng = FCOE_B2V_2(src + offset);
945 945
946 946 break;
947 947
948 948 case LA_ELS_PRLI:
949 949 /*
950 950 * PRLI service parameter response page
951 951 *
952 952 * fcp_prli_acc doesn't include ls_code, don't use offsetof
953 953 */
954 954 offset = 4;
955 955 prli_acc = (struct fcp_prli_acc *)(void *)(dest + offset);
956 956 prli_acc->type = FCOE_B2V_1(src + offset);
957 957 /*
958 958 * Type code extension
959 959 */
960 960 offset += 1;
961 961 /*
962 962 * PRLI response flags
963 963 */
964 964 offset += 1;
965 965 prli_acc->orig_process_assoc_valid =
966 966 (FCOE_B2V_2(src + offset) & BIT_15) ? 1 : 0;
967 967 prli_acc->resp_process_assoc_valid =
968 968 (FCOE_B2V_2(src + offset) & BIT_14) ? 1 : 0;
969 969 prli_acc->image_pair_established =
970 970 (FCOE_B2V_2(src + offset) & BIT_13) ? 1 : 0;
971 971 prli_acc->accept_response_code =
972 972 (FCOE_B2V_2(src + offset) & 0x0F00) >> 8;
973 973 /*
974 974 * process associator
975 975 */
976 976 offset += 2;
977 977 prli_acc->orig_process_associator = FCOE_B2V_4(src + offset);
978 978 offset += 4;
979 979 prli_acc->resp_process_associator = FCOE_B2V_4(src + offset);
980 980 /*
981 981 * FC-4 type
982 982 */
983 983 offset += 4;
984 984 prli_acc->initiator_fn =
985 985 (FCOE_B2V_4(src + offset) & BIT_5) ? 1 : 0;
986 986 prli_acc->target_fn =
987 987 (FCOE_B2V_4(src + offset) & BIT_4) ? 1 : 0;
988 988 prli_acc->cmd_data_mixed =
989 989 (FCOE_B2V_4(src + offset) & BIT_3) ? 1 : 0;
990 990 prli_acc->data_resp_mixed =
991 991 (FCOE_B2V_4(src + offset) & BIT_2) ? 1 : 0;
992 992 prli_acc->read_xfer_rdy_disabled =
993 993 (FCOE_B2V_4(src + offset) & BIT_1) ? 1 : 0;
994 994 prli_acc->write_xfer_rdy_disabled =
995 995 (FCOE_B2V_4(src + offset) & BIT_0) ? 1 : 0;
996 996
997 997 break;
998 998
999 999 case LA_ELS_LOGO:
1000 1000 /*
1001 1001 * could only be LS_ACC, no additional information
1002 1002 */
1003 1003 els_code->ls_code = FCOE_B2V_1(src);
1004 1004 break;
1005 1005
1006 1006 case LA_ELS_SCR:
1007 1007 /*
1008 1008 * LS_ACC/LS_RJT, no additional information
1009 1009 */
1010 1010 els_code->ls_code = FCOE_B2V_1(src);
1011 1011 break;
1012 1012
1013 1013 case LA_ELS_ADISC:
1014 1014 offset = 5;
1015 1015 els_adisc->hard_addr.hard_addr = FCOE_B2V_3(src + offset);
1016 1016 offset = offsetof(la_els_adisc_t, port_wwn);
1017 1017 bcopy(src + offset, &els_adisc->port_wwn, 8);
1018 1018 offset = offsetof(la_els_adisc_t, node_wwn);
1019 1019 bcopy(src + offset, &els_adisc->node_wwn, 8);
1020 1020 offset += 9;
1021 1021 els_adisc->nport_id.port_id = FCOE_B2V_3(src + offset);
1022 1022 break;
1023 1023 case LA_ELS_RLS:
1024 1024 els_rls = (la_els_rls_acc_t *)(void *)dest;
1025 1025 els_rls->ls_code.ls_code = FCOE_B2V_1(src);
1026 1026 offset = 4;
1027 1027 els_rls->rls_link_params.rls_link_fail =
1028 1028 FCOE_B2V_4(src + offset);
1029 1029 offset = 8;
1030 1030 els_rls->rls_link_params.rls_sync_loss =
1031 1031 FCOE_B2V_4(src + offset);
1032 1032 offset = 12;
1033 1033 els_rls->rls_link_params.rls_sig_loss =
1034 1034 FCOE_B2V_4(src + offset);
1035 1035 offset = 16;
1036 1036 els_rls->rls_link_params.rls_prim_seq_err =
1037 1037 FCOE_B2V_4(src + offset);
1038 1038 offset = 20;
1039 1039 els_rls->rls_link_params.rls_invalid_word =
1040 1040 FCOE_B2V_4(src + offset);
1041 1041 offset = 24;
1042 1042 els_rls->rls_link_params.rls_invalid_crc =
1043 1043 FCOE_B2V_4(src + offset);
1044 1044 break;
1045 1045 case LA_ELS_RNID:
1046 1046 els_rnid = (la_els_rnid_acc_t *)(void *)dest;
1047 1047 els_rnid->ls_code.ls_code = FCOE_B2V_1(src);
1048 1048 offset = 4;
1049 1049 bcopy(src + offset, &els_rnid->hdr.data_format, 1);
1050 1050 offset = 5;
1051 1051 bcopy(src + offset, &els_rnid->hdr.cmn_len, 1);
1052 1052 offset = 7;
1053 1053 bcopy(src + offset, &els_rnid->hdr.specific_len, 1);
1054 1054 offset = 8;
1055 1055 bcopy(src + offset, els_rnid->data, FCIO_RNID_MAX_DATA_LEN);
1056 1056 break;
1057 1057 default:
1058 1058 FCOEI_LOG(__FUNCTION__, "unsupported R_CTL");
1059 1059 break;
1060 1060 }
1061 1061 }
1062 1062
1063 1063 /*
1064 1064 * fcoei_fill_fcp_resp
1065 1065 * Fill fpkt FCP response in host format according to frm payload
1066 1066 *
1067 1067 * Input:
1068 1068 * src - frm payload in link format
1069 1069 * dest - fpkt FCP response in host format
1070 1070 * size - Maximum conversion size
1071 1071 *
1072 1072 * Returns:
1073 1073 * N/A
1074 1074 *
1075 1075 * Comments:
1076 1076 * This is called only for SCSI response with non good status
1077 1077 */
1078 1078 static void
1079 1079 fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size)
1080 1080 {
1081 1081 fcp_rsp_t *fcp_rsp_iu = (fcp_rsp_t *)(void *)dest;
1082 1082 int offset;
1083 1083
1084 1084 /*
1085 1085 * set fcp_status
1086 1086 */
1087 1087 offset = offsetof(fcp_rsp_t, fcp_u);
1088 1088 offset += 2;
1089 1089 fcp_rsp_iu->fcp_u.fcp_status.resid_under =
1090 1090 (FCOE_B2V_1(src + offset) & BIT_3) ? 1 : 0;
1091 1091 fcp_rsp_iu->fcp_u.fcp_status.resid_over =
1092 1092 (FCOE_B2V_1(src + offset) & BIT_2) ? 1 : 0;
1093 1093 fcp_rsp_iu->fcp_u.fcp_status.sense_len_set =
1094 1094 (FCOE_B2V_1(src + offset) & BIT_1) ? 1 : 0;
1095 1095 fcp_rsp_iu->fcp_u.fcp_status.rsp_len_set =
1096 1096 (FCOE_B2V_1(src + offset) & BIT_0) ? 1 : 0;
1097 1097 offset += 1;
1098 1098 fcp_rsp_iu->fcp_u.fcp_status.scsi_status = FCOE_B2V_1(src + offset);
1099 1099 /*
1100 1100 * fcp_resid/fcp_sense_len/fcp_response_len
1101 1101 */
1102 1102 offset = offsetof(fcp_rsp_t, fcp_resid);
1103 1103 fcp_rsp_iu->fcp_resid = FCOE_B2V_4(src + offset);
1104 1104 offset = offsetof(fcp_rsp_t, fcp_sense_len);
1105 1105 fcp_rsp_iu->fcp_sense_len = FCOE_B2V_4(src + offset);
1106 1106 offset = offsetof(fcp_rsp_t, fcp_response_len);
1107 1107 fcp_rsp_iu->fcp_response_len = FCOE_B2V_4(src + offset);
1108 1108 /*
1109 1109 * sense or response
1110 1110 */
1111 1111 offset += 4;
1112 1112 if (fcp_rsp_iu->fcp_sense_len) {
1113 1113 if ((offset + fcp_rsp_iu->fcp_sense_len) > size) {
1114 1114 FCOEI_LOG(__FUNCTION__, "buffer too small - sens");
1115 1115 return;
1116 1116 }
1117 1117 bcopy(src + offset, dest + offset, fcp_rsp_iu->fcp_sense_len);
1118 1118 offset += fcp_rsp_iu->fcp_sense_len;
1119 1119 }
1120 1120
1121 1121 if (fcp_rsp_iu->fcp_response_len) {
1122 1122 if ((offset + fcp_rsp_iu->fcp_response_len) > size) {
1123 1123 FCOEI_LOG(__FUNCTION__, "buffer too small - resp");
1124 1124 return;
1125 1125 }
1126 1126 bcopy(src + offset, dest + offset,
1127 1127 fcp_rsp_iu->fcp_response_len);
1128 1128 }
1129 1129 }
1130 1130
1131 1131 void
1132 1132 fcoei_init_ect_vectors(fcoe_client_t *ect)
1133 1133 {
1134 1134 ect->ect_rx_frame = fcoei_rx_frame;
1135 1135 ect->ect_port_event = fcoei_port_event;
1136 1136 ect->ect_release_sol_frame = fcoei_release_sol_frame;
1137 1137 }
1138 1138
1139 1139 /*
1140 1140 * fcoei_process_unsol_frame
1141 1141 * Unsolicited frame is received
1142 1142 *
1143 1143 * Input:
1144 1144 * frame = unsolicited frame that is received
1145 1145 *
1146 1146 * Returns:
1147 1147 * N/A
1148 1148 *
1149 1149 * Comments:
1150 1150 * watchdog will call this to process unsolicited frames that we
1151 1151 * just received fcoei_process_xx is used to handle different
1152 1152 * unsolicited frames
1153 1153 */
1154 1154 void
1155 1155 fcoei_process_unsol_frame(fcoe_frame_t *frm)
1156 1156 {
1157 1157 fcoei_exchange_t *xch;
1158 1158 uint16_t sol_oxid;
1159 1159
1160 1160 switch (FRM_R_CTL(frm)) {
1161 1161 case R_CTL_SOLICITED_DATA:
1162 1162 /*
1163 1163 * READ data phase frame
1164 1164 * Find the associated exchange
1165 1165 */
1166 1166 sol_oxid = FRM_OXID(frm);
1167 1167 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
1168 1168 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
1169 1169 PRT_FRM_HDR(__FUNCTION__, frm);
1170 1170 FCOEI_LOG(__FUNCTION__, "associated xch not found: "
1171 1171 "oxid/%x %lu - %lu", sol_oxid,
1172 1172 CURRENT_CLOCK, frm->frm_clock);
1173 1173 break;
1174 1174 }
1175 1175
1176 1176 /*
1177 1177 * Copy data into fpkt data buffer, and update the counter
1178 1178 */
1179 1179 bcopy(frm->frm_payload, (uint8_t *)xch->xch_fpkt->pkt_data +
1180 1180 FRM_PARAM(frm), frm->frm_payload_size);
1181 1181 xch->xch_resid -= frm->frm_payload_size;
1182 1182 xch->xch_rxid = FRM_RXID(frm);
1183 1183 break;
1184 1184
1185 1185 case R_CTL_XFER_RDY:
1186 1186 fcoei_process_unsol_xfer_rdy(frm);
1187 1187 break;
1188 1188
1189 1189 case R_CTL_STATUS:
1190 1190 fcoei_process_sol_fcp_resp(frm);
1191 1191 break;
1192 1192
1193 1193 case R_CTL_ELS_REQ:
1194 1194 fcoei_process_unsol_els_req(frm);
1195 1195 break;
1196 1196
1197 1197 case R_CTL_LS_ABTS:
1198 1198 fcoei_process_unsol_abts_req(frm);
1199 1199 break;
1200 1200
1201 1201 case R_CTL_ELS_RSP:
1202 1202 fcoei_process_sol_els_rsp(frm);
1203 1203 break;
1204 1204
1205 1205 case R_CTL_SOLICITED_CONTROL:
1206 1206 fcoei_process_sol_ct_rsp(frm);
1207 1207 break;
1208 1208
1209 1209 case R_CTL_LS_BA_ACC:
1210 1210 fcoei_process_sol_abts_acc(frm);
1211 1211 break;
1212 1212
1213 1213 case R_CTL_LS_BA_RJT:
1214 1214 fcoei_process_sol_abts_rjt(frm);
1215 1215 break;
1216 1216
1217 1217 default:
1218 1218 /*
1219 1219 * Unsupported frame
1220 1220 */
1221 1221 PRT_FRM_HDR("Unsupported unsol frame: ", frm);
1222 1222 }
1223 1223
1224 1224 /*
1225 1225 * Release the frame and netb
1226 1226 */
1227 1227 frm->frm_eport->eport_free_netb(frm->frm_netb);
1228 1228 frm->frm_eport->eport_release_frame(frm);
1229 1229 }
1230 1230
1231 1231 /*
1232 1232 * fcoei_handle_sol_frame_done
1233 1233 * solicited frame is just sent out
1234 1234 *
1235 1235 * Input:
1236 1236 * frame = solicited frame that has been sent out
1237 1237 *
1238 1238 * Returns:
1239 1239 * N/A
1240 1240 *
1241 1241 * Comments:
1242 1242 * watchdog will call this to handle solicited frames that FCOEI
1243 1243 * has sent out Non-request frame post handling
1244 1244 */
1245 1245 void
1246 1246 fcoei_handle_sol_frame_done(fcoe_frame_t *frm)
1247 1247 {
1248 1248 /*
1249 1249 * the corresponding xch could be NULL at this time
1250 1250 */
1251 1251 fcoei_exchange_t *xch = FRM2IFM(frm)->ifm_xch;
1252 1252
1253 1253 switch (FRM2IFM(frm)->ifm_rctl) {
1254 1254 case R_CTL_ELS_RSP:
1255 1255 /*
1256 1256 * Complete it with frm as NULL
1257 1257 */
1258 1258 fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
1259 1259 break;
1260 1260
1261 1261 case R_CTL_LS_BA_ACC:
1262 1262 FCOEI_LOG(__FUNCTION__, "BA_ACC out: xch-%p, frm-%p",
1263 1263 xch, frm);
1264 1264 PRT_FRM_HDR("LS_BA_ACC", frm);
1265 1265 break;
1266 1266
1267 1267 case R_CTL_LS_BA_RJT:
1268 1268 FCOEI_LOG(__FUNCTION__, "BA_RJT out: xch-%p, frm-%p",
1269 1269 xch, frm);
1270 1270 PRT_FRM_HDR("LS_BA_RJT", frm);
1271 1271 break;
1272 1272
1273 1273 default:
1274 1274 /*
1275 1275 * Unsupported frame
1276 1276 */
1277 1277 PRT_FRM_HDR("Unsupported sol frame: ", frm);
1278 1278 }
1279 1279
1280 1280 /*
1281 1281 * We should release only the frame, and we don't care its netb
1282 1282 */
1283 1283 FRM2SS(frm)->ss_eport->eport_release_frame(frm);
1284 1284 }
1285 1285
1286 1286 /*
1287 1287 * fcoei_port_event
1288 1288 * link/port state changed
1289 1289 *
1290 1290 * Input:
1291 1291 * eport = to indicate which port has changed
1292 1292 * event = what change
1293 1293 *
1294 1294 * Returns:
1295 1295 * N/A
1296 1296 *
1297 1297 * Comments:
1298 1298 * refer fctl.h for ss_link_state value
1299 1299 */
1300 1300 void
1301 1301 fcoei_port_event(fcoe_port_t *eport, uint32_t event)
1302 1302 {
1303 1303 fcoei_event_t *ae;
1304 1304
1305 1305 if (!(EPORT2SS(eport)->ss_flags & SS_FLAG_LV_BOUND)) {
1306 1306 FCOEI_LOG(__FUNCTION__, "not bound now");
1307 1307 return;
1308 1308 }
1309 1309
1310 1310 mutex_enter(&EPORT2SS(eport)->ss_watchdog_mutex);
1311 1311 switch (event) {
1312 1312 case FCOE_NOTIFY_EPORT_LINK_DOWN:
1313 1313 EPORT2SS(eport)->ss_link_state = FC_STATE_OFFLINE;
1314 1314 cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link down",
1315 1315 eport->eport_portwwn[0], eport->eport_portwwn[1],
1316 1316 eport->eport_portwwn[2], eport->eport_portwwn[3],
1317 1317 eport->eport_portwwn[4], eport->eport_portwwn[5],
1318 1318 eport->eport_portwwn[6], eport->eport_portwwn[7]);
1319 1319 break;
1320 1320
1321 1321 case FCOE_NOTIFY_EPORT_LINK_UP:
1322 1322 if (eport->eport_mtu >= 2200) {
1323 1323 EPORT2SS(eport)->ss_fcp_data_payload_size =
1324 1324 FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE;
1325 1325 } else {
1326 1326 FCOEI_LOG(__FUNCTION__, "fcoei: MTU is not big enough. "
1327 1327 "we will use 1K frames in FCP data phase.");
1328 1328 EPORT2SS(eport)->ss_fcp_data_payload_size =
1329 1329 FCOE_MIN_FCP_DATA_PAYLOAD_SIZE;
1330 1330 }
1331 1331
1332 1332 cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link up",
1333 1333 eport->eport_portwwn[0], eport->eport_portwwn[1],
1334 1334 eport->eport_portwwn[2], eport->eport_portwwn[3],
1335 1335 eport->eport_portwwn[4], eport->eport_portwwn[5],
1336 1336 eport->eport_portwwn[6], eport->eport_portwwn[7]);
1337 1337 EPORT2SS(eport)->ss_link_state = FC_STATE_ONLINE;
1338 1338 break;
1339 1339
1340 1340 default:
1341 1341 FCOEI_LOG(__FUNCTION__, "unsupported event");
1342 1342 mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex);
1343 1343
1344 1344 return;
1345 1345 }
1346 1346
1347 1347 EPORT2SS(eport)->ss_port_event_counter++;
1348 1348 ae = (fcoei_event_t *)kmem_zalloc(sizeof (fcoei_event_t), KM_SLEEP);
1349 1349 ae->ae_type = AE_EVENT_PORT;
1350 1350 ae->ae_obj = EPORT2SS(eport);
1351 1351 ae->ae_specific = EPORT2SS(eport)->ss_link_state;
1352 1352 list_insert_tail(&EPORT2SS(eport)->ss_event_list, ae);
1353 1353 mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex);
1354 1354 }
1355 1355
1356 1356 /*
1357 1357 * fcoei_process_event_port
1358 1358 * link/port state changed
1359 1359 *
1360 1360 * Input:
1361 1361 * ae = link fcoei_event
1362 1362 *
1363 1363 * Returns:
1364 1364 * N/A
1365 1365 *
1366 1366 * Comments:
1367 1367 * asynchronous events from FCOE
1368 1368 */
1369 1369 void
1370 1370 fcoei_process_event_port(fcoei_event_t *ae)
1371 1371 {
1372 1372 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)ae->ae_obj;
1373 1373
1374 1374 if (ss->ss_eport->eport_link_speed == FCOE_PORT_SPEED_1G) {
1375 1375 ae->ae_specific |= FC_STATE_1GBIT_SPEED;
1376 1376 } else if (ss->ss_eport->eport_link_speed ==
1377 1377 FCOE_PORT_SPEED_10G) {
↓ open down ↓ |
1377 lines elided |
↑ open up ↑ |
1378 1378 ae->ae_specific |= FC_STATE_10GBIT_SPEED;
1379 1379 }
1380 1380
1381 1381 if (ss->ss_flags & SS_FLAG_LV_BOUND) {
1382 1382 ss->ss_bind_info.port_statec_cb(ss->ss_port,
1383 1383 (uint32_t)ae->ae_specific);
1384 1384 } else {
1385 1385 FCOEI_LOG(__FUNCTION__, "ss %p not bound now", ss);
1386 1386 }
1387 1387
1388 - atomic_add_32(&ss->ss_port_event_counter, -1);
1388 + atomic_dec_32(&ss->ss_port_event_counter);
1389 1389 kmem_free(ae, sizeof (fcoei_event_t));
1390 1390 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX