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