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> 327978SPeter.Dunlap@Sun.COM 337978SPeter.Dunlap@Sun.COM #include <sys/socket.h> 347978SPeter.Dunlap@Sun.COM #include <sys/strsubr.h> 357978SPeter.Dunlap@Sun.COM #include <sys/socketvar.h> 367978SPeter.Dunlap@Sun.COM #include <sys/sysmacros.h> 377978SPeter.Dunlap@Sun.COM 387978SPeter.Dunlap@Sun.COM #include <sys/idm/idm.h> 397978SPeter.Dunlap@Sun.COM #include <sys/idm/idm_so.h> 407978SPeter.Dunlap@Sun.COM 417978SPeter.Dunlap@Sun.COM extern idm_transport_t idm_transport_list[]; 427978SPeter.Dunlap@Sun.COM 437978SPeter.Dunlap@Sun.COM void 447978SPeter.Dunlap@Sun.COM idm_pdu_rx(idm_conn_t *ic, idm_pdu_t *pdu) 457978SPeter.Dunlap@Sun.COM { 467978SPeter.Dunlap@Sun.COM iscsi_async_evt_hdr_t *async_evt; 477978SPeter.Dunlap@Sun.COM 487978SPeter.Dunlap@Sun.COM /* 497978SPeter.Dunlap@Sun.COM * If we are in full-featured mode then route SCSI-related 507978SPeter.Dunlap@Sun.COM * commands to the appropriate function vector 517978SPeter.Dunlap@Sun.COM */ 527978SPeter.Dunlap@Sun.COM ic->ic_timestamp = ddi_get_lbolt(); 537978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 547978SPeter.Dunlap@Sun.COM if (ic->ic_ffp && ic->ic_pdu_events == 0) { 557978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 567978SPeter.Dunlap@Sun.COM 577978SPeter.Dunlap@Sun.COM if (idm_pdu_rx_forward_ffp(ic, pdu) == B_TRUE) { 587978SPeter.Dunlap@Sun.COM /* Forwarded SCSI-related commands */ 597978SPeter.Dunlap@Sun.COM return; 607978SPeter.Dunlap@Sun.COM } 617978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 627978SPeter.Dunlap@Sun.COM } 637978SPeter.Dunlap@Sun.COM 647978SPeter.Dunlap@Sun.COM /* 657978SPeter.Dunlap@Sun.COM * If we get here with a SCSI-related PDU then we are not in 667978SPeter.Dunlap@Sun.COM * full-feature mode and the PDU is a protocol error (SCSI command 677978SPeter.Dunlap@Sun.COM * PDU's may sometimes be an exception, see below). All 687978SPeter.Dunlap@Sun.COM * non-SCSI PDU's get treated them the same regardless of whether 697978SPeter.Dunlap@Sun.COM * we are in full-feature mode. 707978SPeter.Dunlap@Sun.COM * 717978SPeter.Dunlap@Sun.COM * Look at the opcode and in some cases the PDU status and 727978SPeter.Dunlap@Sun.COM * determine the appropriate event to send to the connection 737978SPeter.Dunlap@Sun.COM * state machine. Generate the event, passing the PDU as data. 747978SPeter.Dunlap@Sun.COM * If the current connection state allows reception of the event 757978SPeter.Dunlap@Sun.COM * the PDU will be submitted to the IDM client for processing, 767978SPeter.Dunlap@Sun.COM * otherwise the PDU will be dropped. 777978SPeter.Dunlap@Sun.COM */ 787978SPeter.Dunlap@Sun.COM switch (IDM_PDU_OPCODE(pdu)) { 797978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_CMD: 807978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_LOGIN_RCV, (uintptr_t)pdu); 817978SPeter.Dunlap@Sun.COM break; 827978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_RSP: 837978SPeter.Dunlap@Sun.COM idm_parse_login_rsp(ic, pdu, /* RX */ B_TRUE); 847978SPeter.Dunlap@Sun.COM break; 857978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_CMD: 867978SPeter.Dunlap@Sun.COM idm_parse_logout_req(ic, pdu, /* RX */ B_TRUE); 877978SPeter.Dunlap@Sun.COM break; 887978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_RSP: 897978SPeter.Dunlap@Sun.COM idm_parse_logout_rsp(ic, pdu, /* RX */ B_TRUE); 907978SPeter.Dunlap@Sun.COM break; 917978SPeter.Dunlap@Sun.COM case ISCSI_OP_ASYNC_EVENT: 927978SPeter.Dunlap@Sun.COM async_evt = (iscsi_async_evt_hdr_t *)pdu->isp_hdr; 939162SPeter.Dunlap@Sun.COM switch (async_evt->async_event) { 947978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT: 957978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_ASYNC_LOGOUT_RCV, 967978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 977978SPeter.Dunlap@Sun.COM break; 987978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION: 997978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_ASYNC_DROP_CONN_RCV, 1007978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 1017978SPeter.Dunlap@Sun.COM break; 1027978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS: 1037978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_ASYNC_DROP_ALL_CONN_RCV, 1047978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 1057978SPeter.Dunlap@Sun.COM break; 1067978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_SCSI_EVENT: 1077978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION: 1087978SPeter.Dunlap@Sun.COM default: 1097978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_MISC_RX, 1107978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 1117978SPeter.Dunlap@Sun.COM break; 1127978SPeter.Dunlap@Sun.COM } 1137978SPeter.Dunlap@Sun.COM break; 1147978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_CMD: 1157978SPeter.Dunlap@Sun.COM /* 1167978SPeter.Dunlap@Sun.COM * Consider this scenario: We are a target connection 1177978SPeter.Dunlap@Sun.COM * in "in login" state and a "login success sent" event has 1187978SPeter.Dunlap@Sun.COM * been generated but not yet handled. Since we've sent 1197978SPeter.Dunlap@Sun.COM * the login response but we haven't actually transitioned 1207978SPeter.Dunlap@Sun.COM * to FFP mode we might conceivably receive a SCSI command 1217978SPeter.Dunlap@Sun.COM * from the initiator before we are ready. We are actually 1227978SPeter.Dunlap@Sun.COM * in FFP we just don't know it yet -- to address this we 1237978SPeter.Dunlap@Sun.COM * can generate an event corresponding to the SCSI command. 1247978SPeter.Dunlap@Sun.COM * At the point when the event is handled by the state 1257978SPeter.Dunlap@Sun.COM * machine the login request will have been handled and we 1267978SPeter.Dunlap@Sun.COM * should be in FFP. If we are not in FFP by that time 1277978SPeter.Dunlap@Sun.COM * we can reject the SCSI command with a protocol error. 1287978SPeter.Dunlap@Sun.COM * 1297978SPeter.Dunlap@Sun.COM * This scenario only applies to the target. 1307978SPeter.Dunlap@Sun.COM */ 1317978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA: 1327978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA_RSP: 1337978SPeter.Dunlap@Sun.COM case ISCSI_OP_RTT_RSP: 1347978SPeter.Dunlap@Sun.COM case ISCSI_OP_SNACK_CMD: 1357978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_IN: 1367978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_OUT: 1377978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_CMD: 1387978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_RSP: 1397978SPeter.Dunlap@Sun.COM case ISCSI_OP_REJECT_MSG: 1407978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_MSG: 1417978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_RSP: 1427978SPeter.Dunlap@Sun.COM /* Validate received PDU against current state */ 1437978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, CE_MISC_RX, 1447978SPeter.Dunlap@Sun.COM (uintptr_t)pdu); 1457978SPeter.Dunlap@Sun.COM break; 1467978SPeter.Dunlap@Sun.COM } 1477978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 1487978SPeter.Dunlap@Sun.COM } 1497978SPeter.Dunlap@Sun.COM 1507978SPeter.Dunlap@Sun.COM void 1517978SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(idm_conn_t *ic, idm_pdu_t *pdu) 1527978SPeter.Dunlap@Sun.COM { 1537978SPeter.Dunlap@Sun.COM (*ic->ic_transport_ops->it_tx_pdu)(ic, pdu); 1547978SPeter.Dunlap@Sun.COM } 1557978SPeter.Dunlap@Sun.COM 1567978SPeter.Dunlap@Sun.COM boolean_t 1577978SPeter.Dunlap@Sun.COM idm_pdu_rx_forward_ffp(idm_conn_t *ic, idm_pdu_t *pdu) 1587978SPeter.Dunlap@Sun.COM { 1597978SPeter.Dunlap@Sun.COM /* 1607978SPeter.Dunlap@Sun.COM * If this is an FFP request, call the appropriate handler 1617978SPeter.Dunlap@Sun.COM * and return B_TRUE, otherwise return B_FALSE. 1627978SPeter.Dunlap@Sun.COM */ 1637978SPeter.Dunlap@Sun.COM switch (IDM_PDU_OPCODE(pdu)) { 1647978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_CMD: 1657978SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_rx_scsi_cmd)(ic, pdu); 1667978SPeter.Dunlap@Sun.COM return (B_TRUE); 1677978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_RSP: 1687978SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_rx_scsi_rsp)(ic, pdu); 1697978SPeter.Dunlap@Sun.COM return (B_TRUE); 1707978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA: 1717978SPeter.Dunlap@Sun.COM (*ic->ic_transport_ops->it_rx_dataout)(ic, pdu); 1727978SPeter.Dunlap@Sun.COM return (B_TRUE); 1737978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA_RSP: 1747978SPeter.Dunlap@Sun.COM (*ic->ic_transport_ops->it_rx_datain)(ic, pdu); 1757978SPeter.Dunlap@Sun.COM return (B_TRUE); 1767978SPeter.Dunlap@Sun.COM case ISCSI_OP_RTT_RSP: 1777978SPeter.Dunlap@Sun.COM (*ic->ic_transport_ops->it_rx_rtt)(ic, pdu); 1787978SPeter.Dunlap@Sun.COM return (B_TRUE); 1797978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_MSG: 1807978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_RSP: 1817978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_CMD: 1827978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_RSP: 1837978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_OUT: 1847978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_IN: 1857978SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_rx_misc)(ic, pdu); 1867978SPeter.Dunlap@Sun.COM return (B_TRUE); 1877978SPeter.Dunlap@Sun.COM default: 1887978SPeter.Dunlap@Sun.COM return (B_FALSE); 1897978SPeter.Dunlap@Sun.COM } 1907978SPeter.Dunlap@Sun.COM /*NOTREACHED*/ 1917978SPeter.Dunlap@Sun.COM } 1927978SPeter.Dunlap@Sun.COM 1937978SPeter.Dunlap@Sun.COM void 1947978SPeter.Dunlap@Sun.COM idm_pdu_rx_forward(idm_conn_t *ic, idm_pdu_t *pdu) 1957978SPeter.Dunlap@Sun.COM { 1967978SPeter.Dunlap@Sun.COM /* 1977978SPeter.Dunlap@Sun.COM * Some PDU's specific to FFP get special handling. This function 1987978SPeter.Dunlap@Sun.COM * will normally never be called in FFP with an FFP PDU since this 1997978SPeter.Dunlap@Sun.COM * is a slow path but in can happen on the target side during 2007978SPeter.Dunlap@Sun.COM * the transition to FFP. We primarily call 2017978SPeter.Dunlap@Sun.COM * idm_pdu_rx_forward_ffp here to avoid code duplication. 2027978SPeter.Dunlap@Sun.COM */ 2037978SPeter.Dunlap@Sun.COM if (idm_pdu_rx_forward_ffp(ic, pdu) == B_FALSE) { 2047978SPeter.Dunlap@Sun.COM /* 2057978SPeter.Dunlap@Sun.COM * Non-FFP PDU, use generic RC handler 2067978SPeter.Dunlap@Sun.COM */ 2077978SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_rx_misc)(ic, pdu); 2087978SPeter.Dunlap@Sun.COM } 2097978SPeter.Dunlap@Sun.COM } 2107978SPeter.Dunlap@Sun.COM 2117978SPeter.Dunlap@Sun.COM void 2127978SPeter.Dunlap@Sun.COM idm_parse_login_rsp(idm_conn_t *ic, idm_pdu_t *login_rsp_pdu, boolean_t rx) 2137978SPeter.Dunlap@Sun.COM { 2147978SPeter.Dunlap@Sun.COM iscsi_login_rsp_hdr_t *login_rsp = 2157978SPeter.Dunlap@Sun.COM (iscsi_login_rsp_hdr_t *)login_rsp_pdu->isp_hdr; 2167978SPeter.Dunlap@Sun.COM idm_conn_event_t new_event; 2177978SPeter.Dunlap@Sun.COM 2187978SPeter.Dunlap@Sun.COM if (login_rsp->status_class == ISCSI_STATUS_CLASS_SUCCESS) { 2197978SPeter.Dunlap@Sun.COM if (!(login_rsp->flags & ISCSI_FLAG_LOGIN_CONTINUE) && 2207978SPeter.Dunlap@Sun.COM (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) && 2217978SPeter.Dunlap@Sun.COM (ISCSI_LOGIN_NEXT_STAGE(login_rsp->flags) == 2227978SPeter.Dunlap@Sun.COM ISCSI_FULL_FEATURE_PHASE)) { 2237978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_LOGIN_SUCCESS_RCV : 2247978SPeter.Dunlap@Sun.COM CE_LOGIN_SUCCESS_SND); 2257978SPeter.Dunlap@Sun.COM } else { 2267978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_MISC_RX : CE_MISC_TX); 2277978SPeter.Dunlap@Sun.COM } 2287978SPeter.Dunlap@Sun.COM } else { 2297978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_LOGIN_FAIL_RCV : CE_LOGIN_FAIL_SND); 2307978SPeter.Dunlap@Sun.COM } 2317978SPeter.Dunlap@Sun.COM 2327978SPeter.Dunlap@Sun.COM if (rx) { 2337978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, new_event, (uintptr_t)login_rsp_pdu); 2347978SPeter.Dunlap@Sun.COM } else { 2357978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, new_event, (uintptr_t)login_rsp_pdu); 2367978SPeter.Dunlap@Sun.COM } 2377978SPeter.Dunlap@Sun.COM } 2387978SPeter.Dunlap@Sun.COM 2397978SPeter.Dunlap@Sun.COM 2407978SPeter.Dunlap@Sun.COM void 2417978SPeter.Dunlap@Sun.COM idm_parse_logout_req(idm_conn_t *ic, idm_pdu_t *logout_req_pdu, boolean_t rx) 2427978SPeter.Dunlap@Sun.COM { 2437978SPeter.Dunlap@Sun.COM iscsi_logout_hdr_t *logout_req = 2447978SPeter.Dunlap@Sun.COM (iscsi_logout_hdr_t *)logout_req_pdu->isp_hdr; 2457978SPeter.Dunlap@Sun.COM idm_conn_event_t new_event; 2467978SPeter.Dunlap@Sun.COM uint8_t reason = 2477978SPeter.Dunlap@Sun.COM (logout_req->flags & ISCSI_FLAG_LOGOUT_REASON_MASK); 2487978SPeter.Dunlap@Sun.COM 2497978SPeter.Dunlap@Sun.COM /* 2507978SPeter.Dunlap@Sun.COM * For a normal logout (close connection or close session) IDM 2517978SPeter.Dunlap@Sun.COM * will terminate processing of all tasks completing the tasks 2527978SPeter.Dunlap@Sun.COM * back to the client with a status indicating the connection 2537978SPeter.Dunlap@Sun.COM * was logged out. These tasks do not get completed. 2547978SPeter.Dunlap@Sun.COM * 2557978SPeter.Dunlap@Sun.COM * For a "close connection for recovery logout) IDM suspends 2567978SPeter.Dunlap@Sun.COM * processing of all tasks and completes them back to the client 2577978SPeter.Dunlap@Sun.COM * with a status indicating connection was logged out for 2587978SPeter.Dunlap@Sun.COM * recovery. Both initiator and target hang onto these tasks. 2597978SPeter.Dunlap@Sun.COM * When we add ERL2 support IDM will need to provide mechanisms 2607978SPeter.Dunlap@Sun.COM * to change the task and buffer associations to a new connection. 2617978SPeter.Dunlap@Sun.COM * 2627978SPeter.Dunlap@Sun.COM * This code doesn't address the possibility of MC/S. We'll 2637978SPeter.Dunlap@Sun.COM * need to decide how the separate connections get handled 2647978SPeter.Dunlap@Sun.COM * in that case. One simple option is to make the client 2657978SPeter.Dunlap@Sun.COM * generate the events for the other connections. 2667978SPeter.Dunlap@Sun.COM */ 2677978SPeter.Dunlap@Sun.COM if (reason == ISCSI_LOGOUT_REASON_CLOSE_SESSION) { 2687978SPeter.Dunlap@Sun.COM new_event = 2697978SPeter.Dunlap@Sun.COM (rx ? CE_LOGOUT_SESSION_RCV : CE_LOGOUT_SESSION_SND); 2707978SPeter.Dunlap@Sun.COM } else if ((reason == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION) || 2717978SPeter.Dunlap@Sun.COM (reason == ISCSI_LOGOUT_REASON_RECOVERY)) { 2727978SPeter.Dunlap@Sun.COM /* Check logout CID against this connection's CID */ 2737978SPeter.Dunlap@Sun.COM if (ntohs(logout_req->cid) == ic->ic_login_cid) { 2747978SPeter.Dunlap@Sun.COM /* Logout is for this connection */ 2757978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_LOGOUT_THIS_CONN_RCV : 2767978SPeter.Dunlap@Sun.COM CE_LOGOUT_THIS_CONN_SND); 2777978SPeter.Dunlap@Sun.COM } else { 2787978SPeter.Dunlap@Sun.COM /* 2797978SPeter.Dunlap@Sun.COM * Logout affects another connection. This is not 2807978SPeter.Dunlap@Sun.COM * a relevant event for this connection so we'll 2817978SPeter.Dunlap@Sun.COM * just treat it as a normal PDU event. Client 2827978SPeter.Dunlap@Sun.COM * will need to lookup the other connection and 2837978SPeter.Dunlap@Sun.COM * generate the event. 2847978SPeter.Dunlap@Sun.COM */ 2857978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_MISC_RX : CE_MISC_TX); 2867978SPeter.Dunlap@Sun.COM } 2877978SPeter.Dunlap@Sun.COM } else { 2887978SPeter.Dunlap@Sun.COM /* Invalid reason code */ 2897978SPeter.Dunlap@Sun.COM new_event = (rx ? CE_RX_PROTOCOL_ERROR : CE_TX_PROTOCOL_ERROR); 2907978SPeter.Dunlap@Sun.COM } 2917978SPeter.Dunlap@Sun.COM 2927978SPeter.Dunlap@Sun.COM if (rx) { 2937978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, new_event, (uintptr_t)logout_req_pdu); 2947978SPeter.Dunlap@Sun.COM } else { 2957978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, new_event, (uintptr_t)logout_req_pdu); 2967978SPeter.Dunlap@Sun.COM } 2977978SPeter.Dunlap@Sun.COM } 2987978SPeter.Dunlap@Sun.COM 2997978SPeter.Dunlap@Sun.COM 3007978SPeter.Dunlap@Sun.COM 3017978SPeter.Dunlap@Sun.COM void 3027978SPeter.Dunlap@Sun.COM idm_parse_logout_rsp(idm_conn_t *ic, idm_pdu_t *logout_rsp_pdu, boolean_t rx) 3037978SPeter.Dunlap@Sun.COM { 3047978SPeter.Dunlap@Sun.COM idm_conn_event_t new_event; 3057978SPeter.Dunlap@Sun.COM iscsi_logout_rsp_hdr_t *logout_rsp = 3067978SPeter.Dunlap@Sun.COM (iscsi_logout_rsp_hdr_t *)logout_rsp_pdu->isp_hdr; 3077978SPeter.Dunlap@Sun.COM 3087978SPeter.Dunlap@Sun.COM if (logout_rsp->response == ISCSI_STATUS_CLASS_SUCCESS) { 3097978SPeter.Dunlap@Sun.COM new_event = rx ? CE_LOGOUT_SUCCESS_RCV : CE_LOGOUT_SUCCESS_SND; 3107978SPeter.Dunlap@Sun.COM } else { 3117978SPeter.Dunlap@Sun.COM new_event = rx ? CE_LOGOUT_FAIL_RCV : CE_LOGOUT_FAIL_SND; 3127978SPeter.Dunlap@Sun.COM } 3137978SPeter.Dunlap@Sun.COM 3147978SPeter.Dunlap@Sun.COM if (rx) { 3157978SPeter.Dunlap@Sun.COM idm_conn_rx_pdu_event(ic, new_event, (uintptr_t)logout_rsp_pdu); 3167978SPeter.Dunlap@Sun.COM } else { 3177978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, new_event, (uintptr_t)logout_rsp_pdu); 3187978SPeter.Dunlap@Sun.COM } 3197978SPeter.Dunlap@Sun.COM } 3207978SPeter.Dunlap@Sun.COM 3217978SPeter.Dunlap@Sun.COM /* 3227978SPeter.Dunlap@Sun.COM * idm_svc_conn_create() 3237978SPeter.Dunlap@Sun.COM * Transport-agnostic service connection creation, invoked from the transport 3247978SPeter.Dunlap@Sun.COM * layer. 3257978SPeter.Dunlap@Sun.COM */ 3267978SPeter.Dunlap@Sun.COM idm_status_t 3277978SPeter.Dunlap@Sun.COM idm_svc_conn_create(idm_svc_t *is, idm_transport_type_t tt, 3287978SPeter.Dunlap@Sun.COM idm_conn_t **ic_result) 3297978SPeter.Dunlap@Sun.COM { 3307978SPeter.Dunlap@Sun.COM idm_conn_t *ic; 3317978SPeter.Dunlap@Sun.COM idm_status_t rc; 3327978SPeter.Dunlap@Sun.COM 3339162SPeter.Dunlap@Sun.COM mutex_enter(&is->is_mutex); 3349162SPeter.Dunlap@Sun.COM if (!is->is_online) { 3359162SPeter.Dunlap@Sun.COM mutex_exit(&is->is_mutex); 3369162SPeter.Dunlap@Sun.COM return (IDM_STATUS_FAIL); 3379162SPeter.Dunlap@Sun.COM } 3389162SPeter.Dunlap@Sun.COM mutex_exit(&is->is_mutex); 3399162SPeter.Dunlap@Sun.COM 3407978SPeter.Dunlap@Sun.COM ic = idm_conn_create_common(CONN_TYPE_TGT, tt, 3417978SPeter.Dunlap@Sun.COM &is->is_svc_req.sr_conn_ops); 3427978SPeter.Dunlap@Sun.COM ic->ic_svc_binding = is; 3437978SPeter.Dunlap@Sun.COM 3447978SPeter.Dunlap@Sun.COM /* 3457978SPeter.Dunlap@Sun.COM * Prepare connection state machine 3467978SPeter.Dunlap@Sun.COM */ 3477978SPeter.Dunlap@Sun.COM if ((rc = idm_conn_sm_init(ic)) != 0) { 3487978SPeter.Dunlap@Sun.COM idm_conn_destroy_common(ic); 3497978SPeter.Dunlap@Sun.COM return (rc); 3507978SPeter.Dunlap@Sun.COM } 3517978SPeter.Dunlap@Sun.COM 3527978SPeter.Dunlap@Sun.COM 3537978SPeter.Dunlap@Sun.COM *ic_result = ic; 3547978SPeter.Dunlap@Sun.COM 3557978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 3567978SPeter.Dunlap@Sun.COM list_insert_tail(&idm.idm_tgt_conn_list, ic); 3577978SPeter.Dunlap@Sun.COM idm.idm_tgt_conn_count++; 3587978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 3597978SPeter.Dunlap@Sun.COM 3609162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS); 3617978SPeter.Dunlap@Sun.COM } 3627978SPeter.Dunlap@Sun.COM 3637978SPeter.Dunlap@Sun.COM void 3647978SPeter.Dunlap@Sun.COM idm_svc_conn_destroy(idm_conn_t *ic) 3657978SPeter.Dunlap@Sun.COM { 3667978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 3677978SPeter.Dunlap@Sun.COM list_remove(&idm.idm_tgt_conn_list, ic); 3687978SPeter.Dunlap@Sun.COM idm.idm_tgt_conn_count--; 3697978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 3707978SPeter.Dunlap@Sun.COM 3717978SPeter.Dunlap@Sun.COM if (ic->ic_transport_private != NULL) { 3727978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_tgt_conn_destroy(ic); 3737978SPeter.Dunlap@Sun.COM } 3747978SPeter.Dunlap@Sun.COM idm_conn_destroy_common(ic); 3757978SPeter.Dunlap@Sun.COM } 3767978SPeter.Dunlap@Sun.COM 3777978SPeter.Dunlap@Sun.COM /* 3787978SPeter.Dunlap@Sun.COM * idm_conn_create_common() 3797978SPeter.Dunlap@Sun.COM * 3807978SPeter.Dunlap@Sun.COM * Allocate and initialize IDM connection context 3817978SPeter.Dunlap@Sun.COM */ 3827978SPeter.Dunlap@Sun.COM idm_conn_t * 3837978SPeter.Dunlap@Sun.COM idm_conn_create_common(idm_conn_type_t conn_type, idm_transport_type_t tt, 3847978SPeter.Dunlap@Sun.COM idm_conn_ops_t *conn_ops) 3857978SPeter.Dunlap@Sun.COM { 3867978SPeter.Dunlap@Sun.COM idm_conn_t *ic; 3877978SPeter.Dunlap@Sun.COM idm_transport_t *it; 3887978SPeter.Dunlap@Sun.COM idm_transport_type_t type; 3897978SPeter.Dunlap@Sun.COM 3907978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 3917978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type]; 3927978SPeter.Dunlap@Sun.COM 3937978SPeter.Dunlap@Sun.COM if ((it->it_ops != NULL) && (it->it_type == tt)) 3947978SPeter.Dunlap@Sun.COM break; 3957978SPeter.Dunlap@Sun.COM } 3967978SPeter.Dunlap@Sun.COM ASSERT(it->it_type == tt); 3977978SPeter.Dunlap@Sun.COM if (it->it_type != tt) 3987978SPeter.Dunlap@Sun.COM return (NULL); 3997978SPeter.Dunlap@Sun.COM 4007978SPeter.Dunlap@Sun.COM ic = kmem_zalloc(sizeof (idm_conn_t), KM_SLEEP); 4017978SPeter.Dunlap@Sun.COM 4027978SPeter.Dunlap@Sun.COM /* Initialize data */ 4037978SPeter.Dunlap@Sun.COM ic->ic_conn_type = conn_type; 4047978SPeter.Dunlap@Sun.COM ic->ic_conn_ops = *conn_ops; 4057978SPeter.Dunlap@Sun.COM ic->ic_transport_ops = it->it_ops; 4067978SPeter.Dunlap@Sun.COM ic->ic_transport_type = tt; 4077978SPeter.Dunlap@Sun.COM ic->ic_transport_private = NULL; /* Set by transport service */ 4087978SPeter.Dunlap@Sun.COM ic->ic_internal_cid = idm_cid_alloc(); 4097978SPeter.Dunlap@Sun.COM if (ic->ic_internal_cid == 0) { 4107978SPeter.Dunlap@Sun.COM kmem_free(ic, sizeof (idm_conn_t)); 4117978SPeter.Dunlap@Sun.COM return (NULL); 4127978SPeter.Dunlap@Sun.COM } 4137978SPeter.Dunlap@Sun.COM mutex_init(&ic->ic_mutex, NULL, MUTEX_DEFAULT, NULL); 4147978SPeter.Dunlap@Sun.COM cv_init(&ic->ic_cv, NULL, CV_DEFAULT, NULL); 4157978SPeter.Dunlap@Sun.COM idm_refcnt_init(&ic->ic_refcnt, ic); 4167978SPeter.Dunlap@Sun.COM 4177978SPeter.Dunlap@Sun.COM return (ic); 4187978SPeter.Dunlap@Sun.COM } 4197978SPeter.Dunlap@Sun.COM 4207978SPeter.Dunlap@Sun.COM void 4217978SPeter.Dunlap@Sun.COM idm_conn_destroy_common(idm_conn_t *ic) 4227978SPeter.Dunlap@Sun.COM { 4239162SPeter.Dunlap@Sun.COM idm_conn_sm_fini(ic); 4247978SPeter.Dunlap@Sun.COM idm_refcnt_destroy(&ic->ic_refcnt); 4257978SPeter.Dunlap@Sun.COM cv_destroy(&ic->ic_cv); 4267978SPeter.Dunlap@Sun.COM mutex_destroy(&ic->ic_mutex); 4277978SPeter.Dunlap@Sun.COM idm_cid_free(ic->ic_internal_cid); 4287978SPeter.Dunlap@Sun.COM 4297978SPeter.Dunlap@Sun.COM kmem_free(ic, sizeof (idm_conn_t)); 4307978SPeter.Dunlap@Sun.COM } 4317978SPeter.Dunlap@Sun.COM 4327978SPeter.Dunlap@Sun.COM /* 4337978SPeter.Dunlap@Sun.COM * Invoked from the SM as a result of client's invocation of 4347978SPeter.Dunlap@Sun.COM * idm_ini_conn_connect() 4357978SPeter.Dunlap@Sun.COM */ 4367978SPeter.Dunlap@Sun.COM idm_status_t 4377978SPeter.Dunlap@Sun.COM idm_ini_conn_finish(idm_conn_t *ic) 4387978SPeter.Dunlap@Sun.COM { 4397978SPeter.Dunlap@Sun.COM /* invoke transport-specific connection */ 4407978SPeter.Dunlap@Sun.COM return (ic->ic_transport_ops->it_ini_conn_connect(ic)); 4417978SPeter.Dunlap@Sun.COM } 4427978SPeter.Dunlap@Sun.COM 4437978SPeter.Dunlap@Sun.COM idm_status_t 4447978SPeter.Dunlap@Sun.COM idm_tgt_conn_finish(idm_conn_t *ic) 4457978SPeter.Dunlap@Sun.COM { 4467978SPeter.Dunlap@Sun.COM idm_status_t rc; 4477978SPeter.Dunlap@Sun.COM 4487978SPeter.Dunlap@Sun.COM rc = idm_notify_client(ic, CN_CONNECT_ACCEPT, NULL); 4497978SPeter.Dunlap@Sun.COM if (rc != IDM_STATUS_SUCCESS) { 4507978SPeter.Dunlap@Sun.COM return (IDM_STATUS_REJECT); 4517978SPeter.Dunlap@Sun.COM } 4527978SPeter.Dunlap@Sun.COM 4537978SPeter.Dunlap@Sun.COM /* Target client is ready to receive a login, start connection */ 4547978SPeter.Dunlap@Sun.COM return (ic->ic_transport_ops->it_tgt_conn_connect(ic)); 4557978SPeter.Dunlap@Sun.COM } 4567978SPeter.Dunlap@Sun.COM 4577978SPeter.Dunlap@Sun.COM idm_transport_t * 4587978SPeter.Dunlap@Sun.COM idm_transport_lookup(idm_conn_req_t *cr) 4597978SPeter.Dunlap@Sun.COM { 4607978SPeter.Dunlap@Sun.COM idm_transport_type_t type; 4617978SPeter.Dunlap@Sun.COM idm_transport_t *it; 4627978SPeter.Dunlap@Sun.COM idm_transport_caps_t caps; 4637978SPeter.Dunlap@Sun.COM 4647978SPeter.Dunlap@Sun.COM /* 4657978SPeter.Dunlap@Sun.COM * Make sure all available transports are setup. We call this now 4667978SPeter.Dunlap@Sun.COM * instead of at initialization time in case IB has become available 4677978SPeter.Dunlap@Sun.COM * since we started (hotplug, etc). 4687978SPeter.Dunlap@Sun.COM */ 4697978SPeter.Dunlap@Sun.COM idm_transport_setup(cr->cr_li); 4707978SPeter.Dunlap@Sun.COM 4717978SPeter.Dunlap@Sun.COM /* Determine the transport for this connection */ 4727978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 4737978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type]; 4747978SPeter.Dunlap@Sun.COM 4757978SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) { 4767978SPeter.Dunlap@Sun.COM /* transport is not registered */ 4777978SPeter.Dunlap@Sun.COM continue; 4787978SPeter.Dunlap@Sun.COM } 4797978SPeter.Dunlap@Sun.COM 4807978SPeter.Dunlap@Sun.COM if (it->it_ops->it_conn_is_capable(cr, &caps)) { 4817978SPeter.Dunlap@Sun.COM return (it); 4827978SPeter.Dunlap@Sun.COM } 4837978SPeter.Dunlap@Sun.COM } 4847978SPeter.Dunlap@Sun.COM 4857978SPeter.Dunlap@Sun.COM ASSERT(0); 4867978SPeter.Dunlap@Sun.COM return (NULL); /* Make gcc happy */ 4877978SPeter.Dunlap@Sun.COM } 4887978SPeter.Dunlap@Sun.COM 4897978SPeter.Dunlap@Sun.COM void 4907978SPeter.Dunlap@Sun.COM idm_transport_setup(ldi_ident_t li) 4917978SPeter.Dunlap@Sun.COM { 4927978SPeter.Dunlap@Sun.COM idm_transport_type_t type; 4937978SPeter.Dunlap@Sun.COM idm_transport_t *it; 4947978SPeter.Dunlap@Sun.COM int rc; 4957978SPeter.Dunlap@Sun.COM 4967978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 4977978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type]; 4987978SPeter.Dunlap@Sun.COM /* 4997978SPeter.Dunlap@Sun.COM * We may want to store the LDI handle in the idm_svc_t 5007978SPeter.Dunlap@Sun.COM * and then allow multiple calls to ldi_open_by_name. This 5017978SPeter.Dunlap@Sun.COM * would enable the LDI code to track who has the device open 5027978SPeter.Dunlap@Sun.COM * which could be useful in the case where we have multiple 5037978SPeter.Dunlap@Sun.COM * services and perhaps also have initiator and target opening 5047978SPeter.Dunlap@Sun.COM * the transport simultaneously. For now we stick with the 5057978SPeter.Dunlap@Sun.COM * plan. 5067978SPeter.Dunlap@Sun.COM */ 5077978SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) { 5087978SPeter.Dunlap@Sun.COM /* transport is not ready, try to initialize it */ 5097978SPeter.Dunlap@Sun.COM if (it->it_type == IDM_TRANSPORT_TYPE_SOCKETS) { 5107978SPeter.Dunlap@Sun.COM idm_so_init(it); 5117978SPeter.Dunlap@Sun.COM } else { 5127978SPeter.Dunlap@Sun.COM rc = ldi_open_by_name(it->it_device_path, 5137978SPeter.Dunlap@Sun.COM FREAD | FWRITE, kcred, &it->it_ldi_hdl, li); 5147978SPeter.Dunlap@Sun.COM /* 5157978SPeter.Dunlap@Sun.COM * If the open is successful we will have 5167978SPeter.Dunlap@Sun.COM * filled in the LDI handle in the transport 5177978SPeter.Dunlap@Sun.COM * table and we expect that the transport 5187978SPeter.Dunlap@Sun.COM * registered itself. 5197978SPeter.Dunlap@Sun.COM */ 5207978SPeter.Dunlap@Sun.COM if (rc != 0) { 5217978SPeter.Dunlap@Sun.COM it->it_ldi_hdl = NULL; 5227978SPeter.Dunlap@Sun.COM } 5237978SPeter.Dunlap@Sun.COM } 5247978SPeter.Dunlap@Sun.COM } 5257978SPeter.Dunlap@Sun.COM } 5267978SPeter.Dunlap@Sun.COM } 5277978SPeter.Dunlap@Sun.COM 5289162SPeter.Dunlap@Sun.COM void 5299162SPeter.Dunlap@Sun.COM idm_transport_teardown() 5309162SPeter.Dunlap@Sun.COM { 5319162SPeter.Dunlap@Sun.COM idm_transport_type_t type; 5329162SPeter.Dunlap@Sun.COM idm_transport_t *it; 5339162SPeter.Dunlap@Sun.COM 5349162SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&idm.idm_global_mutex)); 5359162SPeter.Dunlap@Sun.COM 5369162SPeter.Dunlap@Sun.COM /* Caller holds the IDM global mutex */ 5379162SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 5389162SPeter.Dunlap@Sun.COM it = &idm_transport_list[type]; 5399162SPeter.Dunlap@Sun.COM /* If we have an open LDI handle on this driver, close it */ 5409162SPeter.Dunlap@Sun.COM if (it->it_ldi_hdl != NULL) { 5419162SPeter.Dunlap@Sun.COM (void) ldi_close(it->it_ldi_hdl, FNDELAY, kcred); 5429162SPeter.Dunlap@Sun.COM it->it_ldi_hdl = NULL; 5439162SPeter.Dunlap@Sun.COM } 5449162SPeter.Dunlap@Sun.COM } 5459162SPeter.Dunlap@Sun.COM } 5469162SPeter.Dunlap@Sun.COM 5477978SPeter.Dunlap@Sun.COM /* 5487978SPeter.Dunlap@Sun.COM * ID pool code. We use this to generate unique structure identifiers without 5497978SPeter.Dunlap@Sun.COM * searching the existing structures. This avoids the need to lock entire 5507978SPeter.Dunlap@Sun.COM * sets of structures at inopportune times. Adapted from the CIFS server code. 5517978SPeter.Dunlap@Sun.COM * 5527978SPeter.Dunlap@Sun.COM * A pool of IDs is a pool of 16 bit numbers. It is implemented as a bitmap. 5537978SPeter.Dunlap@Sun.COM * A bit set to '1' indicates that that particular value has been allocated. 5547978SPeter.Dunlap@Sun.COM * The allocation process is done shifting a bit through the whole bitmap. 5557978SPeter.Dunlap@Sun.COM * The current position of that index bit is kept in the idm_idpool_t 5567978SPeter.Dunlap@Sun.COM * structure and represented by a byte index (0 to buffer size minus 1) and 5577978SPeter.Dunlap@Sun.COM * a bit index (0 to 7). 5587978SPeter.Dunlap@Sun.COM * 5597978SPeter.Dunlap@Sun.COM * The pools start with a size of 8 bytes or 64 IDs. Each time the pool runs 5607978SPeter.Dunlap@Sun.COM * out of IDs its current size is doubled until it reaches its maximum size 5617978SPeter.Dunlap@Sun.COM * (8192 bytes or 65536 IDs). The IDs 0 and 65535 are never given out which 5627978SPeter.Dunlap@Sun.COM * means that a pool can have a maximum number of 65534 IDs available. 5637978SPeter.Dunlap@Sun.COM */ 5647978SPeter.Dunlap@Sun.COM 5657978SPeter.Dunlap@Sun.COM static int 5667978SPeter.Dunlap@Sun.COM idm_idpool_increment( 5677978SPeter.Dunlap@Sun.COM idm_idpool_t *pool) 5687978SPeter.Dunlap@Sun.COM { 5697978SPeter.Dunlap@Sun.COM uint8_t *new_pool; 5707978SPeter.Dunlap@Sun.COM uint32_t new_size; 5717978SPeter.Dunlap@Sun.COM 5727978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC); 5737978SPeter.Dunlap@Sun.COM 5747978SPeter.Dunlap@Sun.COM new_size = pool->id_size * 2; 5757978SPeter.Dunlap@Sun.COM if (new_size <= IDM_IDPOOL_MAX_SIZE) { 5767978SPeter.Dunlap@Sun.COM new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP); 5777978SPeter.Dunlap@Sun.COM if (new_pool) { 5787978SPeter.Dunlap@Sun.COM bzero(new_pool, new_size / 8); 5797978SPeter.Dunlap@Sun.COM bcopy(pool->id_pool, new_pool, pool->id_size / 8); 5807978SPeter.Dunlap@Sun.COM kmem_free(pool->id_pool, pool->id_size / 8); 5817978SPeter.Dunlap@Sun.COM pool->id_pool = new_pool; 5827978SPeter.Dunlap@Sun.COM pool->id_free_counter += new_size - pool->id_size; 5837978SPeter.Dunlap@Sun.COM pool->id_max_free_counter += new_size - pool->id_size; 5847978SPeter.Dunlap@Sun.COM pool->id_size = new_size; 5857978SPeter.Dunlap@Sun.COM pool->id_idx_msk = (new_size / 8) - 1; 5867978SPeter.Dunlap@Sun.COM if (new_size >= IDM_IDPOOL_MAX_SIZE) { 5877978SPeter.Dunlap@Sun.COM /* id -1 made unavailable */ 5887978SPeter.Dunlap@Sun.COM pool->id_pool[pool->id_idx_msk] = 0x80; 5897978SPeter.Dunlap@Sun.COM pool->id_free_counter--; 5907978SPeter.Dunlap@Sun.COM pool->id_max_free_counter--; 5917978SPeter.Dunlap@Sun.COM } 5927978SPeter.Dunlap@Sun.COM return (0); 5937978SPeter.Dunlap@Sun.COM } 5947978SPeter.Dunlap@Sun.COM } 5957978SPeter.Dunlap@Sun.COM return (-1); 5967978SPeter.Dunlap@Sun.COM } 5977978SPeter.Dunlap@Sun.COM 5987978SPeter.Dunlap@Sun.COM /* 5997978SPeter.Dunlap@Sun.COM * idm_idpool_constructor 6007978SPeter.Dunlap@Sun.COM * 6017978SPeter.Dunlap@Sun.COM * This function initializes the pool structure provided. 6027978SPeter.Dunlap@Sun.COM */ 6037978SPeter.Dunlap@Sun.COM 6047978SPeter.Dunlap@Sun.COM int 6057978SPeter.Dunlap@Sun.COM idm_idpool_create(idm_idpool_t *pool) 6067978SPeter.Dunlap@Sun.COM { 6077978SPeter.Dunlap@Sun.COM 6087978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic != IDM_IDPOOL_MAGIC); 6097978SPeter.Dunlap@Sun.COM 6107978SPeter.Dunlap@Sun.COM pool->id_size = IDM_IDPOOL_MIN_SIZE; 6117978SPeter.Dunlap@Sun.COM pool->id_idx_msk = (IDM_IDPOOL_MIN_SIZE / 8) - 1; 6127978SPeter.Dunlap@Sun.COM pool->id_free_counter = IDM_IDPOOL_MIN_SIZE - 1; 6137978SPeter.Dunlap@Sun.COM pool->id_max_free_counter = IDM_IDPOOL_MIN_SIZE - 1; 6147978SPeter.Dunlap@Sun.COM pool->id_bit = 0x02; 6157978SPeter.Dunlap@Sun.COM pool->id_bit_idx = 1; 6167978SPeter.Dunlap@Sun.COM pool->id_idx = 0; 6177978SPeter.Dunlap@Sun.COM pool->id_pool = (uint8_t *)kmem_alloc((IDM_IDPOOL_MIN_SIZE / 8), 6187978SPeter.Dunlap@Sun.COM KM_SLEEP); 6197978SPeter.Dunlap@Sun.COM bzero(pool->id_pool, (IDM_IDPOOL_MIN_SIZE / 8)); 6207978SPeter.Dunlap@Sun.COM /* -1 id made unavailable */ 6217978SPeter.Dunlap@Sun.COM pool->id_pool[0] = 0x01; /* id 0 made unavailable */ 6227978SPeter.Dunlap@Sun.COM mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL); 6237978SPeter.Dunlap@Sun.COM pool->id_magic = IDM_IDPOOL_MAGIC; 6247978SPeter.Dunlap@Sun.COM return (0); 6257978SPeter.Dunlap@Sun.COM } 6267978SPeter.Dunlap@Sun.COM 6277978SPeter.Dunlap@Sun.COM /* 6287978SPeter.Dunlap@Sun.COM * idm_idpool_destructor 6297978SPeter.Dunlap@Sun.COM * 6307978SPeter.Dunlap@Sun.COM * This function tears down and frees the resources associated with the 6317978SPeter.Dunlap@Sun.COM * pool provided. 6327978SPeter.Dunlap@Sun.COM */ 6337978SPeter.Dunlap@Sun.COM 6347978SPeter.Dunlap@Sun.COM void 6357978SPeter.Dunlap@Sun.COM idm_idpool_destroy(idm_idpool_t *pool) 6367978SPeter.Dunlap@Sun.COM { 6377978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC); 6387978SPeter.Dunlap@Sun.COM ASSERT(pool->id_free_counter == pool->id_max_free_counter); 6397978SPeter.Dunlap@Sun.COM pool->id_magic = (uint32_t)~IDM_IDPOOL_MAGIC; 6407978SPeter.Dunlap@Sun.COM mutex_destroy(&pool->id_mutex); 6417978SPeter.Dunlap@Sun.COM kmem_free(pool->id_pool, (size_t)(pool->id_size / 8)); 6427978SPeter.Dunlap@Sun.COM } 6437978SPeter.Dunlap@Sun.COM 6447978SPeter.Dunlap@Sun.COM /* 6457978SPeter.Dunlap@Sun.COM * idm_idpool_alloc 6467978SPeter.Dunlap@Sun.COM * 6477978SPeter.Dunlap@Sun.COM * This function allocates an ID from the pool provided. 6487978SPeter.Dunlap@Sun.COM */ 6497978SPeter.Dunlap@Sun.COM int 6507978SPeter.Dunlap@Sun.COM idm_idpool_alloc(idm_idpool_t *pool, uint16_t *id) 6517978SPeter.Dunlap@Sun.COM { 6527978SPeter.Dunlap@Sun.COM uint32_t i; 6537978SPeter.Dunlap@Sun.COM uint8_t bit; 6547978SPeter.Dunlap@Sun.COM uint8_t bit_idx; 6557978SPeter.Dunlap@Sun.COM uint8_t byte; 6567978SPeter.Dunlap@Sun.COM 6577978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC); 6587978SPeter.Dunlap@Sun.COM 6597978SPeter.Dunlap@Sun.COM mutex_enter(&pool->id_mutex); 6607978SPeter.Dunlap@Sun.COM if ((pool->id_free_counter == 0) && idm_idpool_increment(pool)) { 6617978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 6627978SPeter.Dunlap@Sun.COM return (-1); 6637978SPeter.Dunlap@Sun.COM } 6647978SPeter.Dunlap@Sun.COM 6657978SPeter.Dunlap@Sun.COM i = pool->id_size; 6667978SPeter.Dunlap@Sun.COM while (i) { 6677978SPeter.Dunlap@Sun.COM bit = pool->id_bit; 6687978SPeter.Dunlap@Sun.COM bit_idx = pool->id_bit_idx; 6697978SPeter.Dunlap@Sun.COM byte = pool->id_pool[pool->id_idx]; 6707978SPeter.Dunlap@Sun.COM while (bit) { 6717978SPeter.Dunlap@Sun.COM if (byte & bit) { 6727978SPeter.Dunlap@Sun.COM bit = bit << 1; 6737978SPeter.Dunlap@Sun.COM bit_idx++; 6747978SPeter.Dunlap@Sun.COM continue; 6757978SPeter.Dunlap@Sun.COM } 6767978SPeter.Dunlap@Sun.COM pool->id_pool[pool->id_idx] |= bit; 6777978SPeter.Dunlap@Sun.COM *id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx); 6787978SPeter.Dunlap@Sun.COM pool->id_free_counter--; 6797978SPeter.Dunlap@Sun.COM pool->id_bit = bit; 6807978SPeter.Dunlap@Sun.COM pool->id_bit_idx = bit_idx; 6817978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 6827978SPeter.Dunlap@Sun.COM return (0); 6837978SPeter.Dunlap@Sun.COM } 6847978SPeter.Dunlap@Sun.COM pool->id_bit = 1; 6857978SPeter.Dunlap@Sun.COM pool->id_bit_idx = 0; 6867978SPeter.Dunlap@Sun.COM pool->id_idx++; 6877978SPeter.Dunlap@Sun.COM pool->id_idx &= pool->id_idx_msk; 6887978SPeter.Dunlap@Sun.COM --i; 6897978SPeter.Dunlap@Sun.COM } 6907978SPeter.Dunlap@Sun.COM /* 6917978SPeter.Dunlap@Sun.COM * This section of code shouldn't be reached. If there are IDs 6927978SPeter.Dunlap@Sun.COM * available and none could be found there's a problem. 6937978SPeter.Dunlap@Sun.COM */ 6947978SPeter.Dunlap@Sun.COM ASSERT(0); 6957978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 6967978SPeter.Dunlap@Sun.COM return (-1); 6977978SPeter.Dunlap@Sun.COM } 6987978SPeter.Dunlap@Sun.COM 6997978SPeter.Dunlap@Sun.COM /* 7007978SPeter.Dunlap@Sun.COM * idm_idpool_free 7017978SPeter.Dunlap@Sun.COM * 7027978SPeter.Dunlap@Sun.COM * This function frees the ID provided. 7037978SPeter.Dunlap@Sun.COM */ 7047978SPeter.Dunlap@Sun.COM void 7057978SPeter.Dunlap@Sun.COM idm_idpool_free(idm_idpool_t *pool, uint16_t id) 7067978SPeter.Dunlap@Sun.COM { 7077978SPeter.Dunlap@Sun.COM ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC); 7087978SPeter.Dunlap@Sun.COM ASSERT(id != 0); 7097978SPeter.Dunlap@Sun.COM ASSERT(id != 0xFFFF); 7107978SPeter.Dunlap@Sun.COM 7117978SPeter.Dunlap@Sun.COM mutex_enter(&pool->id_mutex); 7127978SPeter.Dunlap@Sun.COM if (pool->id_pool[id >> 3] & (1 << (id & 7))) { 7137978SPeter.Dunlap@Sun.COM pool->id_pool[id >> 3] &= ~(1 << (id & 7)); 7147978SPeter.Dunlap@Sun.COM pool->id_free_counter++; 7157978SPeter.Dunlap@Sun.COM ASSERT(pool->id_free_counter <= pool->id_max_free_counter); 7167978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 7177978SPeter.Dunlap@Sun.COM return; 7187978SPeter.Dunlap@Sun.COM } 7197978SPeter.Dunlap@Sun.COM /* Freeing a free ID. */ 7207978SPeter.Dunlap@Sun.COM ASSERT(0); 7217978SPeter.Dunlap@Sun.COM mutex_exit(&pool->id_mutex); 7227978SPeter.Dunlap@Sun.COM } 7237978SPeter.Dunlap@Sun.COM 7247978SPeter.Dunlap@Sun.COM uint32_t 7257978SPeter.Dunlap@Sun.COM idm_cid_alloc(void) 7267978SPeter.Dunlap@Sun.COM { 7277978SPeter.Dunlap@Sun.COM /* 7287978SPeter.Dunlap@Sun.COM * ID pool works with 16-bit identifiers right now. That should 7297978SPeter.Dunlap@Sun.COM * be plenty since we will probably never have more than 2^16 7307978SPeter.Dunlap@Sun.COM * connections simultaneously. 7317978SPeter.Dunlap@Sun.COM */ 7327978SPeter.Dunlap@Sun.COM uint16_t cid16; 7337978SPeter.Dunlap@Sun.COM 7347978SPeter.Dunlap@Sun.COM if (idm_idpool_alloc(&idm.idm_conn_id_pool, &cid16) == -1) { 7357978SPeter.Dunlap@Sun.COM return (0); /* Fail */ 7367978SPeter.Dunlap@Sun.COM } 7377978SPeter.Dunlap@Sun.COM 7387978SPeter.Dunlap@Sun.COM return ((uint32_t)cid16); 7397978SPeter.Dunlap@Sun.COM } 7407978SPeter.Dunlap@Sun.COM 7417978SPeter.Dunlap@Sun.COM void 7427978SPeter.Dunlap@Sun.COM idm_cid_free(uint32_t cid) 7437978SPeter.Dunlap@Sun.COM { 7447978SPeter.Dunlap@Sun.COM idm_idpool_free(&idm.idm_conn_id_pool, (uint16_t)cid); 7457978SPeter.Dunlap@Sun.COM } 7467978SPeter.Dunlap@Sun.COM 7477978SPeter.Dunlap@Sun.COM 7487978SPeter.Dunlap@Sun.COM /* 7497978SPeter.Dunlap@Sun.COM * Code for generating the header and data digests 7507978SPeter.Dunlap@Sun.COM * 7517978SPeter.Dunlap@Sun.COM * This is the CRC-32C table 7527978SPeter.Dunlap@Sun.COM * Generated with: 7537978SPeter.Dunlap@Sun.COM * width = 32 bits 7547978SPeter.Dunlap@Sun.COM * poly = 0x1EDC6F41 7557978SPeter.Dunlap@Sun.COM * reflect input bytes = true 7567978SPeter.Dunlap@Sun.COM * reflect output bytes = true 7577978SPeter.Dunlap@Sun.COM */ 7587978SPeter.Dunlap@Sun.COM 7597978SPeter.Dunlap@Sun.COM uint32_t idm_crc32c_table[256] = 7607978SPeter.Dunlap@Sun.COM { 7617978SPeter.Dunlap@Sun.COM 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 7627978SPeter.Dunlap@Sun.COM 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 7637978SPeter.Dunlap@Sun.COM 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 7647978SPeter.Dunlap@Sun.COM 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 7657978SPeter.Dunlap@Sun.COM 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 7667978SPeter.Dunlap@Sun.COM 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 7677978SPeter.Dunlap@Sun.COM 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 7687978SPeter.Dunlap@Sun.COM 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 7697978SPeter.Dunlap@Sun.COM 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 7707978SPeter.Dunlap@Sun.COM 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 7717978SPeter.Dunlap@Sun.COM 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 7727978SPeter.Dunlap@Sun.COM 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 7737978SPeter.Dunlap@Sun.COM 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 7747978SPeter.Dunlap@Sun.COM 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 7757978SPeter.Dunlap@Sun.COM 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 7767978SPeter.Dunlap@Sun.COM 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 7777978SPeter.Dunlap@Sun.COM 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 7787978SPeter.Dunlap@Sun.COM 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 7797978SPeter.Dunlap@Sun.COM 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 7807978SPeter.Dunlap@Sun.COM 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 7817978SPeter.Dunlap@Sun.COM 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 7827978SPeter.Dunlap@Sun.COM 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 7837978SPeter.Dunlap@Sun.COM 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 7847978SPeter.Dunlap@Sun.COM 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 7857978SPeter.Dunlap@Sun.COM 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 7867978SPeter.Dunlap@Sun.COM 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 7877978SPeter.Dunlap@Sun.COM 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 7887978SPeter.Dunlap@Sun.COM 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 7897978SPeter.Dunlap@Sun.COM 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 7907978SPeter.Dunlap@Sun.COM 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 7917978SPeter.Dunlap@Sun.COM 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 7927978SPeter.Dunlap@Sun.COM 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 7937978SPeter.Dunlap@Sun.COM 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 7947978SPeter.Dunlap@Sun.COM 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 7957978SPeter.Dunlap@Sun.COM 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 7967978SPeter.Dunlap@Sun.COM 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 7977978SPeter.Dunlap@Sun.COM 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 7987978SPeter.Dunlap@Sun.COM 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 7997978SPeter.Dunlap@Sun.COM 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 8007978SPeter.Dunlap@Sun.COM 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 8017978SPeter.Dunlap@Sun.COM 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 8027978SPeter.Dunlap@Sun.COM 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 8037978SPeter.Dunlap@Sun.COM 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 8047978SPeter.Dunlap@Sun.COM 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 8057978SPeter.Dunlap@Sun.COM 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 8067978SPeter.Dunlap@Sun.COM 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 8077978SPeter.Dunlap@Sun.COM 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 8087978SPeter.Dunlap@Sun.COM 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 8097978SPeter.Dunlap@Sun.COM 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 8107978SPeter.Dunlap@Sun.COM 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 8117978SPeter.Dunlap@Sun.COM 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 8127978SPeter.Dunlap@Sun.COM 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 8137978SPeter.Dunlap@Sun.COM 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 8147978SPeter.Dunlap@Sun.COM 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 8157978SPeter.Dunlap@Sun.COM 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 8167978SPeter.Dunlap@Sun.COM 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 8177978SPeter.Dunlap@Sun.COM 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 8187978SPeter.Dunlap@Sun.COM 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 8197978SPeter.Dunlap@Sun.COM 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 8207978SPeter.Dunlap@Sun.COM 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 8217978SPeter.Dunlap@Sun.COM 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 8227978SPeter.Dunlap@Sun.COM 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 8237978SPeter.Dunlap@Sun.COM 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 8247978SPeter.Dunlap@Sun.COM 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 8257978SPeter.Dunlap@Sun.COM }; 8267978SPeter.Dunlap@Sun.COM 8277978SPeter.Dunlap@Sun.COM /* 8287978SPeter.Dunlap@Sun.COM * iscsi_crc32c - Steps through buffer one byte at at time, calculates 8297978SPeter.Dunlap@Sun.COM * reflected crc using table. 8307978SPeter.Dunlap@Sun.COM */ 8317978SPeter.Dunlap@Sun.COM uint32_t 8327978SPeter.Dunlap@Sun.COM idm_crc32c(void *address, unsigned long length) 8337978SPeter.Dunlap@Sun.COM { 8347978SPeter.Dunlap@Sun.COM uint8_t *buffer = address; 8357978SPeter.Dunlap@Sun.COM uint32_t crc = 0xffffffff, result; 8367978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 8377978SPeter.Dunlap@Sun.COM uint8_t byte0, byte1, byte2, byte3; 8387978SPeter.Dunlap@Sun.COM #endif 8397978SPeter.Dunlap@Sun.COM 8407978SPeter.Dunlap@Sun.COM ASSERT(address != NULL); 8417978SPeter.Dunlap@Sun.COM 8427978SPeter.Dunlap@Sun.COM while (length--) { 8437978SPeter.Dunlap@Sun.COM crc = idm_crc32c_table[(crc ^ *buffer++) & 0xFFL] ^ 8447978SPeter.Dunlap@Sun.COM (crc >> 8); 8457978SPeter.Dunlap@Sun.COM } 8467978SPeter.Dunlap@Sun.COM result = crc ^ 0xffffffff; 8477978SPeter.Dunlap@Sun.COM 8487978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 8497978SPeter.Dunlap@Sun.COM byte0 = (uint8_t)(result & 0xFF); 8507978SPeter.Dunlap@Sun.COM byte1 = (uint8_t)((result >> 8) & 0xFF); 8517978SPeter.Dunlap@Sun.COM byte2 = (uint8_t)((result >> 16) & 0xFF); 8527978SPeter.Dunlap@Sun.COM byte3 = (uint8_t)((result >> 24) & 0xFF); 8537978SPeter.Dunlap@Sun.COM result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 8547978SPeter.Dunlap@Sun.COM #endif /* _BIG_ENDIAN */ 8557978SPeter.Dunlap@Sun.COM 8567978SPeter.Dunlap@Sun.COM return (result); 8577978SPeter.Dunlap@Sun.COM } 8587978SPeter.Dunlap@Sun.COM 8597978SPeter.Dunlap@Sun.COM 8607978SPeter.Dunlap@Sun.COM /* 8617978SPeter.Dunlap@Sun.COM * idm_crc32c_continued - Continues stepping through buffer one 8627978SPeter.Dunlap@Sun.COM * byte at at time, calculates reflected crc using table. 8637978SPeter.Dunlap@Sun.COM */ 8647978SPeter.Dunlap@Sun.COM uint32_t 8657978SPeter.Dunlap@Sun.COM idm_crc32c_continued(void *address, unsigned long length, uint32_t crc) 8667978SPeter.Dunlap@Sun.COM { 8677978SPeter.Dunlap@Sun.COM uint8_t *buffer = address; 8687978SPeter.Dunlap@Sun.COM uint32_t result; 8697978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 8707978SPeter.Dunlap@Sun.COM uint8_t byte0, byte1, byte2, byte3; 8717978SPeter.Dunlap@Sun.COM #endif 8727978SPeter.Dunlap@Sun.COM 8737978SPeter.Dunlap@Sun.COM ASSERT(address != NULL); 8747978SPeter.Dunlap@Sun.COM 8757978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 8767978SPeter.Dunlap@Sun.COM byte0 = (uint8_t)((crc >> 24) & 0xFF); 8777978SPeter.Dunlap@Sun.COM byte1 = (uint8_t)((crc >> 16) & 0xFF); 8787978SPeter.Dunlap@Sun.COM byte2 = (uint8_t)((crc >> 8) & 0xFF); 8797978SPeter.Dunlap@Sun.COM byte3 = (uint8_t)(crc & 0xFF); 8807978SPeter.Dunlap@Sun.COM crc = ((byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0); 8817978SPeter.Dunlap@Sun.COM #endif 8827978SPeter.Dunlap@Sun.COM 8837978SPeter.Dunlap@Sun.COM crc = crc ^ 0xffffffff; 8847978SPeter.Dunlap@Sun.COM while (length--) { 8857978SPeter.Dunlap@Sun.COM crc = idm_crc32c_table[(crc ^ *buffer++) & 0xFFL] ^ 8867978SPeter.Dunlap@Sun.COM (crc >> 8); 8877978SPeter.Dunlap@Sun.COM } 8887978SPeter.Dunlap@Sun.COM result = crc ^ 0xffffffff; 8897978SPeter.Dunlap@Sun.COM 8907978SPeter.Dunlap@Sun.COM #ifdef _BIG_ENDIAN 8917978SPeter.Dunlap@Sun.COM byte0 = (uint8_t)(result & 0xFF); 8927978SPeter.Dunlap@Sun.COM byte1 = (uint8_t)((result >> 8) & 0xFF); 8937978SPeter.Dunlap@Sun.COM byte2 = (uint8_t)((result >> 16) & 0xFF); 8947978SPeter.Dunlap@Sun.COM byte3 = (uint8_t)((result >> 24) & 0xFF); 8957978SPeter.Dunlap@Sun.COM result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 8967978SPeter.Dunlap@Sun.COM #endif 8977978SPeter.Dunlap@Sun.COM return (result); 8987978SPeter.Dunlap@Sun.COM } 8997978SPeter.Dunlap@Sun.COM 9007978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 9017978SPeter.Dunlap@Sun.COM int 9027978SPeter.Dunlap@Sun.COM idm_task_constructor(void *hdl, void *arg, int flags) 9037978SPeter.Dunlap@Sun.COM { 9047978SPeter.Dunlap@Sun.COM idm_task_t *idt = (idm_task_t *)hdl; 9057978SPeter.Dunlap@Sun.COM uint32_t next_task; 9067978SPeter.Dunlap@Sun.COM 9077978SPeter.Dunlap@Sun.COM mutex_init(&idt->idt_mutex, NULL, MUTEX_DEFAULT, NULL); 9087978SPeter.Dunlap@Sun.COM 9097978SPeter.Dunlap@Sun.COM /* Find the next free task ID */ 9107978SPeter.Dunlap@Sun.COM rw_enter(&idm.idm_taskid_table_lock, RW_WRITER); 9117978SPeter.Dunlap@Sun.COM next_task = idm.idm_taskid_next; 9127978SPeter.Dunlap@Sun.COM while (idm.idm_taskid_table[next_task]) { 9137978SPeter.Dunlap@Sun.COM next_task++; 9147978SPeter.Dunlap@Sun.COM if (next_task == idm.idm_taskid_max) 9157978SPeter.Dunlap@Sun.COM next_task = 0; 9167978SPeter.Dunlap@Sun.COM if (next_task == idm.idm_taskid_next) { 9177978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock); 9187978SPeter.Dunlap@Sun.COM return (-1); 9197978SPeter.Dunlap@Sun.COM } 9207978SPeter.Dunlap@Sun.COM } 9217978SPeter.Dunlap@Sun.COM 9227978SPeter.Dunlap@Sun.COM idm.idm_taskid_table[next_task] = idt; 9237978SPeter.Dunlap@Sun.COM idm.idm_taskid_next = (next_task + 1) % idm.idm_taskid_max; 9247978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock); 9257978SPeter.Dunlap@Sun.COM 9267978SPeter.Dunlap@Sun.COM idt->idt_tt = next_task; 9277978SPeter.Dunlap@Sun.COM 9287978SPeter.Dunlap@Sun.COM list_create(&idt->idt_inbufv, sizeof (idm_buf_t), 9297978SPeter.Dunlap@Sun.COM offsetof(idm_buf_t, idb_buflink)); 9307978SPeter.Dunlap@Sun.COM list_create(&idt->idt_outbufv, sizeof (idm_buf_t), 9317978SPeter.Dunlap@Sun.COM offsetof(idm_buf_t, idb_buflink)); 9327978SPeter.Dunlap@Sun.COM idm_refcnt_init(&idt->idt_refcnt, idt); 9337978SPeter.Dunlap@Sun.COM 9347978SPeter.Dunlap@Sun.COM /* 9357978SPeter.Dunlap@Sun.COM * Set the transport header pointer explicitly. This removes the 9367978SPeter.Dunlap@Sun.COM * need for per-transport header allocation, which simplifies cache 9377978SPeter.Dunlap@Sun.COM * init considerably. If at a later date we have an additional IDM 9387978SPeter.Dunlap@Sun.COM * transport that requires a different size, we'll revisit this. 9397978SPeter.Dunlap@Sun.COM */ 9407978SPeter.Dunlap@Sun.COM idt->idt_transport_hdr = (void *)(idt + 1); /* pointer arithmetic */ 9417978SPeter.Dunlap@Sun.COM 9427978SPeter.Dunlap@Sun.COM return (0); 9437978SPeter.Dunlap@Sun.COM } 9447978SPeter.Dunlap@Sun.COM 9457978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 9467978SPeter.Dunlap@Sun.COM void 9477978SPeter.Dunlap@Sun.COM idm_task_destructor(void *hdl, void *arg) 9487978SPeter.Dunlap@Sun.COM { 9497978SPeter.Dunlap@Sun.COM idm_task_t *idt = (idm_task_t *)hdl; 9507978SPeter.Dunlap@Sun.COM 9517978SPeter.Dunlap@Sun.COM /* Remove the task from the ID table */ 9527978SPeter.Dunlap@Sun.COM rw_enter(&idm.idm_taskid_table_lock, RW_WRITER); 9537978SPeter.Dunlap@Sun.COM idm.idm_taskid_table[idt->idt_tt] = NULL; 9547978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock); 9557978SPeter.Dunlap@Sun.COM 9567978SPeter.Dunlap@Sun.COM /* free the inbuf and outbuf */ 9577978SPeter.Dunlap@Sun.COM idm_refcnt_destroy(&idt->idt_refcnt); 9587978SPeter.Dunlap@Sun.COM list_destroy(&idt->idt_inbufv); 9597978SPeter.Dunlap@Sun.COM list_destroy(&idt->idt_outbufv); 9607978SPeter.Dunlap@Sun.COM 9619162SPeter.Dunlap@Sun.COM /* 9629162SPeter.Dunlap@Sun.COM * The final call to idm_task_rele may happen with the task 9639162SPeter.Dunlap@Sun.COM * mutex held which may invoke this destructor immediately. 9649162SPeter.Dunlap@Sun.COM * Stall here until the task mutex owner lets go. 9659162SPeter.Dunlap@Sun.COM */ 9669162SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex); 9677978SPeter.Dunlap@Sun.COM mutex_destroy(&idt->idt_mutex); 9687978SPeter.Dunlap@Sun.COM } 9697978SPeter.Dunlap@Sun.COM 9707978SPeter.Dunlap@Sun.COM /* 9717978SPeter.Dunlap@Sun.COM * idm_listbuf_insert searches from the back of the list looking for the 9727978SPeter.Dunlap@Sun.COM * insertion point. 9737978SPeter.Dunlap@Sun.COM */ 9747978SPeter.Dunlap@Sun.COM void 9757978SPeter.Dunlap@Sun.COM idm_listbuf_insert(list_t *lst, idm_buf_t *buf) 9767978SPeter.Dunlap@Sun.COM { 9777978SPeter.Dunlap@Sun.COM idm_buf_t *idb; 9787978SPeter.Dunlap@Sun.COM 9797978SPeter.Dunlap@Sun.COM /* iterate through the list to find the insertion point */ 9807978SPeter.Dunlap@Sun.COM for (idb = list_tail(lst); idb != NULL; idb = list_prev(lst, idb)) { 9817978SPeter.Dunlap@Sun.COM 9827978SPeter.Dunlap@Sun.COM if (idb->idb_bufoffset < buf->idb_bufoffset) { 9837978SPeter.Dunlap@Sun.COM 9847978SPeter.Dunlap@Sun.COM list_insert_after(lst, idb, buf); 9857978SPeter.Dunlap@Sun.COM return; 9867978SPeter.Dunlap@Sun.COM } 9877978SPeter.Dunlap@Sun.COM } 9887978SPeter.Dunlap@Sun.COM 9897978SPeter.Dunlap@Sun.COM /* add the buf to the head of the list */ 9907978SPeter.Dunlap@Sun.COM list_insert_head(lst, buf); 9917978SPeter.Dunlap@Sun.COM 9927978SPeter.Dunlap@Sun.COM } 9937978SPeter.Dunlap@Sun.COM 9947978SPeter.Dunlap@Sun.COM /*ARGSUSED*/ 9957978SPeter.Dunlap@Sun.COM void 9967978SPeter.Dunlap@Sun.COM idm_wd_thread(void *arg) 9977978SPeter.Dunlap@Sun.COM { 9987978SPeter.Dunlap@Sun.COM idm_conn_t *ic; 9997978SPeter.Dunlap@Sun.COM clock_t wake_time; 10007978SPeter.Dunlap@Sun.COM clock_t idle_time; 10017978SPeter.Dunlap@Sun.COM 10028209SJames.Moore@Sun.COM /* Record the thread id for thread_join() */ 10038209SJames.Moore@Sun.COM idm.idm_wd_thread_did = curthread->t_did; 10047978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 10057978SPeter.Dunlap@Sun.COM idm.idm_wd_thread_running = B_TRUE; 10067978SPeter.Dunlap@Sun.COM cv_signal(&idm.idm_wd_cv); 10077978SPeter.Dunlap@Sun.COM 10087978SPeter.Dunlap@Sun.COM while (idm.idm_wd_thread_running) { 10097978SPeter.Dunlap@Sun.COM for (ic = list_head(&idm.idm_tgt_conn_list); 10107978SPeter.Dunlap@Sun.COM ic != NULL; 10117978SPeter.Dunlap@Sun.COM ic = list_next(&idm.idm_tgt_conn_list, ic)) { 10127978SPeter.Dunlap@Sun.COM idle_time = ddi_get_lbolt() - ic->ic_timestamp; 10137978SPeter.Dunlap@Sun.COM 10147978SPeter.Dunlap@Sun.COM /* 1015*9586SPeter.Dunlap@Sun.COM * If this connection is in FFP then grab a hold 1016*9586SPeter.Dunlap@Sun.COM * and check the various timeout thresholds. Otherwise 1017*9586SPeter.Dunlap@Sun.COM * the connection is closing and we should just 1018*9586SPeter.Dunlap@Sun.COM * move on to the next one. 1019*9586SPeter.Dunlap@Sun.COM */ 1020*9586SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 1021*9586SPeter.Dunlap@Sun.COM if (ic->ic_ffp) { 1022*9586SPeter.Dunlap@Sun.COM idm_conn_hold(ic); 1023*9586SPeter.Dunlap@Sun.COM } else { 1024*9586SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 1025*9586SPeter.Dunlap@Sun.COM continue; 1026*9586SPeter.Dunlap@Sun.COM } 1027*9586SPeter.Dunlap@Sun.COM 1028*9586SPeter.Dunlap@Sun.COM /* 10297978SPeter.Dunlap@Sun.COM * If there hasn't been any activity on this 1030*9586SPeter.Dunlap@Sun.COM * connection for the keepalive timeout period 1031*9586SPeter.Dunlap@Sun.COM * and if the client has provided a keepalive 1032*9586SPeter.Dunlap@Sun.COM * callback then call the keepalive callback. 1033*9586SPeter.Dunlap@Sun.COM * This allows the client to take action to keep 1034*9586SPeter.Dunlap@Sun.COM * the link alive (like send a nop PDU). 1035*9586SPeter.Dunlap@Sun.COM */ 1036*9586SPeter.Dunlap@Sun.COM if ((TICK_TO_SEC(idle_time) >= 1037*9586SPeter.Dunlap@Sun.COM IDM_TRANSPORT_KEEPALIVE_IDLE_TIMEOUT) && 1038*9586SPeter.Dunlap@Sun.COM !ic->ic_keepalive) { 1039*9586SPeter.Dunlap@Sun.COM ic->ic_keepalive = B_TRUE; 1040*9586SPeter.Dunlap@Sun.COM if (ic->ic_conn_ops.icb_keepalive) { 1041*9586SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 1042*9586SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 1043*9586SPeter.Dunlap@Sun.COM (*ic->ic_conn_ops.icb_keepalive)(ic); 1044*9586SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 1045*9586SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 1046*9586SPeter.Dunlap@Sun.COM } 1047*9586SPeter.Dunlap@Sun.COM } else if ((TICK_TO_SEC(idle_time) < 1048*9586SPeter.Dunlap@Sun.COM IDM_TRANSPORT_KEEPALIVE_IDLE_TIMEOUT)) { 1049*9586SPeter.Dunlap@Sun.COM /* Reset keepalive */ 1050*9586SPeter.Dunlap@Sun.COM ic->ic_keepalive = B_FALSE; 1051*9586SPeter.Dunlap@Sun.COM } 1052*9586SPeter.Dunlap@Sun.COM 1053*9586SPeter.Dunlap@Sun.COM /* 1054*9586SPeter.Dunlap@Sun.COM * If there hasn't been any activity on this 1055*9586SPeter.Dunlap@Sun.COM * connection for the failure timeout period then 10567978SPeter.Dunlap@Sun.COM * drop the connection. We expect the initiator 10577978SPeter.Dunlap@Sun.COM * to keep the connection alive if it wants the 10587978SPeter.Dunlap@Sun.COM * connection to stay open. 10597978SPeter.Dunlap@Sun.COM * 10607978SPeter.Dunlap@Sun.COM * If it turns out to be desireable to take a 10617978SPeter.Dunlap@Sun.COM * more active role in maintaining the connect 10627978SPeter.Dunlap@Sun.COM * we could add a client callback to send 10637978SPeter.Dunlap@Sun.COM * a "keepalive" kind of message (no doubt a nop) 10647978SPeter.Dunlap@Sun.COM * and fire that on a shorter timer. 10657978SPeter.Dunlap@Sun.COM */ 10667978SPeter.Dunlap@Sun.COM if (TICK_TO_SEC(idle_time) > 10677978SPeter.Dunlap@Sun.COM IDM_TRANSPORT_FAIL_IDLE_TIMEOUT) { 1068*9586SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 1069*9586SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 1070*9586SPeter.Dunlap@Sun.COM IDM_SM_LOG(CE_WARN, "idm_wd_thread: " 1071*9586SPeter.Dunlap@Sun.COM "conn %p idle for %d seconds, " 1072*9586SPeter.Dunlap@Sun.COM "sending CE_TRANSPORT_FAIL", 1073*9586SPeter.Dunlap@Sun.COM (void *)ic, (int)idle_time); 1074*9586SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL); 1075*9586SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex); 1076*9586SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex); 10777978SPeter.Dunlap@Sun.COM } 1078*9586SPeter.Dunlap@Sun.COM 1079*9586SPeter.Dunlap@Sun.COM idm_conn_rele(ic); 1080*9586SPeter.Dunlap@Sun.COM 1081*9586SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex); 10827978SPeter.Dunlap@Sun.COM } 10837978SPeter.Dunlap@Sun.COM 1084*9586SPeter.Dunlap@Sun.COM wake_time = ddi_get_lbolt() + SEC_TO_TICK(IDM_WD_INTERVAL); 10857978SPeter.Dunlap@Sun.COM (void) cv_timedwait(&idm.idm_wd_cv, &idm.idm_global_mutex, 10867978SPeter.Dunlap@Sun.COM wake_time); 10877978SPeter.Dunlap@Sun.COM } 10887978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex); 10897978SPeter.Dunlap@Sun.COM 10907978SPeter.Dunlap@Sun.COM thread_exit(); 10917978SPeter.Dunlap@Sun.COM } 1092