xref: /illumos-gate/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c (revision 5f8171005a0c33f3c67f7da52d41c2362c3fd891)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * This file defines interfaces between fcoe and fct driver.
29  */
30 
31 /*
32  * Driver kernel header files
33  */
34 #include <sys/conf.h>
35 #include <sys/ddi.h>
36 #include <sys/stat.h>
37 #include <sys/pci.h>
38 #include <sys/sunddi.h>
39 #include <sys/modctl.h>
40 #include <sys/file.h>
41 #include <sys/cred.h>
42 #include <sys/byteorder.h>
43 #include <sys/atomic.h>
44 #include <sys/modhash.h>
45 #include <sys/scsi/scsi.h>
46 #include <sys/ethernet.h>
47 
48 /*
49  * COMSTAR header files
50  */
51 #include <sys/stmf_defines.h>
52 #include <sys/fct_defines.h>
53 #include <sys/stmf.h>
54 #include <sys/portif.h>
55 #include <sys/fct.h>
56 
57 /*
58  * FCoE hader files
59  */
60 #include <sys/fcoe/fcoe_common.h>
61 
62 /*
63  * Driver's own header files
64  */
65 #include <fcoet.h>
66 #include <fcoet_fc.h>
67 #include <fcoet_eth.h>
68 
69 /*
70  * function forward declaration
71  */
72 static fct_status_t fcoet_fill_plogi_req(fct_local_port_t *port,
73     fct_remote_port_t *rp, fct_cmd_t *login);
74 static fct_status_t fcoet_fill_plogi_resp(fct_local_port_t *port,
75     fct_remote_port_t *rp, fct_cmd_t *login);
76 static fct_status_t fcoet_send_sol_els(fct_cmd_t *cmd);
77 static fct_status_t fcoet_send_sol_ct(fct_cmd_t *cmd);
78 static fct_status_t fcoet_send_good_status(fct_cmd_t *cmd);
79 static fct_status_t fcoet_send_els_response(fct_cmd_t *cmd);
80 static fct_status_t fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags);
81 static fct_status_t fcoet_logo_fabric(fcoet_soft_state_t *ss);
82 
83 /*
84  * Return the lower link information
85  */
86 fct_status_t
87 fcoet_get_link_info(fct_local_port_t *port, fct_link_info_t *li)
88 {
89 	bcopy(&PORT2SS(port)->ss_link_info, li, sizeof (fct_link_info_t));
90 	return (FCT_SUCCESS);
91 }
92 
93 /*
94  * FCT will call this, when it wants to send PLOGI or has received PLOGI.
95  */
96 fct_status_t
97 fcoet_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp,
98     fct_cmd_t *login)
99 {
100 	uint16_t	handle;
101 	fct_status_t	ret;
102 
103 	switch (rp->rp_id) {
104 	case 0xFFFFFC:
105 		handle = 0x7FC;
106 		break;
107 
108 	case 0xFFFFFD:
109 		handle = 0x7FD;
110 		break;
111 
112 	case 0xFFFFFE:
113 		handle = 0x7FE;
114 		break;
115 
116 	case 0xFFFFFF:
117 		handle = 0x7FF;
118 		break;
119 
120 	default:
121 		/*
122 		 * For not well-known address, we let FCT to select one.
123 		 */
124 		handle = FCT_HANDLE_NONE;
125 		break;
126 	}
127 
128 	rp->rp_handle = handle;
129 	if (login->cmd_type == FCT_CMD_SOL_ELS) {
130 		ret = fcoet_fill_plogi_req(port, rp, login);
131 	} else {
132 		ret = fcoet_fill_plogi_resp(port, rp, login);
133 	}
134 
135 	return (ret);
136 }
137 
138 /*
139  * FCT will call this to say "FCoET can release resources with this RP now."
140  */
141 /* ARGSUSED */
142 fct_status_t
143 fcoet_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp)
144 {
145 	fcoet_soft_state_t	*this_ss = PORT2SS(port);
146 
147 	this_ss->ss_rport_dereg_state = 0;
148 	this_ss->ss_rportid_in_dereg = 0;
149 	return (FCT_SUCCESS);
150 }
151 
152 fct_status_t
153 fcoet_send_cmd(fct_cmd_t *cmd)
154 {
155 	if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
156 		return (fcoet_send_sol_els(cmd));
157 	} else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
158 		return (fcoet_send_sol_ct(cmd));
159 	}
160 
161 	return (FCT_FAILURE);
162 }
163 
164 /*
165  * SCSI response phase
166  * ELS_ACC/ELS_RJT
167  */
168 fct_status_t
169 fcoet_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags)
170 {
171 	char	info[160];
172 
173 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
174 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
175 			goto send_cmd_rsp_error;
176 		} else {
177 			return (fcoet_send_status(cmd));
178 		}
179 	}
180 
181 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
182 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
183 			goto send_cmd_rsp_error;
184 		} else {
185 			return (fcoet_send_els_response(cmd));
186 		}
187 	}
188 
189 	if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
190 		cmd->cmd_handle = 0;
191 	}
192 
193 	if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
194 		return (fcoet_send_abts_response(cmd, 0));
195 	} else {
196 		ASSERT(0);
197 		return (FCT_FAILURE);
198 	}
199 
200 send_cmd_rsp_error:
201 	(void) snprintf(info, 160, "fcoet_send_cmd_response: can not handle "
202 	    "FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", (void *)cmd,
203 	    ioflags);
204 	info[159] = 0;
205 	(void) fct_port_shutdown(CMD2SS(cmd)->ss_port,
206 	    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
207 	return (FCT_FAILURE);
208 }
209 
210 /*
211  * It's for read/write (xfer_rdy)
212  */
213 /* ARGSUSED */
214 fct_status_t
215 fcoet_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
216 {
217 	fcoe_frame_t	*frm;
218 	int		 idx;
219 	int		 frm_num;
220 	int		 data_size;
221 	int		 left_size;
222 	int		 offset;
223 	fcoet_exchange_t *xch = CMD2XCH(cmd);
224 
225 	ASSERT(!xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN]);
226 	xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN] = dbuf;
227 
228 	left_size = (int)dbuf->db_data_size;
229 	if (dbuf->db_relative_offset == 0)
230 		xch->xch_left_data_size =
231 		    XCH2TASK(xch)->task_expected_xfer_length;
232 
233 	if (dbuf->db_flags == DB_DIRECTION_FROM_RPORT) {
234 		/*
235 		 * If it's write type command, we need send xfer_rdy now
236 		 * We may need to consider bidirectional command later
237 		 */
238 		dbuf->db_sglist_length = 0;
239 		frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(
240 		    CMD2SS(cmd)->ss_eport, sizeof (fcoe_fcp_xfer_rdy_t) +
241 		    FCFH_SIZE, NULL);
242 		if (frm == NULL) {
243 			ASSERT(0);
244 			return (FCT_FAILURE);
245 		} else {
246 			fcoet_init_tfm(frm, CMD2XCH(cmd));
247 			bzero(frm->frm_payload, frm->frm_payload_size);
248 		}
249 
250 		FFM_R_CTL(0x05, frm);
251 		FRM2TFM(frm)->tfm_rctl = 0x05;
252 		FFM_TYPE(0x08, frm);
253 		FFM_F_CTL(0x890000, frm);
254 		FFM_OXID(cmd->cmd_oxid, frm);
255 		FFM_RXID(cmd->cmd_rxid, frm);
256 		FFM_S_ID(cmd->cmd_lportid, frm);
257 		FFM_D_ID(cmd->cmd_rportid, frm);
258 		FCOE_V2B_4(dbuf->db_relative_offset, frm->frm_payload);
259 		FCOE_V2B_4(dbuf->db_data_size, frm->frm_payload + 4);
260 		CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
261 
262 		return (FCT_SUCCESS);
263 	}
264 
265 	/*
266 	 * It's time to transfer READ data to remote side
267 	 */
268 	frm_num = (dbuf->db_data_size + CMD2SS(cmd)->ss_fcp_data_payload_size -
269 	    1) / CMD2SS(cmd)->ss_fcp_data_payload_size;
270 	offset = dbuf->db_relative_offset;
271 	for (idx = 0; idx < frm_num; idx++) {
272 		if (idx == (frm_num -1)) {
273 			data_size = P2ROUNDUP(left_size, 4);
274 		} else {
275 			data_size = CMD2SS(cmd)->ss_fcp_data_payload_size;
276 		}
277 
278 		frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(
279 		    CMD2SS(cmd)->ss_eport, data_size + FCFH_SIZE,
280 		    FCOET_GET_NETB(dbuf, idx));
281 		if (frm == NULL) {
282 			ASSERT(0);
283 			return (FCT_FAILURE);
284 		} else {
285 			fcoet_init_tfm(frm, CMD2XCH(cmd));
286 			/*
287 			 * lock the xchg to avoid being released (by abort)
288 			 * after sent out and before release
289 			 */
290 			FCOET_BUSY_XCHG(CMD2XCH(cmd));
291 		}
292 
293 		FFM_R_CTL(0x01, frm);
294 		FRM2TFM(frm)->tfm_rctl = 0x01;
295 		FRM2TFM(frm)->tfm_buf_idx =
296 		    dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN;
297 		FFM_TYPE(0x08, frm);
298 		if (idx != frm_num - 1) {
299 			FFM_F_CTL(0x800008, frm);
300 		} else {
301 			FFM_F_CTL(0x880008 | (data_size - left_size), frm);
302 		}
303 
304 		FFM_OXID(cmd->cmd_oxid, frm);
305 		FFM_RXID(cmd->cmd_rxid, frm);
306 		FFM_S_ID(cmd->cmd_lportid, frm);
307 		FFM_D_ID(cmd->cmd_rportid, frm);
308 		FFM_SEQ_CNT(xch->xch_sequence_no, frm);
309 		atomic_add_8(&xch->xch_sequence_no, 1);
310 		FFM_PARAM(offset, frm);
311 		offset += data_size;
312 		left_size -= data_size;
313 
314 		/*
315 		 * Disassociate netbs which will be freed by NIC driver
316 		 */
317 		FCOET_SET_NETB(dbuf, idx, NULL);
318 
319 		CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
320 	}
321 
322 	return (FCT_SUCCESS);
323 }
324 
325 fct_status_t
326 fcoet_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags)
327 {
328 	fcoet_soft_state_t	*this_ss = PORT2SS(port);
329 	fct_status_t		 fct_ret = FCT_SUCCESS;
330 
331 	FCOET_LOG("fcoet_abort_cmd", "cmd=%p, xch=%p, cmd_specific=%p",
332 	    cmd, cmd->cmd_fca_private, cmd->cmd_specific);
333 	switch (cmd->cmd_type) {
334 	case FCT_CMD_RCVD_ABTS:
335 		/*
336 		 * Sometimes unsolicited ABTS request will be received twice
337 		 * and the first ABTS is not done yet, so the second ABTS
338 		 * will be passed down here, in this case we will do
339 		 * nothing and abts response is not needed to be sent
340 		 * fct_ret = fcoet_send_abts_response(cmd, 1);
341 		 */
342 		break;
343 	case FCT_CMD_FCP_XCHG:
344 	case FCT_CMD_RCVD_ELS:
345 		if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
346 			break;
347 		}
348 
349 		CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT;
350 		(void) fcoet_clear_unsol_exchange(CMD2XCH(cmd));
351 		if (!(flags & FCT_IOF_FORCE_FCA_DONE)) {
352 			mutex_enter(&this_ss->ss_watch_mutex);
353 			CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt();
354 			list_insert_tail(&this_ss->ss_abort_xchg_list,
355 			    CMD2XCH(cmd));
356 			cv_signal(&this_ss->ss_watch_cv);
357 			mutex_exit(&this_ss->ss_watch_mutex);
358 		}
359 		break;
360 
361 	case FCT_CMD_SOL_ELS:
362 	case FCT_CMD_SOL_CT:
363 		if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
364 			break;
365 		}
366 
367 		CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT;
368 		fcoet_clear_sol_exchange(CMD2XCH(cmd));
369 
370 		if (!(flags & FCT_IOF_FORCE_FCA_DONE)) {
371 			mutex_enter(&this_ss->ss_watch_mutex);
372 			CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt();
373 			cv_signal(&this_ss->ss_watch_cv);
374 			list_insert_tail(&this_ss->ss_abort_xchg_list,
375 			    CMD2XCH(cmd));
376 			mutex_exit(&this_ss->ss_watch_mutex);
377 		}
378 
379 		break;
380 
381 	default:
382 		ASSERT(0);
383 		break;
384 	}
385 
386 	if ((flags & FCT_IOF_FORCE_FCA_DONE) &&
387 	    (cmd->cmd_type != FCT_CMD_FCP_XCHG)) {
388 		cmd->cmd_handle = 0;
389 	}
390 
391 	return (fct_ret);
392 }
393 
394 /* ARGSUSED */
395 fct_status_t
396 fcoet_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx)
397 {
398 	cmn_err(CE_WARN, "FLOGI requested (not supported)");
399 	return (FCT_FAILURE);
400 }
401 
402 void
403 fcoet_send_sol_flogi(fcoet_soft_state_t *ss)
404 {
405 	fcoet_exchange_t	*xch;
406 	fct_cmd_t		*cmd;
407 	fct_els_t		*els;
408 	fcoe_frame_t		*frm;
409 
410 	/*
411 	 * FCT will initialize fct_cmd_t
412 	 * Initialize fcoet_exchange
413 	 */
414 	cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS,
415 	    sizeof (fcoet_exchange_t), 0);
416 	xch = CMD2XCH(cmd);
417 	els = CMD2ELS(cmd);
418 
419 	xch->xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
420 	if (xch->xch_oxid == 0xFFFF) {
421 		xch->xch_oxid =
422 		    atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
423 	}
424 	xch->xch_rxid = 0xFFFF;
425 	xch->xch_flags = 0;
426 	xch->xch_ss = ss;
427 	xch->xch_cmd = cmd;
428 	xch->xch_current_seq = NULL;
429 	xch->xch_start_time = ddi_get_lbolt();
430 
431 	/*
432 	 * Keep it to compare with response
433 	 */
434 	ss->ss_sol_flogi = xch;
435 	els->els_resp_alloc_size = 116;
436 	els->els_resp_size = 116;
437 	els->els_resp_payload = (uint8_t *)
438 	    kmem_zalloc(els->els_resp_size, KM_SLEEP);
439 	(void) mod_hash_insert(xch->xch_ss->ss_sol_oxid_hash,
440 	    (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
441 	xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
442 	atomic_or_32(&ss->ss_flags, SS_FLAG_DELAY_PLOGI);
443 
444 	/*
445 	 * FCoE will initialize fcoe_frame_t
446 	 */
447 	frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
448 	    FLOGI_REQ_PAYLOAD_SIZE + FCFH_SIZE, NULL);
449 	if (frm == NULL) {
450 		ASSERT(0);
451 		return;
452 	} else {
453 		fcoet_init_tfm(frm, xch);
454 		bzero(frm->frm_payload, frm->frm_payload_size);
455 	}
456 
457 	FFM_R_CTL(0x22, frm);
458 	FRM2TFM(frm)->tfm_rctl = 0x22;
459 	FFM_TYPE(0x01, frm);
460 	FFM_F_CTL(0x290000, frm);
461 	FFM_OXID(xch->xch_oxid, frm);
462 	FFM_RXID(xch->xch_rxid, frm);
463 	FFM_D_ID(0xfffffe, frm);
464 	frm->frm_payload[0] = ELS_OP_FLOGI;
465 	/* Common Service Parameters */
466 	frm->frm_payload[4] = 0x20;
467 	frm->frm_payload[5] = 0x08;
468 	frm->frm_payload[6] = 0x0;
469 	frm->frm_payload[7] = 0x03;
470 	/* N_PORT */
471 	frm->frm_payload[8] = 0x88;
472 	frm->frm_payload[9] = 0x00;
473 	frm->frm_payload[10] = 0x08;
474 	frm->frm_payload[11] = 0x0;
475 	frm->frm_payload[12] = 0x0;
476 	frm->frm_payload[13] = 0xff;
477 	frm->frm_payload[14] = 0x0;
478 	frm->frm_payload[15] = 0x03;
479 	frm->frm_payload[16] = 0x0;
480 	frm->frm_payload[17] = 0x0;
481 	frm->frm_payload[18] = 0x07;
482 	frm->frm_payload[19] = 0xd0;
483 	/* PWWN and NWWN */
484 	frm->frm_payload[20] = 0x0;
485 	bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload+20, 8);
486 	bcopy(ss->ss_eport->eport_nodewwn, frm->frm_payload+28, 8);
487 	/* Class 3 Service Parameters */
488 	frm->frm_payload[68] = 0x88;
489 	frm->frm_payload[74] = 0x08;
490 	frm->frm_payload[77] = 0xff;
491 
492 	ss->ss_eport->eport_tx_frame(frm);
493 	xch->xch_flags |= XCH_FLAG_NONFCP_REQ_SENT;
494 }
495 
496 /*
497  * This is for solicited FLOGI only
498  */
499 void
500 fcoet_send_sol_abts(fcoet_exchange_t *xch)
501 {
502 	fcoe_frame_t		*frm;
503 	fcoet_soft_state_t	*ss = xch->xch_ss;
504 
505 	/*
506 	 * FCoE will initialize fcoe_frame_t
507 	 * ABTS has no payload
508 	 */
509 	frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
510 	    FCFH_SIZE, NULL);
511 	if (frm == NULL) {
512 		ASSERT(0);
513 		return;
514 	} else {
515 		fcoet_init_tfm(frm, xch);
516 		frm->frm_payload = NULL;
517 	}
518 
519 	FFM_R_CTL(0x81, frm);
520 	FRM2TFM(frm)->tfm_rctl = 0x81;
521 	FFM_F_CTL(0x090000, frm);
522 	FFM_OXID(xch->xch_oxid, frm);
523 	FFM_RXID(xch->xch_rxid, frm);
524 	FFM_D_ID(0xfffffe, frm);
525 	FFM_SEQ_CNT(xch->xch_sequence_no, frm);
526 	xch->xch_start_time = ddi_get_lbolt();
527 
528 	ss->ss_eport->eport_tx_frame(frm);
529 }
530 
531 void
532 fcoet_ctl(struct fct_local_port *port, int cmd, void *arg)
533 {
534 	stmf_change_status_t		 st;
535 	stmf_state_change_info_t	*ssci = (stmf_state_change_info_t *)arg;
536 	fcoet_soft_state_t		*this_ss = PORT2SS(port);
537 
538 	st.st_completion_status = FCT_SUCCESS;
539 	st.st_additional_info = NULL;
540 
541 	switch (cmd) {
542 	case FCT_CMD_PORT_ONLINE:
543 		if (this_ss->ss_state == FCT_STATE_ONLINE)
544 			st.st_completion_status = STMF_ALREADY;
545 		else if (this_ss->ss_state != FCT_STATE_OFFLINE)
546 			st.st_completion_status = FCT_FAILURE;
547 		if (st.st_completion_status == FCT_SUCCESS) {
548 			this_ss->ss_state = FCT_STATE_ONLINING;
549 			this_ss->ss_state_not_acked = 1;
550 			st.st_completion_status = fcoet_enable_port(this_ss);
551 			if (st.st_completion_status != STMF_SUCCESS) {
552 				this_ss->ss_state = FCT_STATE_OFFLINE;
553 				this_ss->ss_state_not_acked = 0;
554 			} else {
555 				this_ss->ss_state = FCT_STATE_ONLINE;
556 			}
557 		}
558 		fct_ctl(port->port_lport, FCT_CMD_PORT_ONLINE_COMPLETE, &st);
559 		this_ss->ss_change_state_flags = 0;
560 		break;
561 
562 	case FCT_CMD_PORT_OFFLINE:
563 		if (this_ss->ss_state == FCT_STATE_OFFLINE) {
564 			st.st_completion_status = STMF_ALREADY;
565 		} else if (this_ss->ss_state != FCT_STATE_ONLINE) {
566 			st.st_completion_status = FCT_FAILURE;
567 		}
568 		if (st.st_completion_status == FCT_SUCCESS) {
569 			this_ss->ss_state = FCT_STATE_OFFLINING;
570 			this_ss->ss_state_not_acked = 1;
571 			this_ss->ss_change_state_flags = ssci->st_rflags;
572 			st.st_completion_status = fcoet_disable_port(this_ss);
573 			if (st.st_completion_status != STMF_SUCCESS) {
574 				this_ss->ss_state = FCT_STATE_ONLINE;
575 				this_ss->ss_state_not_acked = 0;
576 			} else {
577 				this_ss->ss_state = FCT_STATE_OFFLINE;
578 			}
579 		}
580 		/*
581 		 * Notify the watchdog to do clear work
582 		 */
583 		mutex_enter(&this_ss->ss_watch_mutex);
584 		cv_signal(&this_ss->ss_watch_cv);
585 		mutex_exit(&this_ss->ss_watch_mutex);
586 		fct_ctl(port->port_lport, FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
587 		break;
588 
589 	case FCT_ACK_PORT_ONLINE_COMPLETE:
590 		this_ss->ss_state_not_acked = 0;
591 		break;
592 
593 	case FCT_ACK_PORT_OFFLINE_COMPLETE:
594 		this_ss->ss_state_not_acked = 0;
595 		if (this_ss->ss_change_state_flags & STMF_RFLAG_RESET) {
596 			if (fct_port_initialize(port,
597 			    this_ss->ss_change_state_flags,
598 			    "fcoet_ctl FCT_ACK_PORT_OFFLINE_COMPLETE "
599 			    "with RLFLAG_RESET") != FCT_SUCCESS) {
600 				cmn_err(CE_WARN, "fcoet_ctl: "
601 				    "fct_port_initialize %s failed",
602 				    this_ss->ss_alias);
603 				FCOET_LOG("fcoet_ctl: fct_port_initialize "
604 				    "%s failed", this_ss->ss_alias);
605 			}
606 		}
607 		break;
608 	default:
609 		FCOET_LOG("fcoet_ctl", "Unsupported cmd %x", cmd);
610 		break;
611 	}
612 }
613 
614 /*
615  * Filling the hba attributes
616  */
617 /* ARGSUSED */
618 void
619 fcoet_populate_hba_fru_details(struct fct_local_port *port,
620     struct fct_port_attrs *port_attrs)
621 {
622 	(void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
623 	    "Sun Microsystems, Inc.");
624 	(void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
625 	    "%s", FCOET_NAME);
626 	(void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
627 	    "%s", FCOET_VERSION);
628 	(void) strcpy(port_attrs->serial_number, "N/A");
629 	(void) strcpy(port_attrs->hardware_version, "N/A");
630 	(void) strcpy(port_attrs->model, "FCoE Virtual FC HBA");
631 	(void) strcpy(port_attrs->model_description, "N/A");
632 	(void) strcpy(port_attrs->firmware_version, "N/A");
633 	(void) strcpy(port_attrs->option_rom_version, "N/A");
634 
635 	port_attrs->vendor_specific_id = 0xFC0E;
636 	port_attrs->max_frame_size = 2136;
637 	port_attrs->supported_cos = 0x10000000;
638 	/* Specified a fix speed here, need to change it in the future */
639 	port_attrs->supported_speed = PORT_SPEED_1G | PORT_SPEED_10G;
640 }
641 
642 
643 static fct_status_t
644 fcoet_send_sol_els(fct_cmd_t *cmd)
645 {
646 	fcoe_frame_t	 *frm;
647 	fcoet_exchange_t *xch = NULL;
648 
649 	xch = CMD2XCH(cmd);
650 	xch->xch_flags = 0;
651 	xch->xch_ss = CMD2SS(cmd);
652 	xch->xch_cmd = cmd;
653 	xch->xch_current_seq = NULL;
654 	xch->xch_left_data_size = 0;
655 	xch->xch_sequence_no = 0;
656 	xch->xch_start_time = ddi_get_lbolt();
657 	xch->xch_rxid = 0xFFFF;
658 	xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
659 	if (xch->xch_oxid == 0xFFFF) {
660 		xch->xch_oxid =
661 		    atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
662 	}
663 
664 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
665 	    CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL);
666 	if (frm == NULL) {
667 		ASSERT(0);
668 		return (FCT_FAILURE);
669 	} else {
670 		fcoet_init_tfm(frm, CMD2XCH(cmd));
671 		bzero(frm->frm_payload, frm->frm_payload_size);
672 	}
673 
674 	(void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash,
675 	    (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
676 	xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
677 	bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload,
678 	    frm->frm_payload_size);
679 	FFM_R_CTL(0x22, frm);
680 	FRM2TFM(frm)->tfm_rctl = 0x22;
681 	FFM_TYPE(0x01, frm);
682 	FFM_F_CTL(0x290000, frm);
683 	FFM_OXID(xch->xch_oxid, frm);
684 	FFM_RXID(xch->xch_rxid, frm);
685 	FFM_S_ID(cmd->cmd_lportid, frm);
686 	FFM_D_ID(cmd->cmd_rportid, frm);
687 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
688 
689 	return (FCT_SUCCESS);
690 }
691 
692 static fct_status_t
693 fcoet_send_sol_ct(fct_cmd_t *cmd)
694 {
695 	fcoe_frame_t	 *frm;
696 	fcoet_exchange_t *xch;
697 
698 	xch = CMD2XCH(cmd);
699 	xch->xch_flags = 0;
700 	xch->xch_ss = CMD2SS(cmd);
701 	xch->xch_cmd = cmd;
702 	xch->xch_current_seq = NULL;
703 	xch->xch_left_data_size = 0;
704 	xch->xch_sequence_no = 0;
705 	xch->xch_start_time = ddi_get_lbolt();
706 	xch->xch_rxid = 0xFFFF;
707 	xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
708 	if (xch->xch_oxid == 0xFFFF) {
709 		xch->xch_oxid =
710 		    atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
711 	}
712 
713 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
714 	    CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL);
715 	if (frm == NULL) {
716 		ASSERT(0);
717 		return (FCT_FAILURE);
718 	} else {
719 		fcoet_init_tfm(frm, CMD2XCH(cmd));
720 		bzero(frm->frm_payload, frm->frm_payload_size);
721 	}
722 
723 	(void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash,
724 	    (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
725 	xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
726 	bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload,
727 	    frm->frm_payload_size);
728 	FFM_R_CTL(0x2, frm);
729 	FRM2TFM(frm)->tfm_rctl = 0x2;
730 	FFM_TYPE(0x20, frm);
731 	FFM_F_CTL(0x290000, frm);
732 	FFM_OXID(xch->xch_oxid, frm);
733 	FFM_RXID(xch->xch_rxid, frm);
734 	FFM_S_ID(cmd->cmd_lportid, frm);
735 	FFM_D_ID(cmd->cmd_rportid, frm);
736 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
737 
738 	return (FCT_SUCCESS);
739 }
740 
741 fct_status_t
742 fcoet_send_status(fct_cmd_t *cmd)
743 {
744 	fcoe_frame_t	*frm;
745 	scsi_task_t	*task = CMD2TASK(cmd);
746 	fcoe_fcp_rsp_t	*ffr;
747 	int		 raw_frame_size;
748 
749 	/*
750 	 * Fast channel for good status phase
751 	 */
752 	if (task->task_scsi_status == STATUS_GOOD && !task->task_resid) {
753 		return (fcoet_send_good_status(cmd));
754 	}
755 
756 	raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t);
757 	if (task->task_scsi_status == STATUS_CHECK) {
758 		raw_frame_size += task->task_sense_length;
759 	}
760 	raw_frame_size = P2ROUNDUP(raw_frame_size, 4);
761 
762 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
763 	    raw_frame_size, NULL);
764 	if (frm == NULL) {
765 		ASSERT(0);
766 		return (FCT_FAILURE);
767 	} else {
768 		fcoet_init_tfm(frm, CMD2XCH(cmd));
769 		bzero(frm->frm_payload, frm->frm_payload_size);
770 		/*
771 		 * lock the xchg to avoid being released (by abort)
772 		 * after sent out and before release
773 		 */
774 		FCOET_BUSY_XCHG(CMD2XCH(cmd));
775 	}
776 
777 	/*
778 	 * If there's sense data, copy it first
779 	 */
780 	if ((task->task_scsi_status == STATUS_CHECK) &&
781 	    task->task_sense_length) {
782 		bcopy(task->task_sense_data, frm->frm_payload +
783 		    sizeof (fcoe_fcp_rsp_t), task->task_sense_length);
784 	}
785 
786 	/*
787 	 * Fill fcp_rsp
788 	 */
789 	ffr = (fcoe_fcp_rsp_t *)frm->frm_payload;
790 	FCOE_V2B_4(0, ffr->ffr_retry_delay_timer);
791 	FCOE_V2B_1(0, ffr->ffr_flags);
792 	if (task->task_scsi_status == STATUS_CHECK || task->task_resid) {
793 		if (task->task_scsi_status == STATUS_CHECK) {
794 			ffr->ffr_flags[0] |= BIT_1;
795 		}
796 		if (task->task_status_ctrl == TASK_SCTRL_OVER) {
797 			ffr->ffr_flags[0] |= BIT_2;
798 		} else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
799 			ffr->ffr_flags[0] |= BIT_3;
800 		}
801 	}
802 	FCOE_V2B_1(task->task_scsi_status, ffr->ffr_scsi_status);
803 	FCOE_V2B_4(task->task_resid, ffr->ffr_resid);
804 	FCOE_V2B_4(task->task_sense_length, ffr->ffr_sns_len);
805 	FCOE_V2B_4(0, ffr->ffr_rsp_len);
806 
807 	/*
808 	 * Fill fc frame header
809 	 */
810 	FFM_R_CTL(0x07, frm);
811 	FRM2TFM(frm)->tfm_rctl = 0x07;
812 	FFM_TYPE(0x08, frm);
813 	FFM_F_CTL(0x990000, frm);
814 	FFM_OXID(cmd->cmd_oxid, frm);
815 	FFM_RXID(cmd->cmd_rxid, frm);
816 	FFM_S_ID(cmd->cmd_lportid, frm);
817 	FFM_D_ID(cmd->cmd_rportid, frm);
818 	FFM_SEQ_ID(0x01, frm);
819 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
820 
821 	return (FCT_SUCCESS);
822 }
823 
824 static fct_status_t
825 fcoet_send_els_response(fct_cmd_t *cmd)
826 {
827 	fcoe_frame_t *frm;
828 
829 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
830 	    CMD2ELS(cmd)->els_resp_size + FCFH_SIZE, NULL);
831 	if (frm == NULL) {
832 		ASSERT(0);
833 		return (FCT_FAILURE);
834 	} else {
835 		fcoet_init_tfm(frm, CMD2XCH(cmd));
836 		bzero(frm->frm_payload, frm->frm_payload_size);
837 		/*
838 		 * lock the xchg to avoid being released (by abort)
839 		 * after sent out and before release
840 		 */
841 		FCOET_BUSY_XCHG(CMD2XCH(cmd));
842 	}
843 
844 	bcopy(CMD2ELS(cmd)->els_resp_payload, frm->frm_payload,
845 	    frm->frm_payload_size);
846 	FFM_R_CTL(0x23, frm);
847 	FRM2TFM(frm)->tfm_rctl = 0x23;
848 	FFM_TYPE(0x01, frm);
849 	FFM_F_CTL(0x980000, frm);
850 	FFM_OXID(cmd->cmd_oxid, frm);
851 	FFM_RXID(cmd->cmd_rxid, frm);
852 	FFM_S_ID(cmd->cmd_lportid, frm);
853 	FFM_D_ID(cmd->cmd_rportid, frm);
854 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
855 
856 	return (FCT_SUCCESS);
857 }
858 
859 /* ARGSUSED */
860 static fct_status_t
861 fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags)
862 {
863 	fcoe_frame_t	*frm;
864 	fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
865 
866 	/*
867 	 * The relevant fcoet_exchange has been released
868 	 */
869 	cmd->cmd_fca_private = NULL;
870 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
871 	    12 + FCFH_SIZE, NULL);
872 	if (frm == NULL) {
873 		ASSERT(0);
874 		return (FCT_FAILURE);
875 	} else {
876 		fcoet_init_tfm(frm, NULL);
877 	}
878 
879 	bcopy(abts->abts_resp_payload, frm->frm_payload,
880 	    frm->frm_payload_size);
881 	FFM_R_CTL(abts->abts_resp_rctl, frm);
882 	FRM2TFM(frm)->tfm_rctl = abts->abts_resp_rctl;
883 	FFM_TYPE(0x00, frm);
884 	FFM_F_CTL(0x980000, frm);
885 	FFM_OXID(cmd->cmd_oxid, frm);
886 	FFM_RXID(cmd->cmd_rxid, frm);
887 	FFM_S_ID(cmd->cmd_lportid, frm);
888 	FFM_D_ID(cmd->cmd_rportid, frm);
889 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
890 
891 	return (FCT_SUCCESS);
892 }
893 
894 /*
895  * enable/disable port is simple compared to physical FC HBAs
896  */
897 fct_status_t
898 fcoet_enable_port(fcoet_soft_state_t *ss)
899 {
900 	FCOET_EXT_LOG(ss->ss_alias, "port is being enabled-%p", ss);
901 	/* Call fcoe function to online the port */
902 	if (ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0) ==
903 	    FCOE_FAILURE) {
904 		return (FCT_FAILURE);
905 	}
906 
907 	if ((ss->ss_flags & SS_FLAG_PORT_DISABLED) == SS_FLAG_PORT_DISABLED) {
908 		atomic_and_32(&ss->ss_flags, ~SS_FLAG_PORT_DISABLED);
909 	}
910 
911 	return (FCT_SUCCESS);
912 }
913 
914 fct_status_t
915 fcoet_disable_port(fcoet_soft_state_t *ss)
916 {
917 	fct_status_t	status;
918 
919 	FCOET_EXT_LOG(ss->ss_alias, "port is being disabled-%p", ss);
920 	/* Call fcoe function to offline the port */
921 	status = fcoet_logo_fabric(ss);
922 	ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0);
923 	atomic_or_32(&ss->ss_flags, SS_FLAG_PORT_DISABLED);
924 	return (status);
925 }
926 
927 static fct_status_t
928 fcoet_logo_fabric(fcoet_soft_state_t *ss)
929 {
930 	fcoe_frame_t	*frm;
931 	uint32_t	req_payload_size = 16;
932 	uint16_t	xch_oxid, xch_rxid = 0xFFFF;
933 
934 	frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
935 	    req_payload_size + FCFH_SIZE, NULL);
936 	if (frm == NULL) {
937 		ASSERT(0);
938 		return (FCT_FAILURE);
939 	} else {
940 		fcoet_init_tfm(frm, NULL);
941 		bzero(frm->frm_payload, frm->frm_payload_size);
942 	}
943 	xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
944 	if (xch_oxid == 0xFFFF) {
945 		xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
946 	}
947 	FFM_R_CTL(0x22, frm);
948 	FRM2TFM(frm)->tfm_rctl = 0x22;
949 	FFM_TYPE(0x01, frm);
950 	FFM_F_CTL(0x290000, frm);
951 	FFM_OXID(xch_oxid, frm);
952 	FFM_RXID(xch_rxid, frm);
953 	FFM_S_ID(ss->ss_link_info.portid, frm);
954 	FFM_D_ID(0xfffffe, frm);
955 
956 	FCOE_V2B_1(0x5, frm->frm_payload);
957 	FCOE_V2B_3(ss->ss_link_info.portid, frm->frm_payload + 5);
958 	bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload + 8, 8);
959 	ss->ss_eport->eport_tx_frame(frm);
960 
961 	return (FCT_SUCCESS);
962 
963 }
964 
965 /*
966  * Called by: fcoet_register_remote_port
967  */
968 /* ARGSUSED */
969 static fct_status_t
970 fcoet_fill_plogi_req(fct_local_port_t *port, fct_remote_port_t *rp,
971     fct_cmd_t *login)
972 {
973 	uint8_t *p;
974 
975 	p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
976 	p[0] = ELS_OP_PLOGI;
977 	p[4] = 0x20;
978 	p[5] = 0x20;
979 	p[7] = 3;
980 	p[8] = 0x88;
981 	p[10] = 8;
982 	p[13] = 0xff; p[15] = 0x1f;
983 	p[18] = 7; p[19] = 0xd0;
984 
985 	bcopy(port->port_pwwn, p + 20, 8);
986 	bcopy(port->port_nwwn, p + 28, 8);
987 
988 	p[68] = 0x80;
989 	p[74] = 8;
990 	p[77] = 0xff;
991 	p[81] = 1;
992 
993 	return (FCT_SUCCESS);
994 }
995 
996 /*
997  * Called by: fcoet_register_remote_port
998  */
999 /* ARGSUSED */
1000 static fct_status_t
1001 fcoet_fill_plogi_resp(fct_local_port_t *port, fct_remote_port_t *rp,
1002     fct_cmd_t *login)
1003 {
1004 	uint8_t *p;
1005 	/*
1006 	 * ACC
1007 	 */
1008 	p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
1009 	p[0] = ELS_OP_ACC;
1010 	p[4] = 0x20;
1011 	p[5] = 0x20;
1012 	p[7] = 0x0A;
1013 	p[10] = 0x05;
1014 	p[11] = 0xAC;
1015 
1016 	bcopy(port->port_pwwn, p + 20, 8);
1017 	bcopy(port->port_nwwn, p + 28, 8);
1018 
1019 	p[68] = 0x88;
1020 	return (FCT_SUCCESS);
1021 }
1022 
1023 static fct_status_t
1024 fcoet_send_good_status(fct_cmd_t *cmd)
1025 {
1026 	fcoe_frame_t	*frm;
1027 	int		 raw_frame_size;
1028 
1029 	raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t);
1030 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
1031 	    raw_frame_size, NULL);
1032 	if (frm == NULL) {
1033 		ASSERT(0);
1034 		return (FCT_FAILURE);
1035 	} else {
1036 		fcoet_init_tfm(frm, CMD2XCH(cmd));
1037 		bzero(frm->frm_payload, frm->frm_payload_size);
1038 		/*
1039 		 * lock the xchg to avoid being released (by abort)
1040 		 * after sent out and before release
1041 		 */
1042 		FCOET_BUSY_XCHG(CMD2XCH(cmd));
1043 	}
1044 
1045 	/*
1046 	 * Fill fc frame header
1047 	 */
1048 	FFM_R_CTL(0x07, frm);
1049 	FRM2TFM(frm)->tfm_rctl = 0x07;
1050 	FFM_TYPE(0x08, frm);
1051 	FFM_F_CTL(0x990000, frm);
1052 	FFM_OXID(cmd->cmd_oxid, frm);
1053 	FFM_RXID(cmd->cmd_rxid, frm);
1054 	FFM_S_ID(cmd->cmd_lportid, frm);
1055 	FFM_D_ID(cmd->cmd_rportid, frm);
1056 	FFM_SEQ_ID(0x01, frm);
1057 
1058 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
1059 
1060 	return (FCT_SUCCESS);
1061 }
1062