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