Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / fibre-channel / fca / fcoei / fcoei_lv.c
blob7d0031e509dfa5cb03bf9b4adbb1907e6c8d636f
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * This file defines interfaces between FCOE and LEADVILLE
31 * Driver kernel header files
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/scsi/scsi.h>
44 #include <sys/mac_client.h>
45 #include <sys/modhash.h>
48 * LEADVILLE header files
50 #include <sys/fibre-channel/fc.h>
51 #include <sys/fibre-channel/impl/fc_fcaif.h>
54 * COMSTAR head files (BIT_* macro)
56 #include <sys/stmf_defines.h>
59 * FCOE header files
61 #include <sys/fcoe/fcoe_common.h>
64 * Driver's own header files
66 #include <fcoei.h>
69 * forward declaration of static functions
71 static void fcoei_port_enabled(void *arg);
73 static void fcoei_populate_hba_fru_details(fcoei_soft_state_t *ss,
74 fc_fca_port_info_t *port_info);
76 static void fcoei_initiate_ct_req(fcoei_exchange_t *xch);
77 static void fcoei_initiate_fcp_cmd(fcoei_exchange_t *xch);
78 static void fcoei_initiate_els_req(fcoei_exchange_t *xch);
79 static void fcoei_initiate_els_resp(fcoei_exchange_t *xch);
81 static void fcoei_fill_els_logi_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
82 static void fcoei_fill_els_prli_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
83 static void fcoei_fill_els_logo_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
84 static void fcoei_fill_els_scr_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
85 static void fcoei_fill_els_adisc_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
86 static void fcoei_fill_els_linit_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
87 static void fcoei_fill_els_rls_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
88 static void fcoei_fill_els_rnid_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
90 static void fcoei_fill_els_acc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
91 static void fcoei_fill_els_rjt_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
92 static void fcoei_fill_els_logi_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
93 static void fcoei_fill_els_prli_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
94 static void fcoei_fill_els_logo_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
95 static void fcoei_fill_els_adisc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
97 static void fcoei_logo_peer(void *arg);
98 static void fcoei_fpkt_comp(fc_packet_t *fpkt);
100 static uint32_t
101 fcoei_xch_abort(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
105 * fcoei_bind_port
106 * Bind LV port instance with fcoei soft state
108 * Input:
109 * dip = dev info of fcoei soft state
110 * port_info = fcoei specific parameters about LV port
111 * bind_info = LV specific parameters about fcoei soft state
113 * Returns:
114 * The pointer to fcoei soft state
116 * Comments:
117 * Unpon the completion of this call, the port must be offline.
118 * fcoei_port_enabled could trigger it to online
120 static void *
121 fcoei_bind_port(dev_info_t *dip, fc_fca_port_info_t *port_info,
122 fc_fca_bind_info_t *bind_info)
124 fcoei_soft_state_t *ss;
127 * get state info based on the dip
129 ss = (fcoei_soft_state_t *)
130 ddi_get_soft_state(fcoei_state, ddi_get_instance(dip));
131 if (!ss) {
132 FCOEI_LOG(__FUNCTION__, "ss is NULL");
133 return (NULL);
137 * make sure this port isn't bound
139 if (ss->ss_flags & SS_FLAG_LV_BOUND) {
140 port_info->pi_error = FC_ALREADY;
141 FCOEI_LOG(__FUNCTION__, "ss has been bound");
142 return (NULL);
145 if (bind_info->port_num) {
147 * make sure request is in bounds
149 port_info->pi_error = FC_OUTOFBOUNDS;
150 FCOEI_LOG(__FUNCTION__, "port_num is not 0");
151 return (NULL);
155 * stash the ss_bind_info supplied by the FC Transport
157 bcopy(bind_info, &ss->ss_bind_info, sizeof (fc_fca_bind_info_t));
158 ss->ss_port = bind_info->port_handle;
161 * RNID parameter
163 port_info->pi_rnid_params.status = FC_FAILURE;
166 * populate T11 FC-HBA details
168 fcoei_populate_hba_fru_details(ss, port_info);
171 * set port's current state, and it is always offline before binding
173 * We hack pi_port_state to tell LV if it's NODMA_FCA
175 port_info->pi_port_state = FC_STATE_FCA_IS_NODMA;
178 * copy login param
180 bcopy(&ss->ss_els_logi, &port_info->pi_login_params,
181 sizeof (la_els_logi_t));
184 * Mark it as bound
186 atomic_or_32(&ss->ss_flags, SS_FLAG_LV_BOUND);
189 * Let fcoe to report the link status
191 fcoei_port_enabled((void *)ss);
193 FCOEI_LOG(__FUNCTION__, "Exit fcoei_bind_port: %p", ss);
194 return (ss);
198 * fcoei_unbind_port
199 * Un-bind the fcoei port
201 * Input:
202 * fca_handle = fcoei soft state set in fcoei_bind_port
204 * Returns:
205 * N/A
207 * Comments:
208 * Clear binding flag
210 static void
211 fcoei_unbind_port(void *fca_handle)
213 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
215 atomic_and_32(&ss->ss_flags, ~SS_FLAG_LV_BOUND);
216 ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, NULL);
217 FCOEI_LOG(__FUNCTION__, "Exit fcoei_unbind_port: %p", ss);
221 * fcoei_init_pkt
222 * Initialize fcoei related part of fc_packet
224 * Input:
225 * fca_handle = fcoei soft state set in fcoei_bind_port
226 * fpkt = The pointer to fc_packet
227 * sleep = This call can sleep or not
229 * Returns:
230 * FC_SUCCESS - Initialization completed successfully
232 * Comments:
233 * Link the exchange elements with proper objects
235 /* ARGSUSED */
236 static int
237 fcoei_init_pkt(void *fca_handle, fc_packet_t *fpkt, int sleep)
239 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
240 fcoei_exchange_t *xch = FPKT2XCH(fpkt);
242 ASSERT(sleep + 1);
243 xch->xch_ss = ss;
244 xch->xch_fpkt = fpkt;
245 xch->xch_flags = 0;
246 return (FC_SUCCESS);
250 * fcoei_un_init_pkt
251 * Uninitialize fcoei related part of fc_packet
253 * Input:
254 * fca_handle = fcoei soft state set in fcoei_bind_port
255 * fpkt = The pointer to fc_packet
257 * Returns:
258 * FC_SUCCESS - Uninitialize successfully
260 * Comments:
261 * Very simple, just return successfully
263 /* ARGSUSED */
264 static int
265 fcoei_un_init_pkt(void *fca_handle, fc_packet_t *fpkt)
267 ASSERT(fca_handle && fpkt);
268 return (FC_SUCCESS);
272 * fcoei_get_cap
273 * Export FCA hardware and software capability.
275 * Input:
276 * fca_handle = fcoei soft state set in fcoei_bind_port
277 * cap = pointer to the capability string
278 * ptr = buffer pointer for returning capability
280 * Returns:
281 * FC_CAP_ERROR - no such capability
282 * FC_CAP_FOUND - the capability was returned and cannot be set
284 * Comments:
285 * FC_CAP_UNSOL_BUF is one important capability, it will affect the
286 * implementation of fcoei_ub_alloc/free.
288 static int
289 fcoei_get_cap(void * fca_handle, char *cap, void *ptr)
291 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
292 uint32_t *rptr = (uint32_t *)ptr;
293 int rval = FC_CAP_FOUND;
295 ASSERT(fca_handle);
296 FCOEI_LOG(__FUNCTION__, "cap: %s", cap);
297 if (strcmp(cap, FC_NODE_WWN) == 0) {
298 bcopy(&ss->ss_els_logi.node_ww_name.raw_wwn[0], ptr, 8);
299 } else if (strcmp(cap, FC_LOGIN_PARAMS) == 0) {
300 bcopy((void *)&ss->ss_els_logi, ptr, sizeof (la_els_logi_t));
301 } else if (strcmp(cap, FC_CAP_UNSOL_BUF) == 0) {
302 *rptr = 0;
303 } else if (strcmp(cap, FC_CAP_NOSTREAM_ON_UNALIGN_BUF) == 0) {
304 *rptr = (uint32_t)FC_ALLOW_STREAMING;
305 } else if (strcmp(cap, FC_CAP_PAYLOAD_SIZE) == 0) {
306 *rptr = (uint32_t)2136;
307 } else if (strcmp(cap, FC_CAP_POST_RESET_BEHAVIOR) == 0) {
308 *rptr = FC_RESET_RETURN_ALL;
309 } else if (strcmp(cap, FC_CAP_FCP_DMA) == 0) {
310 *rptr = FC_NO_DVMA_SPACE;
311 } else {
312 rval = FC_CAP_ERROR;
313 FCOEI_LOG(__FUNCTION__, "not supported");
316 return (rval);
320 * fcoei_set_cap
321 * Allow the FC Transport to set FCA capabilities if possible
323 * Input:
324 * fca_handle = fcoei soft state set in fcoei_bind_port
325 * cap = pointer to the capabilities string.
326 * ptr = buffer pointer for capability.
328 * Returns:
329 * FC_CAP_ERROR - no such capability
331 * Comments:
332 * Currently, all capabilities can't be changed.
334 static int
335 fcoei_set_cap(void * fca_handle, char *cap, void *ptr)
337 FCOEI_LOG(__FUNCTION__, "cap: %s, %p, %p", cap, fca_handle, ptr);
338 return (FC_CAP_ERROR);
342 * fcoei_getmap
343 * Get lilp map
345 * Input:
346 * fca_handle = fcoei soft state set in fcoei_bind_port
347 * mapbuf = the buffer to store lilp map
349 * Returns:
350 * FC_FAILURE - Can't get the lilp map
352 * Comments:
353 * fcoei can't work in loop topology, so it should never get called
355 static int
356 fcoei_getmap(void * fca_handle, fc_lilpmap_t *mapbuf)
358 FCOEI_LOG(__FUNCTION__, "not: %p-%p", fca_handle, mapbuf);
359 return (FC_FAILURE);
363 * fcoei_ub_alloc
364 * Pre-allocate unsolicited buffers at the request of LV
366 * Input:
367 * fca_handle = fcoei soft state set in fcoei_bind_port
368 * tokens = token array for each buffer.
369 * size = number of tokens
370 * count = the acutual number of allocated unsolicited buffers
371 * type = unsolicited buffer type
373 * Returns:
374 * FC_SUCCESS - The requested buffers have been freeed
376 * Comments:
377 * fcoei_get_cap will set UNSOL_BUF to 0, so it should never get called.
379 static int
380 fcoei_ub_alloc(void * fca_handle, uint64_t tokens[], uint32_t size,
381 uint32_t *count, uint32_t type)
383 FCOEI_LOG(__FUNCTION__, "not: %p-%p-%x-%p-%x", fca_handle, tokens,
384 size, count, type);
385 return (FC_SUCCESS);
389 * fcoei_ub_free
390 * Free the pre-allocated unsolicited buffers at the request of LV
392 * Input:
393 * fca_handle = fcoei soft state set in fcoei_bind_port
394 * count = number of buffers.
395 * tokens = token array for each buffer.
397 * Returns:
398 * FC_SUCCESS - The requested buffers have been freeed
400 * Comments:
401 * fcoei_get_cap will set UNSOL_BUF to 0, so it should never get called.
403 static int
404 fcoei_ub_free(void * fca_handle, uint32_t count, uint64_t tokens[])
406 FCOEI_EXT_LOG(__FUNCTION__, "not: %p-%x-%p", fca_handle, count, tokens);
407 return (FC_SUCCESS);
411 * fcoei_ub_release
412 * Release unsolicited buffers from FC Transport to FCA for future use
414 * Input:
415 * fca_handle = fcoei soft state set in fcoei_bind_port
416 * count = number of buffers.
417 * tokens = token array for each buffer.
419 * Returns:
420 * FC_SUCCESS - The requested buffers have been released.
421 * FC_FAILURE - The requested buffers have not been released.
423 * Comments:
424 * It will always succeed. It has nothing to do with fcoei_ub_alloc/free.
426 static int
427 fcoei_ub_release(void * fca_handle, uint32_t count, uint64_t tokens[])
429 fc_unsol_buf_t *ub = *((fc_unsol_buf_t **)tokens);
431 if (count != 1) {
432 FCOEI_LOG(__FUNCTION__, "count is not 1: %p", fca_handle);
433 return (FC_FAILURE);
436 kmem_free(ub->ub_buffer, ub->ub_bufsize);
437 kmem_free(ub, sizeof (fc_unsol_buf_t));
438 FCOEI_EXT_LOG(__FUNCTION__, "ub is freeed");
439 return (FC_SUCCESS);
443 * fcoei_abort
444 * Direct FCA driver to abort an outstanding exchange associated with a
445 * specified fc_packet_t struct
447 * Input:
448 * fca_handle - fcoei soft state set in fcoei_bind_port
449 * fpkt - A pointer to the fc_packet_t for the exchange to be aborted.
450 * flags - Set to KM_SLEEP if the function may sleep, or KM_NOSLEEP if
451 * the function may not sleep.
453 * Returns:
454 * FC_ABORTED - The specified exchange was successfully aborted.
455 * FC_ABORTING - The specified exchange is being aborted.
456 * FC_ABORT_FAILED - The specified exchange could not be aborted.
457 * FC_TRANSPORT_ERROR - A transport error occurred while attempting to
458 * abort the specified exchange.
459 * FC_BADEXCHANGE - The specified exchange does not exist.
461 * Comments:
462 * After the exchange is aborted, the FCA driver must update the relevant
463 * fields in the fc_packet_t struct as per normal exchange completion and
464 * call the pkt_comp function to return the fc_packet_t struct to the FC
465 * Transport.
466 * When an exchange is successfully aborted, the FCA driver must set the
467 * pkt_reason field in the fc_packet_t to FC_REASON_ABORTED and the
468 * pkt_state field in the fc_packet_t to FC_PKT_LOCAL_RJT before returning
469 * the fc_packet_t to the FC Transport.
471 * Unfortunately, LV doesn't conform to the spec. It will take all these
472 * legal return value as failure to abort.
474 static int
475 fcoei_abort(void * fca_handle, fc_packet_t *fpkt, int flags)
477 FCOEI_LOG(__FUNCTION__, "not: %p-%p-%x", fca_handle, fpkt, flags);
478 return (FC_SUCCESS);
482 * fcoei_reset
483 * Reset link or hardware
485 * Input:
486 * fca_handle = fcoei soft state set in fcoei_bind_port
487 * cmd = reset type command
489 * Returns:
490 * FC_SUCCESS - Reset has completed successfully
491 * FC_FAILURE - Reset has failed
493 * Comments:
494 * N/A
496 static int
497 fcoei_reset(void * fca_handle, uint32_t cmd)
499 int rval = FC_SUCCESS;
500 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
501 fcoei_event_t *ae;
503 switch (cmd) {
504 case FC_FCA_LINK_RESET:
505 if (ss->ss_link_state != FC_STATE_ONLINE) {
506 FCOEI_LOG(__FUNCTION__, "not online now: ss-%p", ss);
507 rval = FC_FAILURE;
508 break;
512 * This is linkreset phase I
514 fcoei_logo_peer(ss);
515 delay(FCOE_SEC2TICK(1) / 10);
516 ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0);
517 fcoei_port_event(ss->ss_eport, FCOE_NOTIFY_EPORT_LINK_DOWN);
520 * Perpare linkreset phase II
522 ae = kmem_zalloc(sizeof (*ae), KM_SLEEP);
523 ae->ae_type = AE_EVENT_RESET;
524 ae->ae_obj = ss;
526 mutex_enter(&ss->ss_watchdog_mutex);
527 list_insert_tail(&ss->ss_event_list, ae);
528 mutex_exit(&ss->ss_watchdog_mutex);
529 break;
531 case FC_FCA_RESET:
532 break;
534 case FC_FCA_CORE:
535 break;
537 case FC_FCA_RESET_CORE:
538 break;
540 default:
541 rval = FC_FAILURE;
542 FCOEI_LOG(__FUNCTION__, "cmd-%x not supported", cmd);
543 break;
546 return (rval);
550 * fcoei_port_manage
551 * Perform various port management operations at the request of LV
553 * Input:
554 * fca_handle = fcoei soft state set in fcoei_bind_port
555 * pm = the pointer to the struct specifying the port management operation
557 * Returns:
558 * FC_SUCCESS - The request completed successfully
559 * FC_FAILURE - The request did not complete successfully
561 * Comments:
562 * N/A
564 static int
565 fcoei_port_manage(void * fca_handle, fc_fca_pm_t *pm)
567 int rval = FC_FAILURE;
568 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
570 if (fca_handle == NULL || pm == NULL) {
571 return (rval);
574 FCOEI_LOG(__FUNCTION__, "code0x%x, %p", pm->pm_cmd_code, fca_handle);
575 switch (pm->pm_cmd_code) {
577 case FC_PORT_GET_NODE_ID:
579 if (pm->pm_data_len < sizeof (fc_rnid_t)) {
580 rval = FC_NOMEM;
581 break;
583 ss->ss_rnid.port_id = ss->ss_p2p_info.fca_d_id;
584 bcopy((void *)&ss->ss_rnid,
585 pm->pm_data_buf, sizeof (fc_rnid_t));
586 rval = FC_SUCCESS;
587 break;
590 case FC_PORT_SET_NODE_ID:
592 if (pm->pm_data_len < sizeof (fc_rnid_t)) {
593 rval = FC_NOMEM;
594 break;
596 bcopy(pm->pm_data_buf,
597 (void *)&ss->ss_rnid, sizeof (fc_rnid_t));
598 rval = FC_SUCCESS;
599 break;
602 default:
603 FCOEI_LOG(__FUNCTION__, "unsupported cmd-%x", pm->pm_cmd_code);
604 rval = FC_INVALID_REQUEST;
605 break;
608 return (rval);
612 * fcoei_get_device
613 * Get fcoei remote port with FCID of d_id
615 * Input:
616 * fca_handle = fcoei soft state set in fcoei_bind_port
617 * d_id = 24-bit FCID of remote port
619 * Returns:
620 * The pointer to fcoei remote port
622 * Comments:
623 * fcoei has no remote port device
625 static void *
626 fcoei_get_device(void *fca_handle, fc_portid_t d_id)
628 FCOEI_EXT_LOG(__FUNCTION__, "not supported: %p-%x", fca_handle, d_id);
629 return (NULL);
633 * fcoei_notify
634 * Notify the change of target device
636 * Input:
637 * fca_handle = fcoei soft state set in fcoei_bind_port
638 * cmd = detailed cmd
640 * Returns:
641 * FC_SUCCESS - Notification completed successfully
643 * Comments:
644 * It's only needed to support non-COMSTAR FC target, so it should
645 * never get called.
647 static int
648 fcoei_notify(void *fca_handle, uint32_t cmd)
650 FCOEI_LOG(__FUNCTION__, "not supported: %p-%x", fca_handle, cmd);
651 return (FC_SUCCESS);
655 * fcoei_transport
656 * Submit FCP/CT requests
658 * Input:
659 * fca_handle - fcoei soft state set in fcoei_bind_port
660 * fpkt - LV fc_packet
662 * Returns:
663 * N/A
665 * Comments:
666 * N/A
668 static int
669 fcoei_transport(void *fca_handle, fc_packet_t *fpkt)
671 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
672 fcoei_exchange_t *xch = FPKT2XCH(fpkt);
673 uint16_t pkt_tran_flags = fpkt->pkt_tran_flags;
675 xch->xch_start_tick = ddi_get_lbolt();
676 xch->xch_end_tick = xch->xch_start_tick +
677 FCOE_SEC2TICK(fpkt->pkt_timeout);
678 xch->xch_ae.ae_type = AE_EVENT_EXCHANGE;
679 xch->xch_ae.ae_obj = xch;
681 if (pkt_tran_flags & FC_TRAN_NO_INTR) {
682 FCOEI_LOG(__FUNCTION__, "AaA polling: %p-%p", fpkt, xch);
683 sema_init(&xch->xch_sema, 0, NULL, SEMA_DRIVER, NULL);
686 mutex_enter(&ss->ss_watchdog_mutex);
687 list_insert_tail(&ss->ss_event_list, &xch->xch_ae);
688 if (ss->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
689 cv_signal(&ss->ss_watchdog_cv);
691 mutex_exit(&ss->ss_watchdog_mutex);
693 if (pkt_tran_flags & FC_TRAN_NO_INTR) {
694 FCOEI_LOG(__FUNCTION__, "BaB polling: %p-%p", fpkt, xch);
695 sema_p(&xch->xch_sema);
696 sema_destroy(&xch->xch_sema);
697 FCOEI_LOG(__FUNCTION__, "after polling: %p-%p", fpkt, xch);
700 return (FC_SUCCESS);
704 * fcoei_els_send
705 * Submit ELS request or response
707 * Input:
708 * fca_handle - fcoei soft state set in fcoei_bind_port
709 * fpkt = LV fc_packet
711 * Returns:
712 * N/A
714 * Comments:
715 * N/A
717 static int
718 fcoei_els_send(void *fca_handle, fc_packet_t *fpkt)
720 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
721 fcoei_exchange_t *xch = FPKT2XCH(fpkt);
723 if (fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
724 FCOEI_LOG(__FUNCTION__, "ELS poll mode is not supported");
725 return (FC_BADPACKET);
728 xch->xch_start_tick = ddi_get_lbolt();
729 xch->xch_end_tick = xch->xch_start_tick +
730 FCOE_SEC2TICK(fpkt->pkt_timeout);
731 xch->xch_ae.ae_type = AE_EVENT_EXCHANGE;
732 xch->xch_ae.ae_obj = xch;
735 * LV could release ub after this call, so we must save the ub type
736 * for later use
738 if (fpkt->pkt_cmd_fhdr.r_ctl == R_CTL_ELS_RSP) {
739 ((uint8_t *)&fpkt->pkt_fca_rsvd1)[0] =
740 ((fc_unsol_buf_t *)fpkt->pkt_ub_resp_token)->ub_buffer[0];
743 mutex_enter(&ss->ss_watchdog_mutex);
744 list_insert_tail(&ss->ss_event_list, &xch->xch_ae);
745 if (ss->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
746 cv_signal(&ss->ss_watchdog_cv);
748 mutex_exit(&ss->ss_watchdog_mutex);
750 return (FC_SUCCESS);
754 * fcoei_populate_hba_fru_details
755 * Fill detailed information about HBA
757 * Input:
758 * ss - fcoei soft state
759 * port_info = fc_fca_port_info_t that need be updated
761 * Returns:
762 * N/A
764 * Comments:
765 * N/A
767 static void
768 fcoei_populate_hba_fru_details(fcoei_soft_state_t *ss,
769 fc_fca_port_info_t *port_info)
771 fca_port_attrs_t *port_attrs = &(port_info->pi_attrs);
772 int instance;
774 ASSERT(ss != NULL);
775 (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
776 "Sun Microsystems, Inc.");
777 (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
778 "%s", FCOEI_NAME_VERSION);
779 (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
780 "%s", FCOEI_VERSION);
781 (void) strcpy(port_attrs->serial_number, "N/A");
782 (void) strcpy(port_attrs->hardware_version, "N/A");
783 (void) strcpy(port_attrs->model, "FCoE Virtual FC HBA");
784 (void) strcpy(port_attrs->model_description, "N/A");
785 (void) strcpy(port_attrs->firmware_version, "N/A");
786 (void) strcpy(port_attrs->option_rom_version, "N/A");
788 port_attrs->vendor_specific_id = 0xFC0E;
789 port_attrs->max_frame_size = FCOE_MAX_FC_FRAME_SIZE;
790 port_attrs->supported_cos = 0x10000000;
791 port_attrs->supported_speed = FC_HBA_PORTSPEED_1GBIT |
792 FC_HBA_PORTSPEED_10GBIT;
793 instance = ddi_get_instance(ss->ss_dip);
794 port_attrs->hba_fru_details.high =
795 (short)((instance & 0xffff0000) >> 16);
796 port_attrs->hba_fru_details.low =
797 (short)(instance & 0x0000ffff);
801 * fcoei_port_enabled
802 * Notify fcoe that the port has been enabled
804 * Input:
805 * arg = the related soft state
807 * Returns:
808 * N/A
810 * Comments:
811 * Only after this, fcoe will report the link status to us
813 static void
814 fcoei_port_enabled(void *arg)
816 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)arg;
818 ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, NULL);
823 * fcoei_initiate_ct_req
824 * Fill and submit CT request
826 * Input:
827 * xch - the exchange that will be initiated
829 * Returns:
830 * N/A
832 * Comments:
833 * N/A
835 static void
836 fcoei_initiate_ct_req(fcoei_exchange_t *xch)
838 fc_packet_t *fpkt = xch->xch_fpkt;
839 fc_ct_header_t *ct = (fc_ct_header_t *)(void *)fpkt->pkt_cmd;
840 uint8_t *bp = (uint8_t *)fpkt->pkt_cmd;
841 fcoe_frame_t *frm;
842 int offset;
843 int idx;
844 uint32_t cmd_len = fpkt->pkt_cmdlen;
847 * Ensure it's 4-byte aligned
849 cmd_len = P2ROUNDUP(cmd_len, 4);
852 * Allocate CT request frame
854 frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
855 cmd_len + FCFH_SIZE, NULL);
856 if (frm == NULL) {
857 FCOEI_LOG(__FUNCTION__, "failed to alloc: %p", xch);
858 return;
861 bzero(frm->frm_payload, cmd_len);
862 xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
863 atomic_inc_32(xch->xch_cnt);
865 FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
866 FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
867 FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
868 FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
869 FFM_F_CTL(fpkt->pkt_cmd_fhdr.f_ctl, frm);
870 FFM_OXID(xch->xch_oxid, frm);
871 FFM_RXID(xch->xch_rxid, frm);
872 fcoei_init_ifm(frm, xch);
875 * CT header (FC payload)
877 offset = 0;
878 FCOE_V2B_1(ct->ct_rev, FPLD + offset);
880 offset = 1;
881 FCOE_V2B_3(ct->ct_inid, FPLD + offset);
883 offset = 4;
884 FCOE_V2B_1(ct->ct_fcstype, FPLD + offset);
886 offset = 5;
887 FCOE_V2B_1(ct->ct_fcssubtype, FPLD + offset);
889 offset = 6;
890 FCOE_V2B_1(ct->ct_options, FPLD + offset);
892 offset = 8;
893 FCOE_V2B_2(ct->ct_cmdrsp, FPLD + offset);
895 offset = 10;
896 FCOE_V2B_2(ct->ct_aiusize, FPLD + offset);
898 offset = 13;
899 FCOE_V2B_1(ct->ct_reason, FPLD + offset);
901 offset = 14;
902 FCOE_V2B_1(ct->ct_expln, FPLD + offset);
904 offset = 15;
905 FCOE_V2B_1(ct->ct_vendor, FPLD + offset);
908 * CT payload (FC payload)
910 switch (ct->ct_fcstype) {
911 case FCSTYPE_DIRECTORY:
912 switch (ct->ct_cmdrsp) {
913 case NS_GA_NXT:
914 case NS_GPN_ID:
915 case NS_GNN_ID:
916 case NS_GCS_ID:
917 case NS_GFT_ID:
918 case NS_GSPN_ID:
919 case NS_GPT_ID:
920 case NS_GID_FT:
921 case NS_GID_PT:
922 case NS_DA_ID:
923 offset = 16;
924 FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
925 FPLD + offset);
926 break;
928 case NS_GID_PN:
929 offset = 16;
930 bcopy(bp + offset, FPLD + offset, 8);
931 break;
933 case NS_RNN_ID:
934 case NS_RPN_ID:
935 offset = 16;
936 FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
937 FPLD + offset);
939 offset = 20;
940 bcopy(bp + offset, FPLD + offset, 8);
941 break;
943 case NS_RSPN_ID:
944 offset = 16;
945 FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
946 FPLD + offset);
948 offset = 20;
949 bcopy(bp + offset, FPLD + offset, bp[20] + 1);
950 break;
952 case NS_RSNN_NN:
953 offset = 16;
954 bcopy(bp + offset, FPLD + offset, 8);
956 offset = 24;
957 bcopy(bp + offset, FPLD + offset, bp[24] + 1);
958 break;
960 case NS_RFT_ID:
961 offset = 16;
962 FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
963 FPLD + offset);
966 * fp use bcopy to copy fp_fc4_types,
967 * we need to swap order for each integer
969 offset = 20;
970 for (idx = 0; idx < 8; idx++) {
971 FCOE_V2B_4(
972 ((uint32_t *)(intptr_t)(bp + offset))[0],
973 FPLD + offset);
974 offset += 4;
976 break;
978 case NS_RCS_ID:
979 case NS_RPT_ID:
980 offset = 16;
981 FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
982 FPLD + offset);
984 offset = 20;
985 FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
986 FPLD + offset);
987 break;
989 case NS_RIP_NN:
990 offset = 16;
991 bcopy(bp + offset, FPLD + offset, 24);
992 break;
994 default:
995 fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
996 FC_REASON_CMD_UNSUPPORTED);
997 break;
999 break; /* FCSTYPE_DIRECTORY */
1001 case FCSTYPE_MGMTSERVICE:
1002 switch (ct->ct_cmdrsp) {
1003 case MS_GIEL:
1004 FCOEI_LOG(__FUNCTION__,
1005 "MS_GIEL ct_fcstype %x, ct_cmdrsp: %x",
1006 ct->ct_fcstype, ct->ct_cmdrsp);
1007 break;
1009 default:
1010 fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1011 FC_REASON_CMD_UNSUPPORTED);
1012 break;
1014 break; /* FCSTYPE_MGMTSERVICE */
1016 default:
1017 fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1018 FC_REASON_CMD_UNSUPPORTED);
1019 break;
1021 xch->xch_ss->ss_eport->eport_tx_frame(frm);
1025 * fcoei_initiate_fcp_cmd
1026 * Submit FCP command
1028 * Input:
1029 * xch - the exchange to be submitted
1031 * Returns:
1032 * N/A
1034 * Comments:
1035 * N/A
1037 static void
1038 fcoei_initiate_fcp_cmd(fcoei_exchange_t *xch)
1040 fc_packet_t *fpkt = xch->xch_fpkt;
1041 fcoe_frame_t *frm;
1042 fcp_cmd_t *fcp_cmd_iu = (fcp_cmd_t *)(void *)fpkt->pkt_cmd;
1043 int offset = 0;
1045 ASSERT((fpkt->pkt_cmdlen % 4) == 0);
1046 frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1047 fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
1048 if (!frm) {
1049 ASSERT(0);
1050 } else {
1051 fcoei_init_ifm(frm, xch);
1052 bzero(frm->frm_payload, fpkt->pkt_cmdlen);
1056 * This will affect timing check
1058 xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
1059 atomic_inc_32(xch->xch_cnt);
1062 * Set exchange residual bytes
1064 xch->xch_resid = (int)fpkt->pkt_datalen;
1067 * Fill FCP command IU
1069 * fcp_ent_addr
1071 FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_0,
1072 frm->frm_payload + offset);
1073 offset += 2;
1074 FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_1,
1075 frm->frm_payload + offset);
1076 offset += 2;
1077 FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_2,
1078 frm->frm_payload + offset);
1079 offset += 2;
1080 FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_3,
1081 frm->frm_payload + offset);
1083 * fcp_cntl
1085 offset = offsetof(fcp_cmd_t, fcp_cntl);
1086 frm->frm_payload[offset] = 0;
1088 offset += 1;
1089 frm->frm_payload[offset] = fcp_cmd_iu->fcp_cntl.cntl_qtype & 0x07;
1090 offset += 1;
1091 frm->frm_payload[offset] =
1092 (fcp_cmd_iu->fcp_cntl.cntl_kill_tsk << 7) |
1093 (fcp_cmd_iu->fcp_cntl.cntl_clr_aca << 6) |
1094 (fcp_cmd_iu->fcp_cntl.cntl_reset_tgt << 5) |
1095 (fcp_cmd_iu->fcp_cntl.cntl_reset_lun << 4) |
1096 (fcp_cmd_iu->fcp_cntl.cntl_clr_tsk << 2) |
1097 (fcp_cmd_iu->fcp_cntl.cntl_abort_tsk << 1);
1098 offset += 1;
1099 frm->frm_payload[offset] =
1100 (fcp_cmd_iu->fcp_cntl.cntl_read_data << 1) |
1101 (fcp_cmd_iu->fcp_cntl.cntl_write_data);
1103 * fcp_cdb
1105 offset = offsetof(fcp_cmd_t, fcp_cdb);
1106 bcopy(fcp_cmd_iu->fcp_cdb, frm->frm_payload + offset, FCP_CDB_SIZE);
1108 * fcp_data_len
1110 offset += FCP_CDB_SIZE;
1111 FCOE_V2B_4(fcp_cmd_iu->fcp_data_len, frm->frm_payload + offset);
1114 * FC frame header
1116 FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
1118 FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
1119 FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1120 FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1121 FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
1122 FFM_F_CTL(0x290000, frm);
1123 FFM_OXID(xch->xch_oxid, frm);
1124 FFM_RXID(xch->xch_rxid, frm);
1126 xch->xch_ss->ss_eport->eport_tx_frame(frm);
1130 * fcoei_initiate_els_req
1131 * Initiate ELS request
1133 * Input:
1134 * xch = the exchange that will be initiated
1136 * Returns:
1137 * N/A
1139 * Comments:
1140 * N/A
1142 static void
1143 fcoei_initiate_els_req(fcoei_exchange_t *xch)
1145 fc_packet_t *fpkt = xch->xch_fpkt;
1146 fcoe_frame_t *frm;
1147 ls_code_t *els_code;
1149 ASSERT((fpkt->pkt_cmdlen % 4) == 0);
1150 frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1151 fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
1152 if (!frm) {
1153 ASSERT(0);
1154 } else {
1155 fcoei_init_ifm(frm, xch);
1156 bzero(frm->frm_payload, fpkt->pkt_cmdlen);
1160 * This will affect timing check
1162 xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
1163 atomic_inc_32(xch->xch_cnt);
1165 els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1166 switch (els_code->ls_code) {
1167 case LA_ELS_FLOGI:
1169 * For FLOGI, we expect response within E_D_TOV
1171 xch->xch_start_tick = ddi_get_lbolt();
1172 xch->xch_end_tick = xch->xch_start_tick +
1173 FCOE_SEC2TICK(2);
1174 xch->xch_ss->ss_flags &= ~SS_FLAG_FLOGI_FAILED;
1175 /* FALLTHROUGH */
1177 case LA_ELS_PLOGI:
1178 fcoei_fill_els_logi_cmd(fpkt, frm);
1179 break;
1181 case LA_ELS_PRLI:
1182 fcoei_fill_els_prli_cmd(fpkt, frm);
1183 break;
1185 case LA_ELS_SCR:
1186 fcoei_fill_els_scr_cmd(fpkt, frm);
1187 break;
1189 case LA_ELS_LINIT:
1190 fcoei_fill_els_linit_cmd(fpkt, frm);
1191 break;
1193 case LA_ELS_ADISC:
1194 fcoei_fill_els_adisc_cmd(fpkt, frm);
1195 break;
1197 case LA_ELS_LOGO:
1199 * For LOGO, we expect response within E_D_TOV
1201 xch->xch_start_tick = ddi_get_lbolt();
1202 xch->xch_end_tick = xch->xch_start_tick +
1203 FCOE_SEC2TICK(2);
1204 fcoei_fill_els_logo_cmd(fpkt, frm);
1205 break;
1206 case LA_ELS_RLS:
1207 fcoei_fill_els_rls_cmd(fpkt, frm);
1208 break;
1209 case LA_ELS_RNID:
1210 fcoei_fill_els_rnid_cmd(fpkt, frm);
1211 break;
1212 default:
1213 fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1214 FC_REASON_CMD_UNSUPPORTED);
1215 return;
1219 * set ifm_rtcl
1221 FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
1224 * FCPH
1226 FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
1227 FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1228 FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1229 FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
1230 FFM_F_CTL(0x290000, frm);
1231 FFM_OXID(xch->xch_oxid, frm);
1232 FFM_RXID(xch->xch_rxid, frm);
1234 xch->xch_ss->ss_eport->eport_tx_frame(frm);
1238 * fcoei_initiate_els_resp
1239 * Originate ELS response
1241 * Input:
1242 * xch = the associated exchange
1244 * Returns:
1245 * N/A
1247 * Comments:
1248 * N/A
1250 static void
1251 fcoei_initiate_els_resp(fcoei_exchange_t *xch)
1253 fc_packet_t *fpkt = xch->xch_fpkt;
1254 fcoe_frame_t *frm;
1256 ASSERT((fpkt->pkt_cmdlen % 4) == 0);
1257 frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1258 fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
1259 if (!frm) {
1260 ASSERT(0);
1261 } else {
1262 fcoei_init_ifm(frm, xch);
1263 bzero(frm->frm_payload, fpkt->pkt_cmdlen);
1267 * This will affect timing check
1269 xch->xch_cnt = xch->xch_ss->ss_unsol_cnt;
1270 atomic_inc_32(xch->xch_cnt);
1273 * Set ifm_rctl
1275 FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
1278 * FCPH
1280 FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
1281 FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1282 FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1283 FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
1284 FFM_F_CTL(0x980000, frm);
1285 FFM_OXID(xch->xch_oxid, frm);
1286 FFM_RXID(xch->xch_rxid, frm);
1288 switch (((uint8_t *)&fpkt->pkt_fca_rsvd1)[0]) {
1289 case LA_ELS_FLOGI:
1290 fcoei_fill_els_logi_resp(fpkt, frm);
1291 break;
1293 case LA_ELS_PLOGI:
1294 if (FRM2SS(frm)->ss_eport->eport_flags &
1295 EPORT_FLAG_IS_DIRECT_P2P) {
1296 FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_S_ID(frm);
1297 FRM2SS(frm)->ss_p2p_info.d_id = FRM_D_ID(frm);
1300 fcoei_fill_els_logi_resp(fpkt, frm);
1301 break;
1303 case LA_ELS_PRLI:
1304 fcoei_fill_els_prli_resp(fpkt, frm);
1305 break;
1307 case LA_ELS_ADISC:
1308 fcoei_fill_els_adisc_resp(fpkt, frm);
1309 break;
1311 case LA_ELS_LOGO:
1312 fcoei_fill_els_logo_resp(fpkt, frm);
1313 break;
1314 case LA_ELS_RSCN:
1315 fcoei_fill_els_acc_resp(fpkt, frm);
1316 break;
1318 default:
1319 fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1320 FC_REASON_CMD_UNSUPPORTED);
1321 return;
1324 xch->xch_ss->ss_eport->eport_tx_frame(frm);
1328 * fcoei_fill_els_logi_cmd
1329 * Fill SCR (state change register) command frame
1331 * Input:
1332 * fpkt = LV fc_packet
1333 * frm = Unsolicited frame containing LOGI response
1335 * Returns:
1336 * N/A
1338 * Comments:
1339 * N/A
1341 static void
1342 fcoei_fill_els_logi_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1344 la_els_logi_t *els_logi = (la_els_logi_t *)(void *)fpkt->pkt_cmd;
1345 int offset;
1348 * fill ls_code
1350 offset = 0;
1351 FCOE_V2B_1(els_logi->ls_code.ls_code, FPLD + offset);
1354 * fill common service parameters
1356 offset = 4;
1357 FCOE_V2B_2(els_logi->common_service.fcph_version, FPLD + offset);
1359 offset = 6;
1360 FCOE_V2B_2(els_logi->common_service.btob_credit, FPLD + offset);
1362 offset = 8;
1363 FCOE_V2B_2(els_logi->common_service.cmn_features, FPLD + offset);
1365 offset = 10;
1366 FCOE_V2B_2(els_logi->common_service.rx_bufsize, FPLD + offset);
1368 offset = 12;
1369 FCOE_V2B_2(els_logi->common_service.conc_sequences, FPLD + offset);
1371 offset = 14;
1372 FCOE_V2B_2(els_logi->common_service.relative_offset, FPLD + offset);
1374 offset = 16;
1375 FCOE_V2B_4(els_logi->common_service.e_d_tov, FPLD + offset);
1378 * port/node wwn
1380 offset = 20;
1381 bcopy(&els_logi->nport_ww_name, FPLD + offset, 8);
1383 offset = 28;
1384 bcopy(&els_logi->node_ww_name, FPLD + offset, 8);
1387 * class_3
1389 offset = 68;
1390 FCOE_V2B_2(els_logi->class_3.class_opt, FPLD + offset);
1392 offset = 70;
1393 FCOE_V2B_2(els_logi->class_3.initiator_ctl, FPLD + offset);
1395 offset = 72;
1396 FCOE_V2B_2(els_logi->class_3.recipient_ctl, FPLD + offset);
1398 offset = 74;
1399 FCOE_V2B_2(els_logi->class_3.rcv_size, FPLD + offset);
1401 offset = 76;
1402 FCOE_V2B_2(els_logi->class_3.conc_sequences, FPLD + offset);
1404 offset = 78;
1405 FCOE_V2B_2(els_logi->class_3.n_port_e_to_e_credit, FPLD + offset);
1407 offset = 80;
1408 FCOE_V2B_2(els_logi->class_3.open_seq_per_xchng, FPLD + offset);
1410 * needn't touch other fields
1415 * fcoei_fill_prli_cmd
1416 * Fill PRLI command frame
1418 * Input:
1419 * fpkt = LV fc_packet
1420 * frm = Unsolicited frame containing PRLI response
1422 * Returns:
1423 * N/A
1425 * Comments:
1426 * N/A
1428 static void
1429 fcoei_fill_els_prli_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1431 int offset = 0;
1432 la_els_prli_t *els_prli = (la_els_prli_t *)(void *)fpkt->pkt_cmd;
1433 struct fcp_prli *fcp_spp =
1434 (struct fcp_prli *)(void *)els_prli->service_params;
1437 * fill basic PRLI fields
1439 offset = 0;
1440 FCOE_V2B_1(els_prli->ls_code, FPLD + offset);
1442 offset = 1;
1443 FCOE_V2B_1(els_prli->page_length, FPLD + offset);
1445 offset = 2;
1446 FCOE_V2B_2(els_prli->payload_length, FPLD + offset);
1449 * fill FCP service parameters page
1451 offset = 4;
1452 FCOE_V2B_1(fcp_spp->type, FPLD + offset);
1455 * PRLI flags, only 3 bits are valid
1457 offset = 6;
1459 FCOE_V2B_2(((fcp_spp->orig_process_assoc_valid << 15) |
1460 (fcp_spp->resp_process_assoc_valid << 14) |
1461 (fcp_spp->establish_image_pair << 13)), FPLD + offset);
1464 * process associator
1466 offset = 8;
1467 FCOE_V2B_4(fcp_spp->orig_process_associator, FPLD + offset);
1469 offset = 12;
1470 FCOE_V2B_4(fcp_spp->resp_process_associator, FPLD + offset);
1473 * FC-4 type
1475 offset = 16;
1476 FCOE_V2B_4((fcp_spp->retry << 8) |
1477 (fcp_spp->confirmed_compl_allowed << 7) |
1478 (fcp_spp->data_overlay_allowed << 6) |
1479 (fcp_spp->initiator_fn << 5) | (fcp_spp->target_fn << 4) |
1480 (fcp_spp->read_xfer_rdy_disabled << 1) |
1481 (fcp_spp->write_xfer_rdy_disabled), FPLD + offset);
1485 * fcoei_fill_els_scr_cmd
1486 * Fill SCR (state change register) command frame
1488 * Input:
1489 * fpkt = LV fc_packet
1490 * frm = Unsolicited frame containing SCR command
1492 * Returns:
1493 * N/A
1495 * Comments:
1496 * N/A
1498 static void
1499 fcoei_fill_els_scr_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1501 fc_scr_req_t *els_scr = (fc_scr_req_t *)(void *)fpkt->pkt_cmd;
1502 int offset;
1504 offset = 0;
1505 FCOE_V2B_1(els_scr->ls_code.ls_code, FPLD + offset);
1507 offset = 7;
1508 FCOE_V2B_1(els_scr->scr_func, FPLD + offset);
1512 * fcoei_fill_els_adisc_cmd
1513 * Fill ADISC command frame
1515 * Input:
1516 * fpkt = LV fc_packet
1517 * frm = Unsolicited frame containing ADISC command
1519 * Returns:
1520 * N/A
1522 * Comments:
1523 * N/A
1525 static void
1526 fcoei_fill_els_adisc_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1528 la_els_adisc_t *els_adisc = (la_els_adisc_t *)(void *)fpkt->pkt_cmd;
1529 int offset;
1531 offset = 0;
1532 FCOE_V2B_1(els_adisc->ls_code.ls_code, FPLD + offset);
1534 offset = 5;
1535 FCOE_V2B_3(els_adisc->hard_addr.hard_addr, FPLD + offset);
1537 offset = 8;
1538 bcopy(&els_adisc->port_wwn, FPLD + offset, 8);
1540 offset = 16;
1541 bcopy(&els_adisc->node_wwn, FPLD + offset, 8);
1543 offset = 25;
1544 FCOE_V2B_3(els_adisc->nport_id.port_id, FPLD + offset);
1548 * fcoei_fill_els_linit_cmd
1549 * Fill LINIT command frame
1551 * Input:
1552 * fpkt = LV fc_packet
1553 * frm = Unsolicited frame containing LINIT command
1555 * Returns:
1556 * N/A
1558 * Comments:
1559 * N/A
1561 /* ARGSUSED */
1562 static void
1563 fcoei_fill_els_linit_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1565 ASSERT(fpkt && frm);
1569 * fcoei_fill_els_logo_cmd
1570 * Fill LOGO command frame
1572 * Input:
1573 * fpkt = LV fc_packet
1574 * frm = Unsolicited frame containing LOGO command
1576 * Returns:
1577 * N/A
1579 * Comments:
1580 * N/A
1582 static void
1583 fcoei_fill_els_logo_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1585 la_els_logo_t *els_logo = (la_els_logo_t *)(void *)fpkt->pkt_cmd;
1586 int offset;
1588 offset = 0;
1589 FCOE_V2B_1(els_logo->ls_code.ls_code, FPLD + offset);
1591 offset = 5;
1592 FCOE_V2B_3(els_logo->nport_id.port_id, FPLD + offset);
1594 offset = 8;
1595 bcopy(&els_logo->nport_ww_name, FPLD + offset, 8);
1598 static void
1599 fcoei_fill_els_rls_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1601 la_els_rls_t *els_rls = (la_els_rls_t *)(void *)fpkt->pkt_cmd;
1602 int offset;
1604 offset = 0;
1605 FCOE_V2B_1(els_rls->ls_code.ls_code, FPLD + offset);
1607 offset = 5;
1608 FCOE_V2B_3(els_rls->rls_portid.port_id, FPLD + offset);
1611 static void
1612 fcoei_fill_els_rnid_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1614 la_els_rnid_t *els_rnid = (la_els_rnid_t *)(void *)fpkt->pkt_cmd;
1615 int offset;
1617 offset = 0;
1618 FCOE_V2B_1(els_rnid->ls_code.ls_code, FPLD + offset);
1620 offset = 4;
1621 bcopy(&els_rnid->data_format, FPLD + offset, 1);
1624 * fcoei_fill_els_acc_resp
1625 * Fill ELS ACC response frame
1627 * Input:
1628 * fpkt = LV fc_packet
1629 * frm = Unsolicited frame containing ELS ACC response
1631 * Returns:
1632 * N/A
1634 * Comments:
1635 * N/A
1637 static void
1638 fcoei_fill_els_acc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1640 ls_code_t *els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1641 int offset;
1643 offset = 0;
1644 FCOE_V2B_1(els_code->ls_code, FPLD + offset);
1646 offset = 1;
1647 FCOE_V2B_3(els_code->mbz, FPLD + offset);
1651 * fcoei_fill_els_rjt_resp
1652 * Fill ELS RJT response frame
1654 * Input:
1655 * fpkt = LV fc_packet
1656 * frm = Unsolicited frame containg ELS RJT response
1658 * Returns:
1659 * N/A
1661 * Comments:
1662 * N/A
1664 static void
1665 fcoei_fill_els_rjt_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1667 la_els_rjt_t *els_rjt = (la_els_rjt_t *)(void *)fpkt->pkt_cmd;
1668 int offset;
1670 offset = 0; /* reset ls code */
1671 FCOE_V2B_1(els_rjt->ls_code.ls_code, FPLD + offset);
1673 offset = 5; /* reason code */
1674 FCOE_V2B_1(els_rjt->action, FPLD + offset);
1676 offset = 6; /* reason explanation */
1677 FCOE_V2B_1(els_rjt->reason, FPLD + offset);
1679 offset = 7; /* vendor unique */
1680 FCOE_V2B_1(els_rjt->vu, FPLD + offset);
1684 * fcoei_fill_els_adisc_resp
1685 * Fill ADISC response frame
1687 * Input:
1688 * fpkt = LV fc_packet
1689 * frm = Unsolicited frame containing ADISC response
1691 * Returns:
1692 * N/A
1694 * Comments:
1695 * N/A
1697 static void
1698 fcoei_fill_els_adisc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1700 la_els_adisc_t *els_adisc = (la_els_adisc_t *)(void *)fpkt->pkt_cmd;
1701 int offset;
1703 if (els_adisc->ls_code.ls_code == LA_ELS_RJT) {
1704 fcoei_fill_els_rjt_resp(fpkt, frm);
1705 } else {
1706 offset = 0;
1707 FCOE_V2B_1(els_adisc->ls_code.ls_code, FPLD + offset);
1709 offset = 5;
1710 FCOE_V2B_3(els_adisc->hard_addr.hard_addr, FPLD + offset);
1712 offset = 8;
1713 bcopy(&els_adisc->port_wwn, FPLD + offset, FC_WWN_SIZE);
1715 offset = 16;
1716 bcopy(&els_adisc->node_wwn, FPLD + offset, FC_WWN_SIZE);
1718 offset = 25;
1719 FCOE_V2B_3(els_adisc->nport_id.port_id, FPLD + offset);
1724 * fcoei_fill_els_logi_resp
1725 * Fill FLOGI/PLOGI response frame
1727 * Input:
1728 * fpkt = LV fc_packet
1729 * frm = Unsolicited frame containing LOGI response
1731 * Returns:
1732 * N/A
1734 * Comments:
1735 * N/A
1737 static void
1738 fcoei_fill_els_logi_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1740 ls_code_t *els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1742 if (els_code->ls_code == LA_ELS_RJT) {
1743 fcoei_fill_els_rjt_resp(fpkt, frm);
1744 } else {
1745 fcoei_fill_els_logi_cmd(fpkt, frm);
1750 * fcoei_fill_els_prli_resp
1751 * Fill PRLI response frame
1753 * Input:
1754 * fpkt = LV fc_packet
1755 * frm = Unsolicited frame containing PRLI response
1757 * Returns:
1758 * N/A
1760 * Comments:
1761 * N/A
1763 static void
1764 fcoei_fill_els_prli_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1766 ls_code_t *els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1768 if (els_code->ls_code == LA_ELS_RJT) {
1769 fcoei_fill_els_rjt_resp(fpkt, frm);
1770 } else {
1771 fcoei_fill_els_prli_cmd(fpkt, frm);
1776 * fcoei_fill_els_logo_resp
1777 * Fill LOGO response frame
1779 * Input:
1780 * fpkt = LV fc_packet
1781 * frm = Unsolicited frame containing LOGO response
1783 * Returns:
1784 * N/A
1786 * Comments:
1787 * N/A
1789 static void
1790 fcoei_fill_els_logo_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1792 ls_code_t *els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1794 if (els_code->ls_code == LA_ELS_RJT) {
1795 fcoei_fill_els_rjt_resp(fpkt, frm);
1796 } else {
1797 fcoei_fill_els_acc_resp(fpkt, frm);
1802 * fcoei_logo_peer
1803 * Send LOGO to the peer to emulate link offline event
1805 * Input:
1806 * arg - fcoei soft state set in fcoei_bind_port
1808 * Returns:
1809 * N/A
1811 * Comments:
1812 * N/A
1814 static void
1815 fcoei_logo_peer(void *arg)
1817 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)arg;
1818 fc_packet_t *fpkt;
1819 fcoei_exchange_t *xch;
1820 la_els_logo_t *els_logo;
1823 * Allocate space for exchange
1825 xch = kmem_zalloc(sizeof (*xch), KM_SLEEP);
1828 * Allocate space for fc_packet
1830 fpkt = kmem_zalloc(sizeof (fc_packet_t), KM_SLEEP);
1831 fpkt->pkt_cmdlen = 20;
1832 fpkt->pkt_cmd = kmem_zalloc(fpkt->pkt_cmdlen, KM_SLEEP);
1833 fpkt->pkt_rsplen = 20;
1834 fpkt->pkt_resp = kmem_zalloc(fpkt->pkt_rsplen, KM_SLEEP);
1837 * Link them together
1839 fpkt->pkt_fca_private = xch;
1840 (void) fcoei_init_pkt(ss, fpkt, 0);
1843 * Initialize FC frame header
1845 if (ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P) {
1846 fpkt->pkt_cmd_fhdr.d_id = ss->ss_p2p_info.d_id;
1847 } else {
1848 fpkt->pkt_cmd_fhdr.d_id = 0xFFFFFE;
1851 fpkt->pkt_cmd_fhdr.s_id = ss->ss_p2p_info.fca_d_id;
1852 fpkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
1853 fpkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
1854 fpkt->pkt_cmd_fhdr.f_ctl = 0x290000;
1855 fpkt->pkt_timeout = 1;
1858 * Initialize LOGO payload
1860 els_logo = (la_els_logo_t *)(void *)fpkt->pkt_cmd;
1861 els_logo->ls_code.ls_code = LA_ELS_LOGO;
1862 els_logo->nport_id.port_id = ss->ss_p2p_info.fca_d_id;
1863 bcopy(ss->ss_eport->eport_portwwn, &els_logo->nport_ww_name, 8);
1866 * Set the completion function
1868 fpkt->pkt_comp = fcoei_fpkt_comp;
1869 if (fcoei_transport(ss, fpkt) != FC_SUCCESS) {
1870 FCOEI_LOG(__FUNCTION__, "fcoei_transport LOGO failed");
1871 fcoei_fpkt_comp(fpkt);
1876 * fcoei_fpkt_comp
1877 * internal exchange completion
1879 * Input:
1880 * fpkt - fc_packet_t to be completed
1882 * Returns:
1883 * N/A
1885 * Comments:
1888 static void
1889 fcoei_fpkt_comp(fc_packet_t *fpkt)
1891 fcoei_exchange_t *xch = FPKT2XCH(fpkt);
1893 FCOEI_LOG(__FUNCTION__, "internal exchange is completed: %p", xch);
1895 (void) fcoei_un_init_pkt(xch->xch_ss, xch->xch_fpkt);
1896 kmem_free(xch->xch_fpkt->pkt_cmd, xch->xch_fpkt->pkt_cmdlen);
1897 kmem_free(xch->xch_fpkt->pkt_resp, xch->xch_fpkt->pkt_rsplen);
1898 kmem_free(xch->xch_fpkt, sizeof (fc_packet_t));
1899 kmem_free(xch, sizeof (fcoei_exchange_t));
1903 * fcoei_xch_abort
1904 * Prepare to abort the exchange
1906 * Input:
1907 * key = oxid/rxid of the exchange
1908 * val = the exchange
1909 * arg = the soft state
1911 * Returns:
1912 * MH_WALK_CONTINUE = continue to walk
1914 * Comments:
1915 * N/A
1917 /* ARGSUSED */
1918 static uint32_t
1919 fcoei_xch_abort(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1921 fcoei_exchange_t *xch = (fcoei_exchange_t *)val;
1923 ASSERT(arg == xch->xch_ss);
1924 ASSERT(CMHK(key) != 0xFFFF);
1925 xch->xch_flags |= XCH_FLAG_ABORT;
1926 xch->xch_fpkt->pkt_state = FC_PKT_LOCAL_RJT;
1927 xch->xch_fpkt->pkt_reason = FC_REASON_OFFLINE;
1928 list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
1929 return (MH_WALK_CONTINUE);
1933 * fcoei_init_fcatran_vectors
1934 * Initialize fc_fca_tran vectors that are defined in this file
1936 * Input:
1937 * fcatran - fc_fca_tran of the soft state
1939 * Returns:
1940 * N/A
1942 * Comments:
1943 * N/A
1945 void
1946 fcoei_init_fcatran_vectors(fc_fca_tran_t *fcatran)
1948 fcatran->fca_bind_port = fcoei_bind_port;
1949 fcatran->fca_unbind_port = fcoei_unbind_port;
1950 fcatran->fca_init_pkt = fcoei_init_pkt;
1951 fcatran->fca_un_init_pkt = fcoei_un_init_pkt;
1952 fcatran->fca_els_send = fcoei_els_send;
1953 fcatran->fca_get_cap = fcoei_get_cap;
1954 fcatran->fca_set_cap = fcoei_set_cap;
1955 fcatran->fca_getmap = fcoei_getmap;
1956 fcatran->fca_transport = fcoei_transport;
1957 fcatran->fca_ub_alloc = fcoei_ub_alloc;
1958 fcatran->fca_ub_free = fcoei_ub_free;
1959 fcatran->fca_ub_release = fcoei_ub_release;
1960 fcatran->fca_abort = fcoei_abort;
1961 fcatran->fca_reset = fcoei_reset;
1962 fcatran->fca_port_manage = fcoei_port_manage;
1963 fcatran->fca_get_device = fcoei_get_device;
1964 fcatran->fca_notify = fcoei_notify;
1968 * fcoei_process_event_reset
1969 * link reset phase II
1971 * Input:
1972 * arg - fcoei soft state set in fcoei_bind_port
1974 * Returns:
1975 * N/A
1977 * Comments:
1980 void
1981 fcoei_process_event_reset(fcoei_event_t *ae)
1983 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)ae->ae_obj;
1985 ASSERT(!MUTEX_HELD(&ss->ss_watchdog_mutex));
1986 kmem_free(ae, sizeof (*ae));
1988 mod_hash_walk(ss->ss_sol_oxid_hash, fcoei_xch_abort, ss);
1989 mod_hash_walk(ss->ss_unsol_rxid_hash, fcoei_xch_abort, ss);
1990 fcoei_handle_comp_xch_list(ss);
1993 * Notify LV that the link is up now
1995 ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0);
1999 * fcoei_process_event_exchange
2000 * Process exchange in the single thread context
2002 * Input:
2003 * ae = the exchange event
2005 * Returns:
2006 * N/A
2008 * Comments:
2009 * N/A
2011 void
2012 fcoei_process_event_exchange(fcoei_event_t *ae)
2014 fcoei_exchange_t *xch = (fcoei_exchange_t *)ae->ae_obj;
2015 fcoei_exchange_t *xch_tmp;
2016 fc_packet_t *fpkt = xch->xch_fpkt;
2019 * These 4 elements need reset, pkt_state & pkt_reason will be set
2021 fpkt->pkt_action = 0;
2022 fpkt->pkt_expln = 0;
2023 fpkt->pkt_data_resid = 0;
2024 fpkt->pkt_resp_resid = 0;
2027 * port state sanity checking
2029 if ((xch->xch_ss->ss_link_state != FC_STATE_ONLINE) ||
2030 xch->xch_ss->ss_port_event_counter) {
2032 * LV will retry it after one second
2034 fcoei_complete_xch(xch, NULL, FC_PKT_PORT_OFFLINE,
2035 FC_REASON_OFFLINE);
2036 return;
2039 switch (fpkt->pkt_cmd_fhdr.r_ctl) {
2040 case R_CTL_COMMAND:
2041 FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
2042 fcoei_initiate_fcp_cmd(xch);
2043 break;
2045 case R_CTL_ELS_REQ:
2046 FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
2047 fcoei_initiate_els_req(xch);
2048 break;
2050 case R_CTL_UNSOL_CONTROL:
2051 FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
2052 fcoei_initiate_ct_req(xch);
2053 break;
2055 case R_CTL_ELS_RSP:
2057 * Caution: in leadville, it still uses pkt_cmd_fhdr
2058 * oxid & rxid have been decided when we get unsolicited frames.
2059 * pkt_cmd_fhdr has contained the right oxid and rxid now.
2061 FCOEI_INIT_UNSOL_ID_HASH(xch);
2062 fcoei_initiate_els_resp(xch);
2063 break;
2065 default:
2066 fcoei_complete_xch(xch, NULL, FC_PKT_FAILURE,
2067 FC_REASON_CMD_UNSUPPORTED);