17978SPeter.Dunlap@Sun.COM /* 27978SPeter.Dunlap@Sun.COM * CDDL HEADER START 37978SPeter.Dunlap@Sun.COM * 47978SPeter.Dunlap@Sun.COM * The contents of this file are subject to the terms of the 57978SPeter.Dunlap@Sun.COM * Common Development and Distribution License (the "License"). 67978SPeter.Dunlap@Sun.COM * You may not use this file except in compliance with the License. 77978SPeter.Dunlap@Sun.COM * 87978SPeter.Dunlap@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97978SPeter.Dunlap@Sun.COM * or http://www.opensolaris.org/os/licensing. 107978SPeter.Dunlap@Sun.COM * See the License for the specific language governing permissions 117978SPeter.Dunlap@Sun.COM * and limitations under the License. 127978SPeter.Dunlap@Sun.COM * 137978SPeter.Dunlap@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147978SPeter.Dunlap@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157978SPeter.Dunlap@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167978SPeter.Dunlap@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177978SPeter.Dunlap@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187978SPeter.Dunlap@Sun.COM * 197978SPeter.Dunlap@Sun.COM * CDDL HEADER END 207978SPeter.Dunlap@Sun.COM */ 217978SPeter.Dunlap@Sun.COM 227978SPeter.Dunlap@Sun.COM /* 239162SPeter.Dunlap@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247978SPeter.Dunlap@Sun.COM * Use is subject to license terms. 257978SPeter.Dunlap@Sun.COM */ 267978SPeter.Dunlap@Sun.COM 277978SPeter.Dunlap@Sun.COM #include <sys/conf.h> 287978SPeter.Dunlap@Sun.COM #include <sys/file.h> 297978SPeter.Dunlap@Sun.COM #include <sys/ddi.h> 307978SPeter.Dunlap@Sun.COM #include <sys/sunddi.h> 317978SPeter.Dunlap@Sun.COM #include <sys/cpuvar.h> 32*9721SPriya.Krishnan@Sun.COM #include <sys/sdt.h> 337978SPeter.Dunlap@Sun.COM 347978SPeter.Dunlap@Sun.COM #include <sys/socket.h> 357978SPeter.Dunlap@Sun.COM #include <sys/strsubr.h> 367978SPeter.Dunlap@Sun.COM #include <sys/socketvar.h> 377978SPeter.Dunlap@Sun.COM #include <sys/sysmacros.h> 387978SPeter.Dunlap@Sun.COM 397978SPeter.Dunlap@Sun.COM #include <sys/idm/idm.h> 407978SPeter.Dunlap@Sun.COM #include <sys/idm/idm_so.h> 417978SPeter.Dunlap@Sun.COM 427978SPeter.Dunlap@Sun.COM extern idm_transport_t idm_transport_list[]; 437978SPeter.Dunlap@Sun.COM 447978SPeter.Dunlap@Sun.COM void 457978SPeter.Dunlap@Sun.COM idm_pdu_rx(idm_conn_t *ic, idm_pdu_t *pdu) 467978SPeter.Dunlap@Sun.COM { 477978SPeter.Dunlap@Sun.COM iscsi_async_evt_hdr_t *async_evt; 487978SPeter.Dunlap@Sun.COM 497978SPeter.Dunlap@Sun.COM /* 507978SPeter.Dunlap@Sun.COM * If we are in full-featured mode then route SCSI-related 517978SPeter.Dunlap@Sun.COM * commands to the appropriate function vector 527978SPeter.Dunlap@Sun.COM */ 537978SPeter.Dunlap@Sun.COM ic->ic_timestamp = ddi_get_lbolt(); 547978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 557978SPeter.Dunlap@Sun.COM if (ic->ic_ffp && ic->ic_pdu_events == 0) { 567978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 577978SPeter.Dunlap@Sun.COM 587978SPeter.Dunlap@Sun.COM if (idm_pdu_rx_forward_ffp(ic, pdu) == B_TRUE) { 597978SPeter.Dunlap@Sun.COM /* Forwarded SCSI-related commands */ 607978SPeter.Dunlap@Sun.COM return; 617978SPeter.Dunlap@Sun.COM } 627978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 637978SPeter.Dunlap@Sun.COM } 647978SPeter.Dunlap@Sun.COM 657978SPeter.Dunlap@Sun.COM /* 667978SPeter.Dunlap@Sun.COM * If we get here with a SCSI-related PDU then we are not in 677978SPeter.Dunlap@Sun.COM * full-feature mode and the PDU is a protocol error (SCSI command 687978SPeter.Dunlap@Sun.COM * PDU's may sometimes be an exception, see below). All 697978SPeter.Dunlap@Sun.COM * non-SCSI PDU's get treated them the same regardless of whether 707978SPeter.Dunlap@Sun.COM * we are in full-feature mode. 717978SPeter.Dunlap@Sun.COM * 727978SPeter.Dunlap@Sun.COM * Look at the opcode and in some cases the PDU status and 737978SPeter.Dunlap@Sun.COM * determine the appropriate event to send to the connection 747978SPeter.Dunlap@Sun.COM * state machine. Generate the event, passing the PDU as data. 757978SPeter.Dunlap@Sun.COM * If the current connection state allows reception of the event 767978SPeter.Dunlap@Sun.COM * the PDU will be submitted to the IDM client for processing, 777978SPeter.Dunlap@Sun.COM * otherwise the PDU will be dropped. 787978SPeter.Dunlap@Sun.COM */ 797978SPeter.Dunlap@Sun.COM switch (IDM_PDU_OPCODE(pdu)) { 807978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_CMD: 81*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(login__command, idm_conn_t *, ic, 82*9721SPriya.Krishnan@Sun.COM iscsi_login_hdr_t *, (iscsi_login_hdr_t *)pdu->isp_hdr); 837978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_LOGIN_RCV, (uintptr_t)pdu); 847978SPeter.Dunlap@Sun.COM break; 857978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_RSP: 867978SPeter.Dunlap@Sun.COM idm_parse_login_rsp(ic, pdu, /* RX */ B_TRUE); 877978SPeter.Dunlap@Sun.COM break; 887978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_CMD: 89*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(logout__command, idm_conn_t *, ic, 90*9721SPriya.Krishnan@Sun.COM iscsi_logout_hdr_t *, 91*9721SPriya.Krishnan@Sun.COM (iscsi_logout_hdr_t *)pdu->isp_hdr); 927978SPeter.Dunlap@Sun.COM idm_parse_logout_req(ic, pdu, /* RX */ B_TRUE); 937978SPeter.Dunlap@Sun.COM break; 947978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_RSP: 957978SPeter.Dunlap@Sun.COM idm_parse_logout_rsp(ic, pdu, /* RX */ B_TRUE); 967978SPeter.Dunlap@Sun.COM break; 977978SPeter.Dunlap@Sun.COM case ISCSI_OP_ASYNC_EVENT: 987978SPeter.Dunlap@Sun.COM async_evt = (iscsi_async_evt_hdr_t *)pdu->isp_hdr; 999162SPeter.Dunlap@Sun.COM switch (async_evt->async_event) { 1007978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT: 1017978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_ASYNC_LOGOUT_RCV, 1027978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 1037978SPeter.Dunlap@Sun.COM break; 1047978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION: 1057978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_ASYNC_DROP_CONN_RCV, 1067978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 1077978SPeter.Dunlap@Sun.COM break; 1087978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS: 1097978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_ASYNC_DROP_ALL_CONN_RCV, 1107978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 1117978SPeter.Dunlap@Sun.COM break; 1127978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_SCSI_EVENT: 1137978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION: 1147978SPeter.Dunlap@Sun.COM default: 1157978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_MISC_RX, 1167978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 1177978SPeter.Dunlap@Sun.COM break; 1187978SPeter.Dunlap@Sun.COM } 1197978SPeter.Dunlap@Sun.COM break; 1207978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_CMD: 1217978SPeter.Dunlap@Sun.COM /* 1227978SPeter.Dunlap@Sun.COM * Consider this scenario: We are a target connection 1237978SPeter.Dunlap@Sun.COM * in "in login" state and a "login success sent" event has 1247978SPeter.Dunlap@Sun.COM * been generated but not yet handled. Since we've sent 1257978SPeter.Dunlap@Sun.COM * the login response but we haven't actually transitioned 1267978SPeter.Dunlap@Sun.COM * to FFP mode we might conceivably receive a SCSI command 1277978SPeter.Dunlap@Sun.COM * from the initiator before we are ready. We are actually 1287978SPeter.Dunlap@Sun.COM * in FFP we just don't know it yet -- to address this we 1297978SPeter.Dunlap@Sun.COM * can generate an event corresponding to the SCSI command. 1307978SPeter.Dunlap@Sun.COM * At the point when the event is handled by the state 1317978SPeter.Dunlap@Sun.COM * machine the login request will have been handled and we 1327978SPeter.Dunlap@Sun.COM * should be in FFP. If we are not in FFP by that time 1337978SPeter.Dunlap@Sun.COM * we can reject the SCSI command with a protocol error. 1347978SPeter.Dunlap@Sun.COM * 1357978SPeter.Dunlap@Sun.COM * This scenario only applies to the target. 136*9721SPriya.Krishnan@Sun.COM * 137*9721SPriya.Krishnan@Sun.COM * Handle dtrace probe in iscsit so we can find all the 138*9721SPriya.Krishnan@Sun.COM * pieces of the CDB 1397978SPeter.Dunlap@Sun.COM */ 140*9721SPriya.Krishnan@Sun.COM idm_conn_rx_pdu_event(ic, CE_MISC_RX, (uintptr_t)pdu); 141*9721SPriya.Krishnan@Sun.COM break; 1427978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA: 143*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(data__receive, idm_conn_t *, ic, 144*9721SPriya.Krishnan@Sun.COM iscsi_data_hdr_t *, 145*9721SPriya.Krishnan@Sun.COM (iscsi_data_hdr_t *)pdu->isp_hdr); 146*9721SPriya.Krishnan@Sun.COM idm_conn_rx_pdu_event(ic, CE_MISC_RX, (uintptr_t)pdu); 147*9721SPriya.Krishnan@Sun.COM break; 148*9721SPriya.Krishnan@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_MSG: 149*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(task__command, idm_conn_t *, ic, 150*9721SPriya.Krishnan@Sun.COM iscsi_scsi_task_mgt_hdr_t *, 151*9721SPriya.Krishnan@Sun.COM (iscsi_scsi_task_mgt_hdr_t *)pdu->isp_hdr); 152*9721SPriya.Krishnan@Sun.COM idm_conn_rx_pdu_event(ic, CE_MISC_RX, (uintptr_t)pdu); 153*9721SPriya.Krishnan@Sun.COM break; 154*9721SPriya.Krishnan@Sun.COM case ISCSI_OP_NOOP_OUT: 155*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(nop__receive, idm_conn_t *, ic, 156*9721SPriya.Krishnan@Sun.COM iscsi_nop_out_hdr_t *, 157*9721SPriya.Krishnan@Sun.COM (iscsi_nop_out_hdr_t *)pdu->isp_hdr); 158*9721SPriya.Krishnan@Sun.COM idm_conn_rx_pdu_event(ic, CE_MISC_RX, (uintptr_t)pdu); 159*9721SPriya.Krishnan@Sun.COM break; 160*9721SPriya.Krishnan@Sun.COM case ISCSI_OP_TEXT_CMD: 161*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(text__command, idm_conn_t *, ic, 162*9721SPriya.Krishnan@Sun.COM iscsi_text_hdr_t *, 163*9721SPriya.Krishnan@Sun.COM (iscsi_text_hdr_t *)pdu->isp_hdr); 164*9721SPriya.Krishnan@Sun.COM idm_conn_rx_pdu_event(ic, CE_MISC_RX, (uintptr_t)pdu); 165*9721SPriya.Krishnan@Sun.COM break; 166*9721SPriya.Krishnan@Sun.COM /* Initiator PDU's */ 1677978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA_RSP: 1687978SPeter.Dunlap@Sun.COM case ISCSI_OP_RTT_RSP: 1697978SPeter.Dunlap@Sun.COM case ISCSI_OP_SNACK_CMD: 1707978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_IN: 1717978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_RSP: 1727978SPeter.Dunlap@Sun.COM case ISCSI_OP_REJECT_MSG: 1737978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_RSP: 1747978SPeter.Dunlap@Sun.COM /* Validate received PDU against current state */ 1757978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_MISC_RX, 1767978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 1777978SPeter.Dunlap@Sun.COM break; 1787978SPeter.Dunlap@Sun.COM } 1797978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 1807978SPeter.Dunlap@Sun.COM } 1817978SPeter.Dunlap@Sun.COM 1827978SPeter.Dunlap@Sun.COM void 1837978SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(idm_conn_t *ic, idm_pdu_t *pdu) 1847978SPeter.Dunlap@Sun.COM { 1857978SPeter.Dunlap@Sun.COM (*ic->ic_transport_ops->it_tx_pdu)(ic, pdu); 1867978SPeter.Dunlap@Sun.COM } 1877978SPeter.Dunlap@Sun.COM 1887978SPeter.Dunlap@Sun.COM boolean_t 1897978SPeter.Dunlap@Sun.COM idm_pdu_rx_forward_ffp(idm_conn_t *ic, idm_pdu_t *pdu) 1907978SPeter.Dunlap@Sun.COM { 1917978SPeter.Dunlap@Sun.COM /* 1927978SPeter.Dunlap@Sun.COM * If this is an FFP request, call the appropriate handler 1937978SPeter.Dunlap@Sun.COM * and return B_TRUE, otherwise return B_FALSE. 1947978SPeter.Dunlap@Sun.COM */ 1957978SPeter.Dunlap@Sun.COM switch (IDM_PDU_OPCODE(pdu)) { 1967978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_CMD: 1977978SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_rx_scsi_cmd)(ic, pdu); 1987978SPeter.Dunlap@Sun.COM return (B_TRUE); 199*9721SPriya.Krishnan@Sun.COM case ISCSI_OP_SCSI_DATA: 200*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(data__receive, idm_conn_t *, ic, 201*9721SPriya.Krishnan@Sun.COM iscsi_data_hdr_t *, 202*9721SPriya.Krishnan@Sun.COM (iscsi_data_hdr_t *)pdu->isp_hdr); 203*9721SPriya.Krishnan@Sun.COM (*ic->ic_transport_ops->it_rx_dataout)(ic, pdu); 204*9721SPriya.Krishnan@Sun.COM return (B_TRUE); 205*9721SPriya.Krishnan@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_MSG: 206*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(task__command, idm_conn_t *, ic, 207*9721SPriya.Krishnan@Sun.COM iscsi_scsi_task_mgt_hdr_t *, 208*9721SPriya.Krishnan@Sun.COM (iscsi_scsi_task_mgt_hdr_t *)pdu->isp_hdr); 209*9721SPriya.Krishnan@Sun.COM (*ic->ic_conn_ops.icb_rx_misc)(ic, pdu); 210*9721SPriya.Krishnan@Sun.COM return (B_TRUE); 211*9721SPriya.Krishnan@Sun.COM case ISCSI_OP_NOOP_OUT: 212*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(nop__receive, idm_conn_t *, ic, 213*9721SPriya.Krishnan@Sun.COM iscsi_nop_out_hdr_t *, 214*9721SPriya.Krishnan@Sun.COM (iscsi_nop_out_hdr_t *)pdu->isp_hdr); 215*9721SPriya.Krishnan@Sun.COM (*ic->ic_conn_ops.icb_rx_misc)(ic, pdu); 216*9721SPriya.Krishnan@Sun.COM return (B_TRUE); 217*9721SPriya.Krishnan@Sun.COM case ISCSI_OP_TEXT_CMD: 218*9721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(text__command, idm_conn_t *, ic, 219*9721SPriya.Krishnan@Sun.COM iscsi_text_hdr_t *, 220*9721SPriya.Krishnan@Sun.COM (iscsi_text_hdr_t *)pdu->isp_hdr); 221*9721SPriya.Krishnan@Sun.COM (*ic->ic_conn_ops.icb_rx_misc)(ic, pdu); 222*9721SPriya.Krishnan@Sun.COM return (B_TRUE); 223*9721SPriya.Krishnan@Sun.COM /* Initiator only */ 2247978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_RSP: 2257978SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_rx_scsi_rsp)(ic, pdu); 2267978SPeter.Dunlap@Sun.COM return (B_TRUE); 2277978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA_RSP: 2287978SPeter.Dunlap@Sun.COM (*ic->ic_transport_ops->it_rx_datain)(ic, pdu); 2297978SPeter.Dunlap@Sun.COM return (B_TRUE); 2307978SPeter.Dunlap@Sun.COM case ISCSI_OP_RTT_RSP: 2317978SPeter.Dunlap@Sun.COM (*ic->ic_transport_ops->it_rx_rtt)(ic, pdu); 2327978SPeter.Dunlap@Sun.COM return (B_TRUE); 2337978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_RSP: 2347978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_RSP: 2357978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_IN: 2367978SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_rx_misc)(ic, pdu); 2377978SPeter.Dunlap@Sun.COM return (B_TRUE); 2387978SPeter.Dunlap@Sun.COM default: 2397978SPeter.Dunlap@Sun.COM return (B_FALSE); 2407978SPeter.Dunlap@Sun.COM } 2417978SPeter.Dunlap@Sun.COM /*NOTREACHED*/ 2427978SPeter.Dunlap@Sun.COM } 2437978SPeter.Dunlap@Sun.COM 2447978SPeter.Dunlap@Sun.COM void 2457978SPeter.Dunlap@Sun.COM idm_pdu_rx_forward(idm_conn_t *ic, idm_pdu_t *pdu) 2467978SPeter.Dunlap@Sun.COM { 2477978SPeter.Dunlap@Sun.COM /* 2487978SPeter.Dunlap@Sun.COM * Some PDU's specific to FFP get special handling. This function 2497978SPeter.Dunlap@Sun.COM * will normally never be called in FFP with an FFP PDU since this 2507978SPeter.Dunlap@Sun.COM * is a slow path but in can happen on the target side during 2517978SPeter.Dunlap@Sun.COM * the transition to FFP. We primarily call 2527978SPeter.Dunlap@Sun.COM * idm_pdu_rx_forward_ffp here to avoid code duplication. 2537978SPeter.Dunlap@Sun.COM */ 2547978SPeter.Dunlap@Sun.COM if (idm_pdu_rx_forward_ffp(ic, pdu) == B_FALSE) { 2557978SPeter.Dunlap@Sun.COM /* 2567978SPeter.Dunlap@Sun.COM * Non-FFP PDU, use generic RC handler 2577978SPeter.Dunlap@Sun.COM */ 2587978SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_rx_misc)(ic, pdu); 2597978SPeter.Dunlap@Sun.COM } 2607978SPeter.Dunlap@Sun.COM } 2617978SPeter.Dunlap@Sun.COM 2627978SPeter.Dunlap@Sun.COM void 2637978SPeter.Dunlap@Sun.COM idm_parse_login_rsp(idm_conn_t *ic, idm_pdu_t *login_rsp_pdu, boolean_t rx) 2647978SPeter.Dunlap@Sun.COM { 2657978SPeter.Dunlap@Sun.COM iscsi_login_rsp_hdr_t *login_rsp = 2667978SPeter.Dunlap@Sun.COM (iscsi_login_rsp_hdr_t *)login_rsp_pdu->isp_hdr; 2677978SPeter.Dunlap@Sun.COM idm_conn_event_t new_event; 2687978SPeter.Dunlap@Sun.COM 2697978SPeter.Dunlap@Sun.COM if (login_rsp->status_class == ISCSI_STATUS_CLASS_SUCCESS) { 2707978SPeter.Dunlap@Sun.COM if (!(login_rsp->flags & ISCSI_FLAG_LOGIN_CONTINUE) && 2717978SPeter.Dunlap@Sun.COM (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) && 2727978SPeter.Dunlap@Sun.COM (ISCSI_LOGIN_NEXT_STAGE(login_rsp->flags) == 2737978SPeter.Dunlap@Sun.COM ISCSI_FULL_FEATURE_PHASE)) { 2747978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_LOGIN_SUCCESS_RCV : 2757978SPeter.Dunlap@Sun.COM CE_LOGIN_SUCCESS_SND); 2767978SPeter.Dunlap@Sun.COM } else { 2777978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_MISC_RX : CE_MISC_TX); 2787978SPeter.Dunlap@Sun.COM } 2797978SPeter.Dunlap@Sun.COM } else { 2807978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_LOGIN_FAIL_RCV : CE_LOGIN_FAIL_SND); 2817978SPeter.Dunlap@Sun.COM } 2827978SPeter.Dunlap@Sun.COM 2837978SPeter.Dunlap@Sun.COM if (rx) { 2847978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, new_event, (uintptr_t)login_rsp_pdu); 2857978SPeter.Dunlap@Sun.COM } else { 2867978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, new_event, (uintptr_t)login_rsp_pdu); 2877978SPeter.Dunlap@Sun.COM } 2887978SPeter.Dunlap@Sun.COM } 2897978SPeter.Dunlap@Sun.COM 2907978SPeter.Dunlap@Sun.COM 2917978SPeter.Dunlap@Sun.COM void 2927978SPeter.Dunlap@Sun.COM idm_parse_logout_req(idm_conn_t *ic, idm_pdu_t *logout_req_pdu, boolean_t rx) 2937978SPeter.Dunlap@Sun.COM { 2947978SPeter.Dunlap@Sun.COM iscsi_logout_hdr_t *logout_req = 2957978SPeter.Dunlap@Sun.COM (iscsi_logout_hdr_t *)logout_req_pdu->isp_hdr; 2967978SPeter.Dunlap@Sun.COM idm_conn_event_t new_event; 2977978SPeter.Dunlap@Sun.COM uint8_t reason = 2987978SPeter.Dunlap@Sun.COM (logout_req->flags & ISCSI_FLAG_LOGOUT_REASON_MASK); 2997978SPeter.Dunlap@Sun.COM 3007978SPeter.Dunlap@Sun.COM /* 3017978SPeter.Dunlap@Sun.COM * For a normal logout (close connection or close session) IDM 3027978SPeter.Dunlap@Sun.COM * will terminate processing of all tasks completing the tasks 3037978SPeter.Dunlap@Sun.COM * back to the client with a status indicating the connection 3047978SPeter.Dunlap@Sun.COM * was logged out. These tasks do not get completed. 3057978SPeter.Dunlap@Sun.COM * 3067978SPeter.Dunlap@Sun.COM * For a "close connection for recovery logout) IDM suspends 3077978SPeter.Dunlap@Sun.COM * processing of all tasks and completes them back to the client 3087978SPeter.Dunlap@Sun.COM * with a status indicating connection was logged out for 3097978SPeter.Dunlap@Sun.COM * recovery. Both initiator and target hang onto these tasks. 3107978SPeter.Dunlap@Sun.COM * When we add ERL2 support IDM will need to provide mechanisms 3117978SPeter.Dunlap@Sun.COM * to change the task and buffer associations to a new connection. 3127978SPeter.Dunlap@Sun.COM * 3137978SPeter.Dunlap@Sun.COM * This code doesn't address the possibility of MC/S. We'll 3147978SPeter.Dunlap@Sun.COM * need to decide how the separate connections get handled 3157978SPeter.Dunlap@Sun.COM * in that case. One simple option is to make the client 3167978SPeter.Dunlap@Sun.COM * generate the events for the other connections. 3177978SPeter.Dunlap@Sun.COM */ 3187978SPeter.Dunlap@Sun.COM if (reason == ISCSI_LOGOUT_REASON_CLOSE_SESSION) { 3197978SPeter.Dunlap@Sun.COM new_event = 3207978SPeter.Dunlap@Sun.COM (rx ? CE_LOGOUT_SESSION_RCV : CE_LOGOUT_SESSION_SND); 3217978SPeter.Dunlap@Sun.COM } else if ((reason == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION) || 3227978SPeter.Dunlap@Sun.COM (reason == ISCSI_LOGOUT_REASON_RECOVERY)) { 3237978SPeter.Dunlap@Sun.COM /* Check logout CID against this connection's CID */ 3247978SPeter.Dunlap@Sun.COM if (ntohs(logout_req->cid) == ic->ic_login_cid) { 3257978SPeter.Dunlap@Sun.COM /* Logout is for this connection */ 3267978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_LOGOUT_THIS_CONN_RCV : 3277978SPeter.Dunlap@Sun.COM CE_LOGOUT_THIS_CONN_SND); 3287978SPeter.Dunlap@Sun.COM } else { 3297978SPeter.Dunlap@Sun.COM /* 3307978SPeter.Dunlap@Sun.COM * Logout affects another connection. This is not 3317978SPeter.Dunlap@Sun.COM * a relevant event for this connection so we'll 3327978SPeter.Dunlap@Sun.COM * just treat it as a normal PDU event. Client 3337978SPeter.Dunlap@Sun.COM * will need to lookup the other connection and 3347978SPeter.Dunlap@Sun.COM * generate the event. 3357978SPeter.Dunlap@Sun.COM */ 3367978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_MISC_RX : CE_MISC_TX); 3377978SPeter.Dunlap@Sun.COM } 3387978SPeter.Dunlap@Sun.COM } else { 3397978SPeter.Dunlap@Sun.COM /* Invalid reason code */ 3407978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_RX_PROTOCOL_ERROR : CE_TX_PROTOCOL_ERROR); 3417978SPeter.Dunlap@Sun.COM } 3427978SPeter.Dunlap@Sun.COM 3437978SPeter.Dunlap@Sun.COM if (rx) { 3447978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, new_event, (uintptr_t)logout_req_pdu); 3457978SPeter.Dunlap@Sun.COM } else { 3467978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, new_event, (uintptr_t)logout_req_pdu); 3477978SPeter.Dunlap@Sun.COM } 3487978SPeter.Dunlap@Sun.COM } 3497978SPeter.Dunlap@Sun.COM 3507978SPeter.Dunlap@Sun.COM 3517978SPeter.Dunlap@Sun.COM 3527978SPeter.Dunlap@Sun.COM void 3537978SPeter.Dunlap@Sun.COM idm_parse_logout_rsp(idm_conn_t *ic, idm_pdu_t *logout_rsp_pdu, boolean_t rx) 3547978SPeter.Dunlap@Sun.COM { 3557978SPeter.Dunlap@Sun.COM idm_conn_event_t new_event; 3567978SPeter.Dunlap@Sun.COM iscsi_logout_rsp_hdr_t *logout_rsp = 3577978SPeter.Dunlap@Sun.COM (iscsi_logout_rsp_hdr_t *)logout_rsp_pdu->isp_hdr; 3587978SPeter.Dunlap@Sun.COM 3597978SPeter.Dunlap@Sun.COM if (logout_rsp->response == ISCSI_STATUS_CLASS_SUCCESS) { 3607978SPeter.Dunlap@Sun.COM new_event = rx ? CE_LOGOUT_SUCCESS_RCV : CE_LOGOUT_SUCCESS_SND; 3617978SPeter.Dunlap@Sun.COM } else { 3627978SPeter.Dunlap@Sun.COM new_event = rx ? CE_LOGOUT_FAIL_RCV : CE_LOGOUT_FAIL_SND; 3637978SPeter.Dunlap@Sun.COM } 3647978SPeter.Dunlap@Sun.COM 3657978SPeter.Dunlap@Sun.COM if (rx) { 3667978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, new_event, (uintptr_t)logout_rsp_pdu); 3677978SPeter.Dunlap@Sun.COM } else { 3687978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, new_event, (uintptr_t)logout_rsp_pdu); 3697978SPeter.Dunlap@Sun.COM } 3707978SPeter.Dunlap@Sun.COM } 3717978SPeter.Dunlap@Sun.COM 3727978SPeter.Dunlap@Sun.COM /* 3737978SPeter.Dunlap@Sun.COM * idm_svc_conn_create() 3747978SPeter.Dunlap@Sun.COM * Transport-agnostic service connection creation, invoked from the transport 3757978SPeter.Dunlap@Sun.COM * layer. 3767978SPeter.Dunlap@Sun.COM */ 3777978SPeter.Dunlap@Sun.COM idm_status_t 3787978SPeter.Dunlap@Sun.COM idm_svc_conn_create(idm_svc_t *is, idm_transport_type_t tt, 3797978SPeter.Dunlap@Sun.COM idm_conn_t **ic_result) 3807978SPeter.Dunlap@Sun.COM { 3817978SPeter.Dunlap@Sun.COM idm_conn_t *ic; 3827978SPeter.Dunlap@Sun.COM idm_status_t rc; 3837978SPeter.Dunlap@Sun.COM 3849162SPeter.Dunlap@Sun.COM mutex_enter(&is->is_mutex); 3859162SPeter.Dunlap@Sun.COM if (!is->is_online) { 3869162SPeter.Dunlap@Sun.COM mutex_exit(&is->is_mutex); 3879162SPeter.Dunlap@Sun.COM return (IDM_STATUS_FAIL); 3889162SPeter.Dunlap@Sun.COM } 3899162SPeter.Dunlap@Sun.COM mutex_exit(&is->is_mutex); 3909162SPeter.Dunlap@Sun.COM 3917978SPeter.Dunlap@Sun.COM ic = idm_conn_create_common(CONN_TYPE_TGT, tt, 3927978SPeter.Dunlap@Sun.COM &is->is_svc_req.sr_conn_ops); 3937978SPeter.Dunlap@Sun.COM ic->ic_svc_binding = is; 3947978SPeter.Dunlap@Sun.COM 3957978SPeter.Dunlap@Sun.COM /* 3967978SPeter.Dunlap@Sun.COM * Prepare connection state machine 3977978SPeter.Dunlap@Sun.COM */ 3987978SPeter.Dunlap@Sun.COM if ((rc = idm_conn_sm_init(ic)) != 0) { 3997978SPeter.Dunlap@Sun.COM idm_conn_destroy_common(ic); 4007978SPeter.Dunlap@Sun.COM return (rc); 4017978SPeter.Dunlap@Sun.COM } 4027978SPeter.Dunlap@Sun.COM 4037978SPeter.Dunlap@Sun.COM 4047978SPeter.Dunlap@Sun.COM *ic_result = ic; 4057978SPeter.Dunlap@Sun.COM 4067978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 4077978SPeter.Dunlap@Sun.COM list_insert_tail(&idm.idm_tgt_conn_list, ic); 4087978SPeter.Dunlap@Sun.COM idm.idm_tgt_conn_count++; 4097978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 4107978SPeter.Dunlap@Sun.COM 4119162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS); 4127978SPeter.Dunlap@Sun.COM } 4137978SPeter.Dunlap@Sun.COM 4147978SPeter.Dunlap@Sun.COM void 4157978SPeter.Dunlap@Sun.COM idm_svc_conn_destroy(idm_conn_t *ic) 4167978SPeter.Dunlap@Sun.COM { 4177978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 4187978SPeter.Dunlap@Sun.COM list_remove(&idm.idm_tgt_conn_list, ic); 4197978SPeter.Dunlap@Sun.COM idm.idm_tgt_conn_count--; 4207978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 4217978SPeter.Dunlap@Sun.COM 4227978SPeter.Dunlap@Sun.COM if (ic->ic_transport_private != NULL) { 4237978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_tgt_conn_destroy(ic); 4247978SPeter.Dunlap@Sun.COM } 4257978SPeter.Dunlap@Sun.COM idm_conn_destroy_common(ic); 4267978SPeter.Dunlap@Sun.COM } 4277978SPeter.Dunlap@Sun.COM 4287978SPeter.Dunlap@Sun.COM /* 4297978SPeter.Dunlap@Sun.COM * idm_conn_create_common() 4307978SPeter.Dunlap@Sun.COM * 4317978SPeter.Dunlap@Sun.COM * Allocate and initialize IDM connection context 4327978SPeter.Dunlap@Sun.COM */ 4337978SPeter.Dunlap@Sun.COM idm_conn_t * 4347978SPeter.Dunlap@Sun.COM idm_conn_create_common(idm_conn_type_t conn_type, idm_transport_type_t tt, 4357978SPeter.Dunlap@Sun.COM idm_conn_ops_t *conn_ops) 4367978SPeter.Dunlap@Sun.COM { 4377978SPeter.Dunlap@Sun.COM idm_conn_t *ic; 4387978SPeter.Dunlap@Sun.COM idm_transport_t *it; 4397978SPeter.Dunlap@Sun.COM idm_transport_type_t type; 4407978SPeter.Dunlap@Sun.COM 4417978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 4427978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type]; 4437978SPeter.Dunlap@Sun.COM 4447978SPeter.Dunlap@Sun.COM if ((it->it_ops != NULL) && (it->it_type == tt)) 4457978SPeter.Dunlap@Sun.COM break; 4467978SPeter.Dunlap@Sun.COM } 4477978SPeter.Dunlap@Sun.COM ASSERT(it->it_type == tt); 4487978SPeter.Dunlap@Sun.COM if (it->it_type != tt) 4497978SPeter.Dunlap@Sun.COM return (NULL); 4507978SPeter.Dunlap@Sun.COM 4517978SPeter.Dunlap@Sun.COM ic = kmem_zalloc(sizeof (idm_conn_t), KM_SLEEP); 4527978SPeter.Dunlap@Sun.COM 4537978SPeter.Dunlap@Sun.COM /* Initialize data */ 454*9721SPriya.Krishnan@Sun.COM ic->ic_target_name[0] = '\0'; 455*9721SPriya.Krishnan@Sun.COM ic->ic_initiator_name[0] = '\0'; 456*9721SPriya.Krishnan@Sun.COM ic->ic_isid[0] = '\0'; 457*9721SPriya.Krishnan@Sun.COM ic->ic_tsih[0] = '\0'; 4587978SPeter.Dunlap@Sun.COM ic->ic_conn_type = conn_type; 4597978SPeter.Dunlap@Sun.COM ic->ic_conn_ops = *conn_ops; 4607978SPeter.Dunlap@Sun.COM ic->ic_transport_ops = it->it_ops; 4617978SPeter.Dunlap@Sun.COM ic->ic_transport_type = tt; 4627978SPeter.Dunlap@Sun.COM ic->ic_transport_private = NULL; /* Set by transport service */ 4637978SPeter.Dunlap@Sun.COM ic->ic_internal_cid = idm_cid_alloc(); 4647978SPeter.Dunlap@Sun.COM if (ic->ic_internal_cid == 0) { 4657978SPeter.Dunlap@Sun.COM kmem_free(ic, sizeof (idm_conn_t)); 4667978SPeter.Dunlap@Sun.COM return (NULL); 4677978SPeter.Dunlap@Sun.COM } 4687978SPeter.Dunlap@Sun.COM mutex_init(&ic->ic_mutex, NULL, MUTEX_DEFAULT, NULL); 4697978SPeter.Dunlap@Sun.COM cv_init(&ic->ic_cv, NULL, CV_DEFAULT, NULL); 4707978SPeter.Dunlap@Sun.COM idm_refcnt_init(&ic->ic_refcnt, ic); 4717978SPeter.Dunlap@Sun.COM 4727978SPeter.Dunlap@Sun.COM return (ic); 4737978SPeter.Dunlap@Sun.COM } 4747978SPeter.Dunlap@Sun.COM 4757978SPeter.Dunlap@Sun.COM void 4767978SPeter.Dunlap@Sun.COM idm_conn_destroy_common(idm_conn_t *ic) 4777978SPeter.Dunlap@Sun.COM { 4789162SPeter.Dunlap@Sun.COM idm_conn_sm_fini(ic); 4797978SPeter.Dunlap@Sun.COM idm_refcnt_destroy(&ic->ic_refcnt); 4807978SPeter.Dunlap@Sun.COM cv_destroy(&ic->ic_cv); 4817978SPeter.Dunlap@Sun.COM mutex_destroy(&ic->ic_mutex); 4827978SPeter.Dunlap@Sun.COM idm_cid_free(ic->ic_internal_cid); 4837978SPeter.Dunlap@Sun.COM 4847978SPeter.Dunlap@Sun.COM kmem_free(ic, sizeof (idm_conn_t)); 4857978SPeter.Dunlap@Sun.COM } 4867978SPeter.Dunlap@Sun.COM 4877978SPeter.Dunlap@Sun.COM /* 4887978SPeter.Dunlap@Sun.COM * Invoked from the SM as a result of client's invocation of 4897978SPeter.Dunlap@Sun.COM * idm_ini_conn_connect() 4907978SPeter.Dunlap@Sun.COM */ 4917978SPeter.Dunlap@Sun.COM idm_status_t 4927978SPeter.Dunlap@Sun.COM idm_ini_conn_finish(idm_conn_t *ic) 4937978SPeter.Dunlap@Sun.COM { 4947978SPeter.Dunlap@Sun.COM /* invoke transport-specific connection */ 4957978SPeter.Dunlap@Sun.COM return (ic->ic_transport_ops->it_ini_conn_connect(ic)); 4967978SPeter.Dunlap@Sun.COM } 4977978SPeter.Dunlap@Sun.COM 4987978SPeter.Dunlap@Sun.COM idm_status_t 4997978SPeter.Dunlap@Sun.COM idm_tgt_conn_finish(idm_conn_t *ic) 5007978SPeter.Dunlap@Sun.COM { 5017978SPeter.Dunlap@Sun.COM idm_status_t rc; 5027978SPeter.Dunlap@Sun.COM 5037978SPeter.Dunlap@Sun.COM rc = idm_notify_client(ic, CN_CONNECT_ACCEPT, NULL); 5047978SPeter.Dunlap@Sun.COM if (rc != IDM_STATUS_SUCCESS) { 5057978SPeter.Dunlap@Sun.COM return (IDM_STATUS_REJECT); 5067978SPeter.Dunlap@Sun.COM } 5077978SPeter.Dunlap@Sun.COM 5087978SPeter.Dunlap@Sun.COM /* Target client is ready to receive a login, start connection */ 5097978SPeter.Dunlap@Sun.COM return (ic->ic_transport_ops->it_tgt_conn_connect(ic)); 5107978SPeter.Dunlap@Sun.COM } 5117978SPeter.Dunlap@Sun.COM 5127978SPeter.Dunlap@Sun.COM idm_transport_t * 5137978SPeter.Dunlap@Sun.COM idm_transport_lookup(idm_conn_req_t *cr) 5147978SPeter.Dunlap@Sun.COM { 5157978SPeter.Dunlap@Sun.COM idm_transport_type_t type; 5167978SPeter.Dunlap@Sun.COM idm_transport_t *it; 5177978SPeter.Dunlap@Sun.COM idm_transport_caps_t caps; 5187978SPeter.Dunlap@Sun.COM 5197978SPeter.Dunlap@Sun.COM /* 5207978SPeter.Dunlap@Sun.COM * Make sure all available transports are setup. We call this now 5217978SPeter.Dunlap@Sun.COM * instead of at initialization time in case IB has become available 5227978SPeter.Dunlap@Sun.COM * since we started (hotplug, etc). 5237978SPeter.Dunlap@Sun.COM */ 5247978SPeter.Dunlap@Sun.COM idm_transport_setup(cr->cr_li); 5257978SPeter.Dunlap@Sun.COM 5267978SPeter.Dunlap@Sun.COM /* Determine the transport for this connection */ 5277978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 5287978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type]; 5297978SPeter.Dunlap@Sun.COM 5307978SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) { 5317978SPeter.Dunlap@Sun.COM /* transport is not registered */ 5327978SPeter.Dunlap@Sun.COM continue; 5337978SPeter.Dunlap@Sun.COM } 5347978SPeter.Dunlap@Sun.COM 5357978SPeter.Dunlap@Sun.COM if (it->it_ops->it_conn_is_capable(cr, &caps)) { 5367978SPeter.Dunlap@Sun.COM return (it); 5377978SPeter.Dunlap@Sun.COM } 5387978SPeter.Dunlap@Sun.COM } 5397978SPeter.Dunlap@Sun.COM 5407978SPeter.Dunlap@Sun.COM ASSERT(0); 5417978SPeter.Dunlap@Sun.COM return (NULL); /* Make gcc happy */ 5427978SPeter.Dunlap@Sun.COM } 5437978SPeter.Dunlap@Sun.COM 5447978SPeter.Dunlap@Sun.COM void 5457978SPeter.Dunlap@Sun.COM idm_transport_setup(ldi_ident_t li) 5467978SPeter.Dunlap@Sun.COM { 5477978SPeter.Dunlap@Sun.COM idm_transport_type_t type; 5487978SPeter.Dunlap@Sun.COM idm_transport_t *it; 5497978SPeter.Dunlap@Sun.COM int rc; 5507978SPeter.Dunlap@Sun.COM 5517978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 5527978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type]; 5537978SPeter.Dunlap@Sun.COM /* 5547978SPeter.Dunlap@Sun.COM * We may want to store the LDI handle in the idm_svc_t 5557978SPeter.Dunlap@Sun.COM * and then allow multiple calls to ldi_open_by_name. This 5567978SPeter.Dunlap@Sun.COM * would enable the LDI code to track who has the device open 5577978SPeter.Dunlap@Sun.COM * which could be useful in the case where we have multiple 5587978SPeter.Dunlap@Sun.COM * services and perhaps also have initiator and target opening 5597978SPeter.Dunlap@Sun.COM * the transport simultaneously. For now we stick with the 5607978SPeter.Dunlap@Sun.COM * plan. 5617978SPeter.Dunlap@Sun.COM */ 5627978SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) { 5637978SPeter.Dunlap@Sun.COM /* transport is not ready, try to initialize it */ 5647978SPeter.Dunlap@Sun.COM if (it->it_type == IDM_TRANSPORT_TYPE_SOCKETS) { 5657978SPeter.Dunlap@Sun.COM idm_so_init(it); 5667978SPeter.Dunlap@Sun.COM } else { 5677978SPeter.Dunlap@Sun.COM rc = ldi_open_by_name(it->it_device_path, 5687978SPeter.Dunlap@Sun.COM FREAD | FWRITE, kcred, &it->it_ldi_hdl, li); 5697978SPeter.Dunlap@Sun.COM /* 5707978SPeter.Dunlap@Sun.COM * If the open is successful we will have 5717978SPeter.Dunlap@Sun.COM * filled in the LDI handle in the transport 5727978SPeter.Dunlap@Sun.COM * table and we expect that the transport 5737978SPeter.Dunlap@Sun.COM * registered itself. 5747978SPeter.Dunlap@Sun.COM */ 5757978SPeter.Dunlap@Sun.COM if (rc != 0) { 5767978SPeter.Dunlap@Sun.COM it->it_ldi_hdl = NULL; 5777978SPeter.Dunlap@Sun.COM } 5787978SPeter.Dunlap@Sun.COM } 5797978SPeter.Dunlap@Sun.COM } 5807978SPeter.Dunlap@Sun.COM } 5817978SPeter.Dunlap@Sun.COM } 5827978SPeter.Dunlap@Sun.COM 5839162SPeter.Dunlap@Sun.COM void 5849162SPeter.Dunlap@Sun.COM idm_transport_teardown() 5859162SPeter.Dunlap@Sun.COM { 5869162SPeter.Dunlap@Sun.COM idm_transport_type_t type; 5879162SPeter.Dunlap@Sun.COM idm_transport_t *it; 5889162SPeter.Dunlap@Sun.COM 5899162SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&idm.idm_global_mutex)); 5909162SPeter.Dunlap@Sun.COM 5919162SPeter.Dunlap@Sun.COM /* Caller holds the IDM global mutex */ 5929162SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 5939162SPeter.Dunlap@Sun.COM it = &idm_transport_list[type]; 5949162SPeter.Dunlap@Sun.COM /* If we have an open LDI handle on this driver, close it */ 5959162SPeter.Dunlap@Sun.COM if (it->it_ldi_hdl != NULL) { 5969162SPeter.Dunlap@Sun.COM (void) ldi_close(it->it_ldi_hdl, FNDELAY, kcred); 5979162SPeter.Dunlap@Sun.COM it->it_ldi_hdl = NULL; 5989162SPeter.Dunlap@Sun.COM } 5999162SPeter.Dunlap@Sun.COM } 6009162SPeter.Dunlap@Sun.COM } 6019162SPeter.Dunlap@Sun.COM 6027978SPeter.Dunlap@Sun.COM /* 6037978SPeter.Dunlap@Sun.COM * ID pool code. We use this to generate unique structure identifiers without 6047978SPeter.Dunlap@Sun.COM * searching the existing structures. This avoids the need to lock entire 6057978SPeter.Dunlap@Sun.COM * sets of structures at inopportune times. Adapted from the CIFS server code. 6067978SPeter.Dunlap@Sun.COM * 6077978SPeter.Dunlap@Sun.COM * A pool of IDs is a pool of 16 bit numbers. It is implemented as a bitmap. 6087978SPeter.Dunlap@Sun.COM * A bit set to '1' indicates that that particular value has been allocated. 6097978SPeter.Dunlap@Sun.COM * The allocation process is done shifting a bit through the whole bitmap. 6107978SPeter.Dunlap@Sun.COM * The current position of that index bit is kept in the idm_idpool_t 6117978SPeter.Dunlap@Sun.COM * structure and represented by a byte index (0 to buffer size minus 1) and 6127978SPeter.Dunlap@Sun.COM * a bit index (0 to 7). 6137978SPeter.Dunlap@Sun.COM * 6147978SPeter.Dunlap@Sun.COM * The pools start with a size of 8 bytes or 64 IDs. Each time the pool runs 6157978SPeter.Dunlap@Sun.COM * out of IDs its current size is doubled until it reaches its maximum size 6167978SPeter.Dunlap@Sun.COM * (8192 bytes or 65536 IDs). The IDs 0 and 65535 are never given out which 6177978SPeter.Dunlap@Sun.COM * means that a pool can have a maximum number of 65534 IDs available. 6187978SPeter.Dunlap@Sun.COM */ 6197978SPeter.Dunlap@Sun.COM 6207978SPeter.Dunlap@Sun.COM static int 6217978SPeter.Dunlap@Sun.COM idm_idpool_increment( 6227978SPeter.Dunlap@Sun.COM idm_idpool_t *pool) 6237978SPeter.Dunlap@Sun.COM { 6247978SPeter.Dunlap@Sun.COM uint8_t *new_pool; 6257978SPeter.Dunlap@Sun.COM uint32_t new_size; 6267978SPeter.Dunlap@Sun.COM 6277978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC); 6287978SPeter.Dunlap@Sun.COM 6297978SPeter.Dunlap@Sun.COM new_size = pool->id_size * 2; 6307978SPeter.Dunlap@Sun.COM if (new_size <= IDM_IDPOOL_MAX_SIZE) { 6317978SPeter.Dunlap@Sun.COM new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP); 6327978SPeter.Dunlap@Sun.COM if (new_pool) { 6337978SPeter.Dunlap@Sun.COM bzero(new_pool, new_size / 8); 6347978SPeter.Dunlap@Sun.COM bcopy(pool->id_pool, new_pool, pool->id_size / 8); 6357978SPeter.Dunlap@Sun.COM kmem_free(pool->id_pool, pool->id_size / 8); 6367978SPeter.Dunlap@Sun.COM pool->id_pool = new_pool; 6377978SPeter.Dunlap@Sun.COM pool->id_free_counter += new_size - pool->id_size; 6387978SPeter.Dunlap@Sun.COM pool->id_max_free_counter += new_size - pool->id_size; 6397978SPeter.Dunlap@Sun.COM pool->id_size = new_size; 6407978SPeter.Dunlap@Sun.COM pool->id_idx_msk = (new_size / 8) - 1; 6417978SPeter.Dunlap@Sun.COM if (new_size >= IDM_IDPOOL_MAX_SIZE) { 6427978SPeter.Dunlap@Sun.COM /* id -1 made unavailable */ 6437978SPeter.Dunlap@Sun.COM pool->id_pool[pool->id_idx_msk] = 0x80; 6447978SPeter.Dunlap@Sun.COM pool->id_free_counter--; 6457978SPeter.Dunlap@Sun.COM pool->id_max_free_counter--; 6467978SPeter.Dunlap@Sun.COM } 6477978SPeter.Dunlap@Sun.COM return (0); 6487978SPeter.Dunlap@Sun.COM } 6497978SPeter.Dunlap@Sun.COM } 6507978SPeter.Dunlap@Sun.COM return (-1); 6517978SPeter.Dunlap@Sun.COM } 6527978SPeter.Dunlap@Sun.COM 6537978SPeter.Dunlap@Sun.COM /* 6547978SPeter.Dunlap@Sun.COM * idm_idpool_constructor 6557978SPeter.Dunlap@Sun.COM * 6567978SPeter.Dunlap@Sun.COM * This function initializes the pool structure provided. 6577978SPeter.Dunlap@Sun.COM */ 6587978SPeter.Dunlap@Sun.COM 6597978SPeter.Dunlap@Sun.COM int 6607978SPeter.Dunlap@Sun.COM idm_idpool_create(idm_idpool_t *pool) 6617978SPeter.Dunlap@Sun.COM { 6627978SPeter.Dunlap@Sun.COM 6637978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic != IDM_IDPOOL_MAGIC); 6647978SPeter.Dunlap@Sun.COM 6657978SPeter.Dunlap@Sun.COM pool->id_size = IDM_IDPOOL_MIN_SIZE; 6667978SPeter.Dunlap@Sun.COM pool->id_idx_msk = (IDM_IDPOOL_MIN_SIZE / 8) - 1; 6677978SPeter.Dunlap@Sun.COM pool->id_free_counter = IDM_IDPOOL_MIN_SIZE - 1; 6687978SPeter.Dunlap@Sun.COM pool->id_max_free_counter = IDM_IDPOOL_MIN_SIZE - 1; 6697978SPeter.Dunlap@Sun.COM pool->id_bit = 0x02; 6707978SPeter.Dunlap@Sun.COM pool->id_bit_idx = 1; 6717978SPeter.Dunlap@Sun.COM pool->id_idx = 0; 6727978SPeter.Dunlap@Sun.COM pool->id_pool = (uint8_t *)kmem_alloc((IDM_IDPOOL_MIN_SIZE / 8), 6737978SPeter.Dunlap@Sun.COM KM_SLEEP); 6747978SPeter.Dunlap@Sun.COM bzero(pool->id_pool, (IDM_IDPOOL_MIN_SIZE / 8)); 6757978SPeter.Dunlap@Sun.COM /* -1 id made unavailable */ 6767978SPeter.Dunlap@Sun.COM pool->id_pool[0] = 0x01; /* id 0 made unavailable */ 6777978SPeter.Dunlap@Sun.COM mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL); 6787978SPeter.Dunlap@Sun.COM pool->id_magic = IDM_IDPOOL_MAGIC; 6797978SPeter.Dunlap@Sun.COM return (0); 6807978SPeter.Dunlap@Sun.COM } 6817978SPeter.Dunlap@Sun.COM 6827978SPeter.Dunlap@Sun.COM /* 6837978SPeter.Dunlap@Sun.COM * idm_idpool_destructor 6847978SPeter.Dunlap@Sun.COM * 6857978SPeter.Dunlap@Sun.COM * This function tears down and frees the resources associated with the 6867978SPeter.Dunlap@Sun.COM * pool provided. 6877978SPeter.Dunlap@Sun.COM */ 6887978SPeter.Dunlap@Sun.COM 6897978SPeter.Dunlap@Sun.COM void 6907978SPeter.Dunlap@Sun.COM idm_idpool_destroy(idm_idpool_t *pool) 6917978SPeter.Dunlap@Sun.COM { 6927978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC); 6937978SPeter.Dunlap@Sun.COM ASSERT(pool->id_free_counter == pool->id_max_free_counter); 6947978SPeter.Dunlap@Sun.COM pool->id_magic = (uint32_t)~IDM_IDPOOL_MAGIC; 6957978SPeter.Dunlap@Sun.COM mutex_destroy(&pool->id_mutex); 6967978SPeter.Dunlap@Sun.COM kmem_free(pool->id_pool, (size_t)(pool->id_size / 8)); 6977978SPeter.Dunlap@Sun.COM } 6987978SPeter.Dunlap@Sun.COM 6997978SPeter.Dunlap@Sun.COM /* 7007978SPeter.Dunlap@Sun.COM * idm_idpool_alloc 7017978SPeter.Dunlap@Sun.COM * 7027978SPeter.Dunlap@Sun.COM * This function allocates an ID from the pool provided. 7037978SPeter.Dunlap@Sun.COM */ 7047978SPeter.Dunlap@Sun.COM int 7057978SPeter.Dunlap@Sun.COM idm_idpool_alloc(idm_idpool_t *pool, uint16_t *id) 7067978SPeter.Dunlap@Sun.COM { 7077978SPeter.Dunlap@Sun.COM uint32_t i; 7087978SPeter.Dunlap@Sun.COM uint8_t bit; 7097978SPeter.Dunlap@Sun.COM uint8_t bit_idx; 7107978SPeter.Dunlap@Sun.COM uint8_t byte; 7117978SPeter.Dunlap@Sun.COM 7127978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC); 7137978SPeter.Dunlap@Sun.COM 7147978SPeter.Dunlap@Sun.COM mutex_enter(&pool->id_mutex); 7157978SPeter.Dunlap@Sun.COM if ((pool->id_free_counter == 0) && idm_idpool_increment(pool)) { 7167978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 7177978SPeter.Dunlap@Sun.COM return (-1); 7187978SPeter.Dunlap@Sun.COM } 7197978SPeter.Dunlap@Sun.COM 7207978SPeter.Dunlap@Sun.COM i = pool->id_size; 7217978SPeter.Dunlap@Sun.COM while (i) { 7227978SPeter.Dunlap@Sun.COM bit = pool->id_bit; 7237978SPeter.Dunlap@Sun.COM bit_idx = pool->id_bit_idx; 7247978SPeter.Dunlap@Sun.COM byte = pool->id_pool[pool->id_idx]; 7257978SPeter.Dunlap@Sun.COM while (bit) { 7267978SPeter.Dunlap@Sun.COM if (byte & bit) { 7277978SPeter.Dunlap@Sun.COM bit = bit << 1; 7287978SPeter.Dunlap@Sun.COM bit_idx++; 7297978SPeter.Dunlap@Sun.COM continue; 7307978SPeter.Dunlap@Sun.COM } 7317978SPeter.Dunlap@Sun.COM pool->id_pool[pool->id_idx] |= bit; 7327978SPeter.Dunlap@Sun.COM *id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx); 7337978SPeter.Dunlap@Sun.COM pool->id_free_counter--; 7347978SPeter.Dunlap@Sun.COM pool->id_bit = bit; 7357978SPeter.Dunlap@Sun.COM pool->id_bit_idx = bit_idx; 7367978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 7377978SPeter.Dunlap@Sun.COM return (0); 7387978SPeter.Dunlap@Sun.COM } 7397978SPeter.Dunlap@Sun.COM pool->id_bit = 1; 7407978SPeter.Dunlap@Sun.COM pool->id_bit_idx = 0; 7417978SPeter.Dunlap@Sun.COM pool->id_idx++; 7427978SPeter.Dunlap@Sun.COM pool->id_idx &= pool->id_idx_msk; 7437978SPeter.Dunlap@Sun.COM --i; 7447978SPeter.Dunlap@Sun.COM } 7457978SPeter.Dunlap@Sun.COM /* 7467978SPeter.Dunlap@Sun.COM * This section of code shouldn't be reached. If there are IDs 7477978SPeter.Dunlap@Sun.COM * available and none could be found there's a problem. 7487978SPeter.Dunlap@Sun.COM */ 7497978SPeter.Dunlap@Sun.COM ASSERT(0); 7507978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 7517978SPeter.Dunlap@Sun.COM return (-1); 7527978SPeter.Dunlap@Sun.COM } 7537978SPeter.Dunlap@Sun.COM 7547978SPeter.Dunlap@Sun.COM /* 7557978SPeter.Dunlap@Sun.COM * idm_idpool_free 7567978SPeter.Dunlap@Sun.COM * 7577978SPeter.Dunlap@Sun.COM * This function frees the ID provided. 7587978SPeter.Dunlap@Sun.COM */ 7597978SPeter.Dunlap@Sun.COM void 7607978SPeter.Dunlap@Sun.COM idm_idpool_free(idm_idpool_t *pool, uint16_t id) 7617978SPeter.Dunlap@Sun.COM { 7627978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC); 7637978SPeter.Dunlap@Sun.COM ASSERT(id != 0); 7647978SPeter.Dunlap@Sun.COM ASSERT(id != 0xFFFF); 7657978SPeter.Dunlap@Sun.COM 7667978SPeter.Dunlap@Sun.COM mutex_enter(&pool->id_mutex); 7677978SPeter.Dunlap@Sun.COM if (pool->id_pool[id >> 3] & (1 << (id & 7))) { 7687978SPeter.Dunlap@Sun.COM pool->id_pool[id >> 3] &= ~(1 << (id & 7)); 7697978SPeter.Dunlap@Sun.COM pool->id_free_counter++; 7707978SPeter.Dunlap@Sun.COM ASSERT(pool->id_free_counter <= pool->id_max_free_counter); 7717978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 7727978SPeter.Dunlap@Sun.COM return; 7737978SPeter.Dunlap@Sun.COM } 7747978SPeter.Dunlap@Sun.COM /* Freeing a free ID. */ 7757978SPeter.Dunlap@Sun.COM ASSERT(0); 7767978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 7777978SPeter.Dunlap@Sun.COM } 7787978SPeter.Dunlap@Sun.COM 7797978SPeter.Dunlap@Sun.COM uint32_t 7807978SPeter.Dunlap@Sun.COM idm_cid_alloc(void) 7817978SPeter.Dunlap@Sun.COM { 7827978SPeter.Dunlap@Sun.COM /* 7837978SPeter.Dunlap@Sun.COM * ID pool works with 16-bit identifiers right now. That should 7847978SPeter.Dunlap@Sun.COM * be plenty since we will probably never have more than 2^16 7857978SPeter.Dunlap@Sun.COM * connections simultaneously. 7867978SPeter.Dunlap@Sun.COM */ 7877978SPeter.Dunlap@Sun.COM uint16_t cid16; 7887978SPeter.Dunlap@Sun.COM 7897978SPeter.Dunlap@Sun.COM if (idm_idpool_alloc(&idm.idm_conn_id_pool, &cid16) == -1) { 7907978SPeter.Dunlap@Sun.COM return (0); /* Fail */ 7917978SPeter.Dunlap@Sun.COM } 7927978SPeter.Dunlap@Sun.COM 7937978SPeter.Dunlap@Sun.COM return ((uint32_t)cid16); 7947978SPeter.Dunlap@Sun.COM } 7957978SPeter.Dunlap@Sun.COM 7967978SPeter.Dunlap@Sun.COM void 7977978SPeter.Dunlap@Sun.COM idm_cid_free(uint32_t cid) 7987978SPeter.Dunlap@Sun.COM { 7997978SPeter.Dunlap@Sun.COM idm_idpool_free(&idm.idm_conn_id_pool, (uint16_t)cid); 8007978SPeter.Dunlap@Sun.COM } 8017978SPeter.Dunlap@Sun.COM 8027978SPeter.Dunlap@Sun.COM 8037978SPeter.Dunlap@Sun.COM /* 8047978SPeter.Dunlap@Sun.COM * Code for generating the header and data digests 8057978SPeter.Dunlap@Sun.COM * 8067978SPeter.Dunlap@Sun.COM * This is the CRC-32C table 8077978SPeter.Dunlap@Sun.COM * Generated with: 8087978SPeter.Dunlap@Sun.COM * width = 32 bits 8097978SPeter.Dunlap@Sun.COM * poly = 0x1EDC6F41 8107978SPeter.Dunlap@Sun.COM * reflect input bytes = true 8117978SPeter.Dunlap@Sun.COM * reflect output bytes = true 8127978SPeter.Dunlap@Sun.COM */ 8137978SPeter.Dunlap@Sun.COM 8147978SPeter.Dunlap@Sun.COM uint32_t idm_crc32c_table[256] = 8157978SPeter.Dunlap@Sun.COM { 8167978SPeter.Dunlap@Sun.COM 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 8177978SPeter.Dunlap@Sun.COM 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 8187978SPeter.Dunlap@Sun.COM 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 8197978SPeter.Dunlap@Sun.COM 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 8207978SPeter.Dunlap@Sun.COM 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 8217978SPeter.Dunlap@Sun.COM 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 8227978SPeter.Dunlap@Sun.COM 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 8237978SPeter.Dunlap@Sun.COM 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 8247978SPeter.Dunlap@Sun.COM 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 8257978SPeter.Dunlap@Sun.COM 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 8267978SPeter.Dunlap@Sun.COM 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 8277978SPeter.Dunlap@Sun.COM 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 8287978SPeter.Dunlap@Sun.COM 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 8297978SPeter.Dunlap@Sun.COM 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 8307978SPeter.Dunlap@Sun.COM 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 8317978SPeter.Dunlap@Sun.COM 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 8327978SPeter.Dunlap@Sun.COM 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 8337978SPeter.Dunlap@Sun.COM 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 8347978SPeter.Dunlap@Sun.COM 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 8357978SPeter.Dunlap@Sun.COM 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 8367978SPeter.Dunlap@Sun.COM 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 8377978SPeter.Dunlap@Sun.COM 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 8387978SPeter.Dunlap@Sun.COM 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 8397978SPeter.Dunlap@Sun.COM 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 8407978SPeter.Dunlap@Sun.COM 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 8417978SPeter.Dunlap@Sun.COM 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 8427978SPeter.Dunlap@Sun.COM 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 8437978SPeter.Dunlap@Sun.COM 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 8447978SPeter.Dunlap@Sun.COM 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 8457978SPeter.Dunlap@Sun.COM 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 8467978SPeter.Dunlap@Sun.COM 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 8477978SPeter.Dunlap@Sun.COM 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 8487978SPeter.Dunlap@Sun.COM 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 8497978SPeter.Dunlap@Sun.COM 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 8507978SPeter.Dunlap@Sun.COM 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 8517978SPeter.Dunlap@Sun.COM 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 8527978SPeter.Dunlap@Sun.COM 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 8537978SPeter.Dunlap@Sun.COM 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 8547978SPeter.Dunlap@Sun.COM 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 8557978SPeter.Dunlap@Sun.COM 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 8567978SPeter.Dunlap@Sun.COM 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 8577978SPeter.Dunlap@Sun.COM 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 8587978SPeter.Dunlap@Sun.COM 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 8597978SPeter.Dunlap@Sun.COM 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 8607978SPeter.Dunlap@Sun.COM 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 8617978SPeter.Dunlap@Sun.COM 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 8627978SPeter.Dunlap@Sun.COM 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 8637978SPeter.Dunlap@Sun.COM 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 8647978SPeter.Dunlap@Sun.COM 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 8657978SPeter.Dunlap@Sun.COM 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 8667978SPeter.Dunlap@Sun.COM 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 8677978SPeter.Dunlap@Sun.COM 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 8687978SPeter.Dunlap@Sun.COM 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 8697978SPeter.Dunlap@Sun.COM 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 8707978SPeter.Dunlap@Sun.COM 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 8717978SPeter.Dunlap@Sun.COM 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 8727978SPeter.Dunlap@Sun.COM 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 8737978SPeter.Dunlap@Sun.COM 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 8747978SPeter.Dunlap@Sun.COM 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 8757978SPeter.Dunlap@Sun.COM 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 8767978SPeter.Dunlap@Sun.COM 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 8777978SPeter.Dunlap@Sun.COM 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 8787978SPeter.Dunlap@Sun.COM 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 8797978SPeter.Dunlap@Sun.COM 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 8807978SPeter.Dunlap@Sun.COM }; 8817978SPeter.Dunlap@Sun.COM 8827978SPeter.Dunlap@Sun.COM /* 8837978SPeter.Dunlap@Sun.COM * iscsi_crc32c - Steps through buffer one byte at at time, calculates 8847978SPeter.Dunlap@Sun.COM * reflected crc using table. 8857978SPeter.Dunlap@Sun.COM */ 8867978SPeter.Dunlap@Sun.COM uint32_t 8877978SPeter.Dunlap@Sun.COM idm_crc32c(void *address, unsigned long length) 8887978SPeter.Dunlap@Sun.COM { 8897978SPeter.Dunlap@Sun.COM uint8_t *buffer = address; 8907978SPeter.Dunlap@Sun.COM uint32_t crc = 0xffffffff, result; 8917978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 8927978SPeter.Dunlap@Sun.COM uint8_t byte0, byte1, byte2, byte3; 8937978SPeter.Dunlap@Sun.COM #endif 8947978SPeter.Dunlap@Sun.COM 8957978SPeter.Dunlap@Sun.COM ASSERT(address != NULL); 8967978SPeter.Dunlap@Sun.COM 8977978SPeter.Dunlap@Sun.COM while (length--) { 8987978SPeter.Dunlap@Sun.COM crc = idm_crc32c_table[(crc ^ *buffer++) & 0xFFL] ^ 8997978SPeter.Dunlap@Sun.COM (crc >> 8); 9007978SPeter.Dunlap@Sun.COM } 9017978SPeter.Dunlap@Sun.COM result = crc ^ 0xffffffff; 9027978SPeter.Dunlap@Sun.COM 9037978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 9047978SPeter.Dunlap@Sun.COM byte0 = (uint8_t)(result & 0xFF); 9057978SPeter.Dunlap@Sun.COM byte1 = (uint8_t)((result >> 8) & 0xFF); 9067978SPeter.Dunlap@Sun.COM byte2 = (uint8_t)((result >> 16) & 0xFF); 9077978SPeter.Dunlap@Sun.COM byte3 = (uint8_t)((result >> 24) & 0xFF); 9087978SPeter.Dunlap@Sun.COM result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 9097978SPeter.Dunlap@Sun.COM #endif /* _BIG_ENDIAN */ 9107978SPeter.Dunlap@Sun.COM 9117978SPeter.Dunlap@Sun.COM return (result); 9127978SPeter.Dunlap@Sun.COM } 9137978SPeter.Dunlap@Sun.COM 9147978SPeter.Dunlap@Sun.COM 9157978SPeter.Dunlap@Sun.COM /* 9167978SPeter.Dunlap@Sun.COM * idm_crc32c_continued - Continues stepping through buffer one 9177978SPeter.Dunlap@Sun.COM * byte at at time, calculates reflected crc using table. 9187978SPeter.Dunlap@Sun.COM */ 9197978SPeter.Dunlap@Sun.COM uint32_t 9207978SPeter.Dunlap@Sun.COM idm_crc32c_continued(void *address, unsigned long length, uint32_t crc) 9217978SPeter.Dunlap@Sun.COM { 9227978SPeter.Dunlap@Sun.COM uint8_t *buffer = address; 9237978SPeter.Dunlap@Sun.COM uint32_t result; 9247978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 9257978SPeter.Dunlap@Sun.COM uint8_t byte0, byte1, byte2, byte3; 9267978SPeter.Dunlap@Sun.COM #endif 9277978SPeter.Dunlap@Sun.COM 9287978SPeter.Dunlap@Sun.COM ASSERT(address != NULL); 9297978SPeter.Dunlap@Sun.COM 9307978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 9317978SPeter.Dunlap@Sun.COM byte0 = (uint8_t)((crc >> 24) & 0xFF); 9327978SPeter.Dunlap@Sun.COM byte1 = (uint8_t)((crc >> 16) & 0xFF); 9337978SPeter.Dunlap@Sun.COM byte2 = (uint8_t)((crc >> 8) & 0xFF); 9347978SPeter.Dunlap@Sun.COM byte3 = (uint8_t)(crc & 0xFF); 9357978SPeter.Dunlap@Sun.COM crc = ((byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0); 9367978SPeter.Dunlap@Sun.COM #endif 9377978SPeter.Dunlap@Sun.COM 9387978SPeter.Dunlap@Sun.COM crc = crc ^ 0xffffffff; 9397978SPeter.Dunlap@Sun.COM while (length--) { 9407978SPeter.Dunlap@Sun.COM crc = idm_crc32c_table[(crc ^ *buffer++) & 0xFFL] ^ 9417978SPeter.Dunlap@Sun.COM (crc >> 8); 9427978SPeter.Dunlap@Sun.COM } 9437978SPeter.Dunlap@Sun.COM result = crc ^ 0xffffffff; 9447978SPeter.Dunlap@Sun.COM 9457978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 9467978SPeter.Dunlap@Sun.COM byte0 = (uint8_t)(result & 0xFF); 9477978SPeter.Dunlap@Sun.COM byte1 = (uint8_t)((result >> 8) & 0xFF); 9487978SPeter.Dunlap@Sun.COM byte2 = (uint8_t)((result >> 16) & 0xFF); 9497978SPeter.Dunlap@Sun.COM byte3 = (uint8_t)((result >> 24) & 0xFF); 9507978SPeter.Dunlap@Sun.COM result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 9517978SPeter.Dunlap@Sun.COM #endif 9527978SPeter.Dunlap@Sun.COM return (result); 9537978SPeter.Dunlap@Sun.COM } 9547978SPeter.Dunlap@Sun.COM 9557978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 9567978SPeter.Dunlap@Sun.COM int 9577978SPeter.Dunlap@Sun.COM idm_task_constructor(void *hdl, void *arg, int flags) 9587978SPeter.Dunlap@Sun.COM { 9597978SPeter.Dunlap@Sun.COM idm_task_t *idt = (idm_task_t *)hdl; 9607978SPeter.Dunlap@Sun.COM uint32_t next_task; 9617978SPeter.Dunlap@Sun.COM 9627978SPeter.Dunlap@Sun.COM mutex_init(&idt->idt_mutex, NULL, MUTEX_DEFAULT, NULL); 9637978SPeter.Dunlap@Sun.COM 9647978SPeter.Dunlap@Sun.COM /* Find the next free task ID */ 9657978SPeter.Dunlap@Sun.COM rw_enter(&idm.idm_taskid_table_lock, RW_WRITER); 9667978SPeter.Dunlap@Sun.COM next_task = idm.idm_taskid_next; 9677978SPeter.Dunlap@Sun.COM while (idm.idm_taskid_table[next_task]) { 9687978SPeter.Dunlap@Sun.COM next_task++; 9697978SPeter.Dunlap@Sun.COM if (next_task == idm.idm_taskid_max) 9707978SPeter.Dunlap@Sun.COM next_task = 0; 9717978SPeter.Dunlap@Sun.COM if (next_task == idm.idm_taskid_next) { 9727978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock); 9737978SPeter.Dunlap@Sun.COM return (-1); 9747978SPeter.Dunlap@Sun.COM } 9757978SPeter.Dunlap@Sun.COM } 9767978SPeter.Dunlap@Sun.COM 9777978SPeter.Dunlap@Sun.COM idm.idm_taskid_table[next_task] = idt; 9787978SPeter.Dunlap@Sun.COM idm.idm_taskid_next = (next_task + 1) % idm.idm_taskid_max; 9797978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock); 9807978SPeter.Dunlap@Sun.COM 9817978SPeter.Dunlap@Sun.COM idt->idt_tt = next_task; 9827978SPeter.Dunlap@Sun.COM 9837978SPeter.Dunlap@Sun.COM list_create(&idt->idt_inbufv, sizeof (idm_buf_t), 9847978SPeter.Dunlap@Sun.COM offsetof(idm_buf_t, idb_buflink)); 9857978SPeter.Dunlap@Sun.COM list_create(&idt->idt_outbufv, sizeof (idm_buf_t), 9867978SPeter.Dunlap@Sun.COM offsetof(idm_buf_t, idb_buflink)); 9877978SPeter.Dunlap@Sun.COM idm_refcnt_init(&idt->idt_refcnt, idt); 9887978SPeter.Dunlap@Sun.COM 9897978SPeter.Dunlap@Sun.COM /* 9907978SPeter.Dunlap@Sun.COM * Set the transport header pointer explicitly. This removes the 9917978SPeter.Dunlap@Sun.COM * need for per-transport header allocation, which simplifies cache 9927978SPeter.Dunlap@Sun.COM * init considerably. If at a later date we have an additional IDM 9937978SPeter.Dunlap@Sun.COM * transport that requires a different size, we'll revisit this. 9947978SPeter.Dunlap@Sun.COM */ 9957978SPeter.Dunlap@Sun.COM idt->idt_transport_hdr = (void *)(idt + 1); /* pointer arithmetic */ 9967978SPeter.Dunlap@Sun.COM 9977978SPeter.Dunlap@Sun.COM return (0); 9987978SPeter.Dunlap@Sun.COM } 9997978SPeter.Dunlap@Sun.COM 10007978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 10017978SPeter.Dunlap@Sun.COM void 10027978SPeter.Dunlap@Sun.COM idm_task_destructor(void *hdl, void *arg) 10037978SPeter.Dunlap@Sun.COM { 10047978SPeter.Dunlap@Sun.COM idm_task_t *idt = (idm_task_t *)hdl; 10057978SPeter.Dunlap@Sun.COM 10067978SPeter.Dunlap@Sun.COM /* Remove the task from the ID table */ 10077978SPeter.Dunlap@Sun.COM rw_enter(&idm.idm_taskid_table_lock, RW_WRITER); 10087978SPeter.Dunlap@Sun.COM idm.idm_taskid_table[idt->idt_tt] = NULL; 10097978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock); 10107978SPeter.Dunlap@Sun.COM 10117978SPeter.Dunlap@Sun.COM /* free the inbuf and outbuf */ 10127978SPeter.Dunlap@Sun.COM idm_refcnt_destroy(&idt->idt_refcnt); 10137978SPeter.Dunlap@Sun.COM list_destroy(&idt->idt_inbufv); 10147978SPeter.Dunlap@Sun.COM list_destroy(&idt->idt_outbufv); 10157978SPeter.Dunlap@Sun.COM 10169162SPeter.Dunlap@Sun.COM /* 10179162SPeter.Dunlap@Sun.COM * The final call to idm_task_rele may happen with the task 10189162SPeter.Dunlap@Sun.COM * mutex held which may invoke this destructor immediately. 10199162SPeter.Dunlap@Sun.COM * Stall here until the task mutex owner lets go. 10209162SPeter.Dunlap@Sun.COM */ 10219162SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex); 10227978SPeter.Dunlap@Sun.COM mutex_destroy(&idt->idt_mutex); 10237978SPeter.Dunlap@Sun.COM } 10247978SPeter.Dunlap@Sun.COM 10257978SPeter.Dunlap@Sun.COM /* 10267978SPeter.Dunlap@Sun.COM * idm_listbuf_insert searches from the back of the list looking for the 10277978SPeter.Dunlap@Sun.COM * insertion point. 10287978SPeter.Dunlap@Sun.COM */ 10297978SPeter.Dunlap@Sun.COM void 10307978SPeter.Dunlap@Sun.COM idm_listbuf_insert(list_t *lst, idm_buf_t *buf) 10317978SPeter.Dunlap@Sun.COM { 10327978SPeter.Dunlap@Sun.COM idm_buf_t *idb; 10337978SPeter.Dunlap@Sun.COM 10347978SPeter.Dunlap@Sun.COM /* iterate through the list to find the insertion point */ 10357978SPeter.Dunlap@Sun.COM for (idb = list_tail(lst); idb != NULL; idb = list_prev(lst, idb)) { 10367978SPeter.Dunlap@Sun.COM 10377978SPeter.Dunlap@Sun.COM if (idb->idb_bufoffset < buf->idb_bufoffset) { 10387978SPeter.Dunlap@Sun.COM 10397978SPeter.Dunlap@Sun.COM list_insert_after(lst, idb, buf); 10407978SPeter.Dunlap@Sun.COM return; 10417978SPeter.Dunlap@Sun.COM } 10427978SPeter.Dunlap@Sun.COM } 10437978SPeter.Dunlap@Sun.COM 10447978SPeter.Dunlap@Sun.COM /* add the buf to the head of the list */ 10457978SPeter.Dunlap@Sun.COM list_insert_head(lst, buf); 10467978SPeter.Dunlap@Sun.COM 10477978SPeter.Dunlap@Sun.COM } 10487978SPeter.Dunlap@Sun.COM 10497978SPeter.Dunlap@Sun.COM /*ARGSUSED*/ 10507978SPeter.Dunlap@Sun.COM void 10517978SPeter.Dunlap@Sun.COM idm_wd_thread(void *arg) 10527978SPeter.Dunlap@Sun.COM { 10537978SPeter.Dunlap@Sun.COM idm_conn_t *ic; 10547978SPeter.Dunlap@Sun.COM clock_t wake_time; 10557978SPeter.Dunlap@Sun.COM clock_t idle_time; 10567978SPeter.Dunlap@Sun.COM 10578209SJames.Moore@Sun.COM /* Record the thread id for thread_join() */ 10588209SJames.Moore@Sun.COM idm.idm_wd_thread_did = curthread->t_did; 10597978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 10607978SPeter.Dunlap@Sun.COM idm.idm_wd_thread_running = B_TRUE; 10617978SPeter.Dunlap@Sun.COM cv_signal(&idm.idm_wd_cv); 10627978SPeter.Dunlap@Sun.COM 10637978SPeter.Dunlap@Sun.COM while (idm.idm_wd_thread_running) { 10647978SPeter.Dunlap@Sun.COM for (ic = list_head(&idm.idm_tgt_conn_list); 10657978SPeter.Dunlap@Sun.COM ic != NULL; 10667978SPeter.Dunlap@Sun.COM ic = list_next(&idm.idm_tgt_conn_list, ic)) { 10677978SPeter.Dunlap@Sun.COM idle_time = ddi_get_lbolt() - ic->ic_timestamp; 10687978SPeter.Dunlap@Sun.COM 10697978SPeter.Dunlap@Sun.COM /* 10709586SPeter.Dunlap@Sun.COM * If this connection is in FFP then grab a hold 10719586SPeter.Dunlap@Sun.COM * and check the various timeout thresholds. Otherwise 10729586SPeter.Dunlap@Sun.COM * the connection is closing and we should just 10739586SPeter.Dunlap@Sun.COM * move on to the next one. 10749586SPeter.Dunlap@Sun.COM */ 10759586SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 10769586SPeter.Dunlap@Sun.COM if (ic->ic_ffp) { 10779586SPeter.Dunlap@Sun.COM idm_conn_hold(ic); 10789586SPeter.Dunlap@Sun.COM } else { 10799586SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 10809586SPeter.Dunlap@Sun.COM continue; 10819586SPeter.Dunlap@Sun.COM } 10829586SPeter.Dunlap@Sun.COM 10839586SPeter.Dunlap@Sun.COM /* 10847978SPeter.Dunlap@Sun.COM * If there hasn't been any activity on this 10859586SPeter.Dunlap@Sun.COM * connection for the keepalive timeout period 10869586SPeter.Dunlap@Sun.COM * and if the client has provided a keepalive 10879586SPeter.Dunlap@Sun.COM * callback then call the keepalive callback. 10889586SPeter.Dunlap@Sun.COM * This allows the client to take action to keep 10899586SPeter.Dunlap@Sun.COM * the link alive (like send a nop PDU). 10909586SPeter.Dunlap@Sun.COM */ 10919586SPeter.Dunlap@Sun.COM if ((TICK_TO_SEC(idle_time) >= 10929586SPeter.Dunlap@Sun.COM IDM_TRANSPORT_KEEPALIVE_IDLE_TIMEOUT) && 10939586SPeter.Dunlap@Sun.COM !ic->ic_keepalive) { 10949586SPeter.Dunlap@Sun.COM ic->ic_keepalive = B_TRUE; 10959586SPeter.Dunlap@Sun.COM if (ic->ic_conn_ops.icb_keepalive) { 10969586SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 10979586SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 10989586SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_keepalive)(ic); 10999586SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 11009586SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 11019586SPeter.Dunlap@Sun.COM } 11029586SPeter.Dunlap@Sun.COM } else if ((TICK_TO_SEC(idle_time) < 11039586SPeter.Dunlap@Sun.COM IDM_TRANSPORT_KEEPALIVE_IDLE_TIMEOUT)) { 11049586SPeter.Dunlap@Sun.COM /* Reset keepalive */ 11059586SPeter.Dunlap@Sun.COM ic->ic_keepalive = B_FALSE; 11069586SPeter.Dunlap@Sun.COM } 11079586SPeter.Dunlap@Sun.COM 11089586SPeter.Dunlap@Sun.COM /* 11099586SPeter.Dunlap@Sun.COM * If there hasn't been any activity on this 11109586SPeter.Dunlap@Sun.COM * connection for the failure timeout period then 11117978SPeter.Dunlap@Sun.COM * drop the connection. We expect the initiator 11127978SPeter.Dunlap@Sun.COM * to keep the connection alive if it wants the 11137978SPeter.Dunlap@Sun.COM * connection to stay open. 11147978SPeter.Dunlap@Sun.COM * 11157978SPeter.Dunlap@Sun.COM * If it turns out to be desireable to take a 11167978SPeter.Dunlap@Sun.COM * more active role in maintaining the connect 11177978SPeter.Dunlap@Sun.COM * we could add a client callback to send 11187978SPeter.Dunlap@Sun.COM * a "keepalive" kind of message (no doubt a nop) 11197978SPeter.Dunlap@Sun.COM * and fire that on a shorter timer. 11207978SPeter.Dunlap@Sun.COM */ 11217978SPeter.Dunlap@Sun.COM if (TICK_TO_SEC(idle_time) > 11227978SPeter.Dunlap@Sun.COM IDM_TRANSPORT_FAIL_IDLE_TIMEOUT) { 11239586SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 11249586SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 11259586SPeter.Dunlap@Sun.COM IDM_SM_LOG(CE_WARN, "idm_wd_thread: " 11269586SPeter.Dunlap@Sun.COM "conn %p idle for %d seconds, " 11279586SPeter.Dunlap@Sun.COM "sending CE_TRANSPORT_FAIL", 11289586SPeter.Dunlap@Sun.COM (void *)ic, (int)idle_time); 11299586SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL); 11309586SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 11319586SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 11327978SPeter.Dunlap@Sun.COM } 11339586SPeter.Dunlap@Sun.COM 11349586SPeter.Dunlap@Sun.COM idm_conn_rele(ic); 11359586SPeter.Dunlap@Sun.COM 11369586SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 11377978SPeter.Dunlap@Sun.COM } 11387978SPeter.Dunlap@Sun.COM 11399586SPeter.Dunlap@Sun.COM wake_time = ddi_get_lbolt() + SEC_TO_TICK(IDM_WD_INTERVAL); 11407978SPeter.Dunlap@Sun.COM (void) cv_timedwait(&idm.idm_wd_cv, &idm.idm_global_mutex, 11417978SPeter.Dunlap@Sun.COM wake_time); 11427978SPeter.Dunlap@Sun.COM } 11437978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 11447978SPeter.Dunlap@Sun.COM 11457978SPeter.Dunlap@Sun.COM thread_exit(); 11467978SPeter.Dunlap@Sun.COM } 1147