static int fcoet_process_sol_abts_rjt(fcoe_frame_t *frm) { fcoet_exchange_t *xch = NULL; uint16_t sol_oxid; sol_oxid = FRM_OXID(frm); if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash, (mod_hash_key_t)(intptr_t)sol_oxid, (mod_hash_val_t *)&xch) != 0) { /* * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash * in fcoet_watch_handle_sol_flogi, Will improve it later */ return (FCOE_SUCCESS); } xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; if (!FRM_IS_LAST_FRAME(frm)) { FCOET_LOG("fcoet_process_sol_abts_rjt", "not supported this kind frame"); return (FCOE_FAILURE); } FCOET_LOG("fcoet_process_sol_abts_rjt", "ABTS_RJT received rjt reason %x but there is nothing to do", frm->frm_payload[1]); return (FCOE_SUCCESS); }
/* * Solicited frames callback area */ static int fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm) { fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; fct_status_t fc_st; uint32_t iof; FCOET_EXT_LOG("fcoet_send_unsol_els_rsp_done", "frm/oxid/els: %p/%x/%x", frm, FRM_OXID(frm), XCH2ELS(xch)->els_req_payload[0]); if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { FCOET_RELE_XCHG(xch); return (FCOE_SUCCESS); } if (fcoet_clear_unsol_exchange(xch) == FCOE_FAILURE) { FCOET_RELE_XCHG(xch); return (FCOE_SUCCESS); } FCOET_RELE_XCHG(xch); if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) { fc_st = FCT_SUCCESS; iof = FCT_IOF_FCA_DONE; fct_send_response_done(xch->xch_cmd, fc_st, iof); } else { /* * We need update ss_link_info and flags. */ mutex_enter(&xch->xch_ss->ss_watch_mutex); xch->xch_ss->ss_link_info.portid = xch->xch_cmd->cmd_lportid; xch->xch_ss->ss_link_info.port_topology = PORT_TOPOLOGY_PT_TO_PT; if (frm->frm_eport->eport_link_speed == FCOE_PORT_SPEED_1G) { xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_1G; } else if (frm->frm_eport->eport_link_speed == FCOE_PORT_SPEED_10G) { xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G; } xch->xch_ss->ss_link_info.port_no_fct_flogi = 1; xch->xch_ss->ss_link_info.port_fca_flogi_done = 1; xch->xch_ss->ss_link_info.port_fct_flogi_done = 0; bcopy(XCH2ELS(xch)->els_req_payload + 20, xch->xch_ss->ss_link_info.port_rpwwn, 8); bcopy(XCH2ELS(xch)->els_req_payload + 28, xch->xch_ss->ss_link_info.port_rnwwn, 8); atomic_or_32(&xch->xch_ss->ss_flags, SS_FLAG_UNSOL_FLOGI_DONE); atomic_or_32(&xch->xch_ss->ss_flags, SS_FLAG_REPORT_TO_FCT); xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC; mutex_exit(&xch->xch_ss->ss_watch_mutex); fct_free(xch->xch_cmd); } return (FCOE_SUCCESS); }
/* * It's still in the context of being aborted exchange, but FCT can't support * this scheme, so there are two fct_cmd_t that are bound with one exchange. */ static int fcoet_process_unsol_abts_req(fcoe_frame_t *frm) { fct_cmd_t *cmd; fcoet_exchange_t *xch = NULL; uint16_t unsol_rxid; FCOET_LOG("fcoet_process_unsol_abts_req", "ABTS: %x/%x", FRM_OXID(frm), FRM_RXID(frm)); unsol_rxid = FRM_RXID(frm); if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash, (mod_hash_key_t)(intptr_t)unsol_rxid, (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) { FCOET_LOG("fcoet_process_unsol_abts_req", "can't find aborted exchange"); return (FCOE_SUCCESS); } fcoet_init_tfm(frm, xch); if (!FRM_IS_LAST_FRAME(frm)) { FCOET_LOG("fcoet_process_unsol_abts_req", "not supported this kind frame"); FCOET_RELE_XCHG(xch); return (FCOE_FAILURE); } cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS, 0, 0); if (cmd == NULL) { FCOET_LOG("fcoet_process_unsol_abts_req", "can't alloc fct_cmd_t"); FCOET_RELE_XCHG(xch); return (FCOE_FAILURE); } xch->xch_flags |= XCH_FLAG_INI_ASKED_ABORT; cmd->cmd_fca_private = xch; cmd->cmd_port = xch->xch_cmd->cmd_port; cmd->cmd_rp_handle = xch->xch_cmd->cmd_rp_handle; cmd->cmd_rportid = xch->xch_cmd->cmd_rportid; cmd->cmd_lportid = xch->xch_cmd->cmd_lportid; cmd->cmd_oxid = xch->xch_cmd->cmd_oxid; cmd->cmd_rxid = xch->xch_cmd->cmd_rxid; fct_post_rcvd_cmd(cmd, NULL); FCOET_LOG("fcoet_process_unsol_abts_req", "abts now: xch/%p, frm/%p - time/%p", xch, frm, ddi_get_lbolt()); FCOET_RELE_XCHG(xch); return (FCOE_SUCCESS); }
void fcoe_post_frame(fcoe_frame_t *frm) { fcoe_worker_t *w; uint16_t oxid = FRM_OXID(frm); w = &fcoe_workers[oxid % fcoe_nworkers_running]; mutex_enter(&w->worker_lock); list_insert_tail(&w->worker_frm_list, frm->frm_fcoe_private); w->worker_ntasks++; if ((w->worker_flags & FCOE_WORKER_ACTIVE) == 0) { cv_signal(&w->worker_cv); } mutex_exit(&w->worker_lock); }
/* * It must be from link, but could be incomplete because of network problems */ static int fcoet_process_sol_els_rsp(fcoe_frame_t *frm) { uint32_t actual_size; fct_status_t fc_st; uint32_t iof; uint16_t sol_oxid; fcoet_exchange_t *xch = NULL; fct_els_t *els = NULL; int ret = FCOE_SUCCESS; sol_oxid = FRM_OXID(frm); if (mod_hash_find_cb(FRM2SS(frm)->ss_sol_oxid_hash, (mod_hash_key_t)(intptr_t)sol_oxid, (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) { return (FCOE_FAILURE); } if (xch != FRM2SS(frm)->ss_sol_flogi) { fcoet_clear_sol_exchange(xch); } fcoet_init_tfm(frm, xch); els = CMD2ELS(xch->xch_cmd); ASSERT(FRM_IS_LAST_FRAME(frm)); actual_size = els->els_resp_size; if (actual_size > frm->frm_payload_size) { actual_size = frm->frm_payload_size; } els->els_resp_size = (uint16_t)actual_size; bcopy(frm->frm_payload, els->els_resp_payload, actual_size); if (xch->xch_ss->ss_sol_flogi == xch) { /* * We handle FLOGI internally */ ret = fcoet_process_sol_flogi_rsp(frm); FCOET_RELE_XCHG(xch); } else { fc_st = FCT_SUCCESS; iof = FCT_IOF_FCA_DONE; FCOET_RELE_XCHG(xch); fct_send_cmd_done(xch->xch_cmd, fc_st, iof); } return (ret); }
static int fcoet_process_sol_ct_rsp(fcoe_frame_t *frm) { uint32_t actual_size; fct_status_t fc_st; uint32_t iof; fct_sol_ct_t *ct = NULL; fcoet_exchange_t *xch = NULL; uint16_t sol_oxid; sol_oxid = FRM_OXID(frm); if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash, (mod_hash_key_t)(intptr_t)sol_oxid, (mod_hash_val_t *)&xch) != 0) { return (FCOE_SUCCESS); } xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; fcoet_init_tfm(frm, xch); ASSERT(FRM_IS_LAST_FRAME(frm)); actual_size = CMD2ELS(xch->xch_cmd)->els_resp_size; if (actual_size > frm->frm_payload_size) { actual_size = frm->frm_payload_size; } ct = CMD2CT(xch->xch_cmd); ct->ct_resp_size = (uint16_t)actual_size; bcopy(frm->frm_payload, CMD2CT(xch->xch_cmd)->ct_resp_payload, actual_size); fc_st = FCT_SUCCESS; iof = FCT_IOF_FCA_DONE; fct_send_cmd_done(xch->xch_cmd, fc_st, iof); return (FCOE_SUCCESS); }
/* * For unsolicited exchanges, FCoET is only responsible for allocation of * req_payload. FCT will allocate resp_payload after the exchange is * passed on. */ static fcoet_exchange_t * fcoet_create_unsol_exchange(fcoe_frame_t *frm) { uint8_t r_ctl; int cdb_size; fcoet_exchange_t *xch, *xch_tmp; fct_cmd_t *cmd; fcoe_fcp_cmnd_t *ffc; uint32_t task_expected_len = 0; r_ctl = FRM_R_CTL(frm); switch (r_ctl) { case 0x22: /* * FCoET's unsolicited ELS */ cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS, GET_STRUCT_SIZE(fcoet_exchange_t) + frm->frm_payload_size, 0); if (cmd == NULL) { FCOET_EXT_LOG(0, "can't get cmd"); return (NULL); } break; case 0x06: /* * FCoET's unsolicited SCSI cmd */ cdb_size = 16; /* need improve later */ cmd = fct_scsi_task_alloc(FRM2SS(frm)->ss_port, FCT_HANDLE_NONE, FRM_S_ID(frm), frm->frm_payload, cdb_size, STMF_TASK_EXT_NONE); if (cmd == NULL) { FCOET_EXT_LOG(0, "can't get fcp cmd"); return (NULL); } ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload; task_expected_len = FCOE_B2V_4(ffc->ffc_fcp_dl); break; default: FCOET_EXT_LOG(0, "unsupported R_CTL: %x", r_ctl); return (NULL); } /* * xch initialization */ xch = CMD2XCH(cmd); xch->xch_oxid = FRM_OXID(frm); xch->xch_flags = 0; xch->xch_ss = FRM2SS(frm); xch->xch_cmd = cmd; xch->xch_current_seq = NULL; xch->xch_left_data_size = 0; if (task_expected_len) { xch->xch_dbuf_num = (task_expected_len + FCOET_MAX_DBUF_LEN - 1) / FCOET_MAX_DBUF_LEN; xch->xch_dbufs = kmem_zalloc(xch->xch_dbuf_num * sizeof (stmf_data_buf_t *), KM_SLEEP); } xch->xch_start_time = ddi_get_lbolt(); do { xch->xch_rxid = atomic_add_16_nv( &xch->xch_ss->ss_next_unsol_rxid, 1); if (xch->xch_rxid == 0xFFFF) { xch->xch_rxid = atomic_add_16_nv( &xch->xch_ss->ss_next_unsol_rxid, 1); } } while (mod_hash_find(FRM2SS(frm)->ss_unsol_rxid_hash, (mod_hash_key_t)(intptr_t)xch->xch_rxid, (mod_hash_val_t)&xch_tmp) == 0); xch->xch_sequence_no = 0; xch->xch_ref = 0; (void) mod_hash_insert(xch->xch_ss->ss_unsol_rxid_hash, (mod_hash_key_t)(intptr_t)xch->xch_rxid, (mod_hash_val_t)xch); xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; /* * cmd initialization */ cmd->cmd_port = FRM2SS(frm)->ss_port; cmd->cmd_rp_handle = FCT_HANDLE_NONE; cmd->cmd_rportid = FRM_S_ID(frm); cmd->cmd_lportid = FRM_D_ID(frm); cmd->cmd_oxid = xch->xch_oxid; cmd->cmd_rxid = xch->xch_rxid; fcoet_init_tfm(frm, xch); return (xch); }