1a6d42e7dSPeter Dunlap /* 2a6d42e7dSPeter Dunlap * CDDL HEADER START 3a6d42e7dSPeter Dunlap * 4a6d42e7dSPeter Dunlap * The contents of this file are subject to the terms of the 5a6d42e7dSPeter Dunlap * Common Development and Distribution License (the "License"). 6a6d42e7dSPeter Dunlap * You may not use this file except in compliance with the License. 7a6d42e7dSPeter Dunlap * 8a6d42e7dSPeter Dunlap * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9a6d42e7dSPeter Dunlap * or http://www.opensolaris.org/os/licensing. 10a6d42e7dSPeter Dunlap * See the License for the specific language governing permissions 11a6d42e7dSPeter Dunlap * and limitations under the License. 12a6d42e7dSPeter Dunlap * 13a6d42e7dSPeter Dunlap * When distributing Covered Code, include this CDDL HEADER in each 14a6d42e7dSPeter Dunlap * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15a6d42e7dSPeter Dunlap * If applicable, add the following below this CDDL HEADER, with the 16a6d42e7dSPeter Dunlap * fields enclosed by brackets "[]" replaced with your own identifying 17a6d42e7dSPeter Dunlap * information: Portions Copyright [yyyy] [name of copyright owner] 18a6d42e7dSPeter Dunlap * 19a6d42e7dSPeter Dunlap * CDDL HEADER END 20a6d42e7dSPeter Dunlap */ 21a6d42e7dSPeter Dunlap /* 22d618d68dSPriya Krishnan * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23*61dfa509SRick McNeal * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 24a6d42e7dSPeter Dunlap */ 25a6d42e7dSPeter Dunlap 26a6d42e7dSPeter Dunlap #include <sys/cpuvar.h> 27a6d42e7dSPeter Dunlap #include <sys/conf.h> 28a6d42e7dSPeter Dunlap #include <sys/file.h> 29a6d42e7dSPeter Dunlap #include <sys/ddi.h> 30a6d42e7dSPeter Dunlap #include <sys/sunddi.h> 31a6d42e7dSPeter Dunlap #include <sys/modctl.h> 32a6d42e7dSPeter Dunlap 33a6d42e7dSPeter Dunlap #include <sys/socket.h> 34a6d42e7dSPeter Dunlap #include <sys/strsubr.h> 35a6d42e7dSPeter Dunlap #include <sys/sysmacros.h> 36a6d42e7dSPeter Dunlap 37a6d42e7dSPeter Dunlap #include <sys/socketvar.h> 38a6d42e7dSPeter Dunlap #include <netinet/in.h> 39a6d42e7dSPeter Dunlap 40a6d42e7dSPeter Dunlap #include <sys/idm/idm.h> 41a6d42e7dSPeter Dunlap #include <sys/idm/idm_so.h> 42a6d42e7dSPeter Dunlap 43a6d42e7dSPeter Dunlap #define IDM_NAME_VERSION "iSCSI Data Mover" 44a6d42e7dSPeter Dunlap 45a6d42e7dSPeter Dunlap extern struct mod_ops mod_miscops; 46a6d42e7dSPeter Dunlap extern struct mod_ops mod_miscops; 47a6d42e7dSPeter Dunlap 48a6d42e7dSPeter Dunlap static struct modlmisc modlmisc = { 49a6d42e7dSPeter Dunlap &mod_miscops, /* Type of module */ 50a6d42e7dSPeter Dunlap IDM_NAME_VERSION 51a6d42e7dSPeter Dunlap }; 52a6d42e7dSPeter Dunlap 53a6d42e7dSPeter Dunlap static struct modlinkage modlinkage = { 54a6d42e7dSPeter Dunlap MODREV_1, (void *)&modlmisc, NULL 55a6d42e7dSPeter Dunlap }; 56a6d42e7dSPeter Dunlap 57a6d42e7dSPeter Dunlap extern void idm_wd_thread(void *arg); 58a6d42e7dSPeter Dunlap 59a6d42e7dSPeter Dunlap static int _idm_init(void); 60a6d42e7dSPeter Dunlap static int _idm_fini(void); 61a6d42e7dSPeter Dunlap static void idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf); 62a6d42e7dSPeter Dunlap static void idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf); 63a6d42e7dSPeter Dunlap static void idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf); 64a6d42e7dSPeter Dunlap static void idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf); 65*61dfa509SRick McNeal static stmf_status_t idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt, 66a6d42e7dSPeter Dunlap idm_abort_type_t abort_type); 67a6d42e7dSPeter Dunlap static void idm_task_aborted(idm_task_t *idt, idm_status_t status); 6830e7468fSPeter Dunlap static idm_pdu_t *idm_pdu_alloc_common(uint_t hdrlen, uint_t datalen, 6930e7468fSPeter Dunlap int sleepflag); 70a6d42e7dSPeter Dunlap 71a6d42e7dSPeter Dunlap boolean_t idm_conn_logging = 0; 72a6d42e7dSPeter Dunlap boolean_t idm_svc_logging = 0; 7330e7468fSPeter Dunlap #ifdef DEBUG 7430e7468fSPeter Dunlap boolean_t idm_pattern_checking = 1; 7530e7468fSPeter Dunlap #else 7630e7468fSPeter Dunlap boolean_t idm_pattern_checking = 0; 7730e7468fSPeter Dunlap #endif 78a6d42e7dSPeter Dunlap 79a6d42e7dSPeter Dunlap /* 80a6d42e7dSPeter Dunlap * Potential tuneable for the maximum number of tasks. Default to 81a6d42e7dSPeter Dunlap * IDM_TASKIDS_MAX 82a6d42e7dSPeter Dunlap */ 83a6d42e7dSPeter Dunlap 84a6d42e7dSPeter Dunlap uint32_t idm_max_taskids = IDM_TASKIDS_MAX; 85a6d42e7dSPeter Dunlap 86a6d42e7dSPeter Dunlap /* 87a6d42e7dSPeter Dunlap * Global list of transport handles 88a6d42e7dSPeter Dunlap * These are listed in preferential order, so we can simply take the 89a6d42e7dSPeter Dunlap * first "it_conn_is_capable" hit. Note also that the order maps to 90a6d42e7dSPeter Dunlap * the order of the idm_transport_type_t list. 91a6d42e7dSPeter Dunlap */ 92a6d42e7dSPeter Dunlap idm_transport_t idm_transport_list[] = { 93a6d42e7dSPeter Dunlap 94a6d42e7dSPeter Dunlap /* iSER on InfiniBand transport handle */ 95a6d42e7dSPeter Dunlap {IDM_TRANSPORT_TYPE_ISER, /* type */ 96a6d42e7dSPeter Dunlap "/devices/ib/iser@0:iser", /* device path */ 97a6d42e7dSPeter Dunlap NULL, /* LDI handle */ 98a6d42e7dSPeter Dunlap NULL, /* transport ops */ 99a6d42e7dSPeter Dunlap NULL}, /* transport caps */ 100a6d42e7dSPeter Dunlap 101a6d42e7dSPeter Dunlap /* IDM native sockets transport handle */ 102a6d42e7dSPeter Dunlap {IDM_TRANSPORT_TYPE_SOCKETS, /* type */ 103a6d42e7dSPeter Dunlap NULL, /* device path */ 104a6d42e7dSPeter Dunlap NULL, /* LDI handle */ 105a6d42e7dSPeter Dunlap NULL, /* transport ops */ 106a6d42e7dSPeter Dunlap NULL} /* transport caps */ 107a6d42e7dSPeter Dunlap 108a6d42e7dSPeter Dunlap }; 109a6d42e7dSPeter Dunlap 110a6d42e7dSPeter Dunlap int 111a6d42e7dSPeter Dunlap _init(void) 112a6d42e7dSPeter Dunlap { 113a6d42e7dSPeter Dunlap int rc; 114a6d42e7dSPeter Dunlap 115a6d42e7dSPeter Dunlap if ((rc = _idm_init()) != 0) { 116a6d42e7dSPeter Dunlap return (rc); 117a6d42e7dSPeter Dunlap } 118a6d42e7dSPeter Dunlap 119a6d42e7dSPeter Dunlap return (mod_install(&modlinkage)); 120a6d42e7dSPeter Dunlap } 121a6d42e7dSPeter Dunlap 122a6d42e7dSPeter Dunlap int 123a6d42e7dSPeter Dunlap _fini(void) 124a6d42e7dSPeter Dunlap { 125a6d42e7dSPeter Dunlap int rc; 126a6d42e7dSPeter Dunlap 127a6d42e7dSPeter Dunlap if ((rc = _idm_fini()) != 0) { 128a6d42e7dSPeter Dunlap return (rc); 129a6d42e7dSPeter Dunlap } 130a6d42e7dSPeter Dunlap 131a6d42e7dSPeter Dunlap if ((rc = mod_remove(&modlinkage)) != 0) { 132a6d42e7dSPeter Dunlap return (rc); 133a6d42e7dSPeter Dunlap } 134a6d42e7dSPeter Dunlap 135a6d42e7dSPeter Dunlap return (rc); 136a6d42e7dSPeter Dunlap } 137a6d42e7dSPeter Dunlap 138a6d42e7dSPeter Dunlap int 139a6d42e7dSPeter Dunlap _info(struct modinfo *modinfop) 140a6d42e7dSPeter Dunlap { 141a6d42e7dSPeter Dunlap return (mod_info(&modlinkage, modinfop)); 142a6d42e7dSPeter Dunlap } 143a6d42e7dSPeter Dunlap 144a6d42e7dSPeter Dunlap /* 145a6d42e7dSPeter Dunlap * idm_transport_register() 146a6d42e7dSPeter Dunlap * 147a6d42e7dSPeter Dunlap * Provides a mechanism for an IDM transport driver to register its 148a6d42e7dSPeter Dunlap * transport ops and caps with the IDM kernel module. Invoked during 149a6d42e7dSPeter Dunlap * a transport driver's attach routine. 150a6d42e7dSPeter Dunlap */ 151a6d42e7dSPeter Dunlap idm_status_t 152a6d42e7dSPeter Dunlap idm_transport_register(idm_transport_attr_t *attr) 153a6d42e7dSPeter Dunlap { 154a6d42e7dSPeter Dunlap ASSERT(attr->it_ops != NULL); 155a6d42e7dSPeter Dunlap ASSERT(attr->it_caps != NULL); 156a6d42e7dSPeter Dunlap 157a6d42e7dSPeter Dunlap switch (attr->type) { 158a6d42e7dSPeter Dunlap /* All known non-native transports here; for now, iSER */ 159a6d42e7dSPeter Dunlap case IDM_TRANSPORT_TYPE_ISER: 160a6d42e7dSPeter Dunlap idm_transport_list[attr->type].it_ops = attr->it_ops; 161a6d42e7dSPeter Dunlap idm_transport_list[attr->type].it_caps = attr->it_caps; 162a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 163a6d42e7dSPeter Dunlap 164a6d42e7dSPeter Dunlap default: 165a6d42e7dSPeter Dunlap cmn_err(CE_NOTE, "idm: unknown transport type (0x%x) in " 166a6d42e7dSPeter Dunlap "idm_transport_register", attr->type); 167a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 168a6d42e7dSPeter Dunlap } 169a6d42e7dSPeter Dunlap } 170a6d42e7dSPeter Dunlap 171a6d42e7dSPeter Dunlap /* 172a6d42e7dSPeter Dunlap * idm_ini_conn_create 173a6d42e7dSPeter Dunlap * 174a6d42e7dSPeter Dunlap * This function is invoked by the iSCSI layer to create a connection context. 175a6d42e7dSPeter Dunlap * This does not actually establish the socket connection. 176a6d42e7dSPeter Dunlap * 177a6d42e7dSPeter Dunlap * cr - Connection request parameters 178a6d42e7dSPeter Dunlap * new_con - Output parameter that contains the new request if successful 179a6d42e7dSPeter Dunlap * 180a6d42e7dSPeter Dunlap */ 181a6d42e7dSPeter Dunlap idm_status_t 182a6d42e7dSPeter Dunlap idm_ini_conn_create(idm_conn_req_t *cr, idm_conn_t **new_con) 183a6d42e7dSPeter Dunlap { 184a6d42e7dSPeter Dunlap idm_transport_t *it; 185a6d42e7dSPeter Dunlap idm_conn_t *ic; 186a6d42e7dSPeter Dunlap int rc; 187a6d42e7dSPeter Dunlap 188a6d42e7dSPeter Dunlap it = idm_transport_lookup(cr); 189a6d42e7dSPeter Dunlap 190a6d42e7dSPeter Dunlap retry: 191a6d42e7dSPeter Dunlap ic = idm_conn_create_common(CONN_TYPE_INI, it->it_type, 192a6d42e7dSPeter Dunlap &cr->icr_conn_ops); 193a6d42e7dSPeter Dunlap 194a6d42e7dSPeter Dunlap bcopy(&cr->cr_ini_dst_addr, &ic->ic_ini_dst_addr, 195a6d42e7dSPeter Dunlap sizeof (cr->cr_ini_dst_addr)); 196a6d42e7dSPeter Dunlap 197a6d42e7dSPeter Dunlap /* create the transport-specific connection components */ 198a6d42e7dSPeter Dunlap rc = it->it_ops->it_ini_conn_create(cr, ic); 199a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) { 200a6d42e7dSPeter Dunlap /* cleanup the failed connection */ 201a6d42e7dSPeter Dunlap idm_conn_destroy_common(ic); 202a6d42e7dSPeter Dunlap 203a6d42e7dSPeter Dunlap /* 204a6d42e7dSPeter Dunlap * It is possible for an IB client to connect to 205a6d42e7dSPeter Dunlap * an ethernet-only client via an IB-eth gateway. 206a6d42e7dSPeter Dunlap * Therefore, if we are attempting to use iSER and 207a6d42e7dSPeter Dunlap * fail, retry with sockets before ultimately 208a6d42e7dSPeter Dunlap * failing the connection. 209a6d42e7dSPeter Dunlap */ 210a6d42e7dSPeter Dunlap if (it->it_type == IDM_TRANSPORT_TYPE_ISER) { 211a6d42e7dSPeter Dunlap it = &idm_transport_list[IDM_TRANSPORT_TYPE_SOCKETS]; 212a6d42e7dSPeter Dunlap goto retry; 213a6d42e7dSPeter Dunlap } 214a6d42e7dSPeter Dunlap 215a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 216a6d42e7dSPeter Dunlap } 217a6d42e7dSPeter Dunlap 218a6d42e7dSPeter Dunlap *new_con = ic; 219a6d42e7dSPeter Dunlap 220a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 221a6d42e7dSPeter Dunlap list_insert_tail(&idm.idm_ini_conn_list, ic); 222a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 223a6d42e7dSPeter Dunlap 224a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 225a6d42e7dSPeter Dunlap } 226a6d42e7dSPeter Dunlap 227a6d42e7dSPeter Dunlap /* 228a6d42e7dSPeter Dunlap * idm_ini_conn_destroy 229a6d42e7dSPeter Dunlap * 230a6d42e7dSPeter Dunlap * Releases any resources associated with the connection. This is the 231a6d42e7dSPeter Dunlap * complement to idm_ini_conn_create. 232a6d42e7dSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection 233a6d42e7dSPeter Dunlap * 234a6d42e7dSPeter Dunlap */ 23530e7468fSPeter Dunlap void 23630e7468fSPeter Dunlap idm_ini_conn_destroy_task(void *ic_void) 23730e7468fSPeter Dunlap { 23830e7468fSPeter Dunlap idm_conn_t *ic = ic_void; 23930e7468fSPeter Dunlap 24030e7468fSPeter Dunlap ic->ic_transport_ops->it_ini_conn_destroy(ic); 24130e7468fSPeter Dunlap idm_conn_destroy_common(ic); 24230e7468fSPeter Dunlap } 24330e7468fSPeter Dunlap 244a6d42e7dSPeter Dunlap void 245a6d42e7dSPeter Dunlap idm_ini_conn_destroy(idm_conn_t *ic) 246a6d42e7dSPeter Dunlap { 24730e7468fSPeter Dunlap /* 24830e7468fSPeter Dunlap * It's reasonable for the initiator to call idm_ini_conn_destroy 24930e7468fSPeter Dunlap * from within the context of the CN_CONNECT_DESTROY notification. 25030e7468fSPeter Dunlap * That's a problem since we want to destroy the taskq for the 25130e7468fSPeter Dunlap * state machine associated with the connection. Remove the 25230e7468fSPeter Dunlap * connection from the list right away then handle the remaining 25330e7468fSPeter Dunlap * work via the idm_global_taskq. 25430e7468fSPeter Dunlap */ 255a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 256a6d42e7dSPeter Dunlap list_remove(&idm.idm_ini_conn_list, ic); 257a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 258a6d42e7dSPeter Dunlap 25930e7468fSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq, 260fc8ae2ecSToomas Soome &idm_ini_conn_destroy_task, ic, TQ_SLEEP) == TASKQID_INVALID) { 26130e7468fSPeter Dunlap cmn_err(CE_WARN, 26230e7468fSPeter Dunlap "idm_ini_conn_destroy: Couldn't dispatch task"); 26330e7468fSPeter Dunlap } 264a6d42e7dSPeter Dunlap } 265a6d42e7dSPeter Dunlap 266a6d42e7dSPeter Dunlap /* 267a6d42e7dSPeter Dunlap * idm_ini_conn_connect 268a6d42e7dSPeter Dunlap * 269a6d42e7dSPeter Dunlap * Establish connection to the remote system identified in idm_conn_t. 270a6d42e7dSPeter Dunlap * The connection parameters including the remote IP address were established 27130e7468fSPeter Dunlap * in the call to idm_ini_conn_create. The IDM state machine will 27230e7468fSPeter Dunlap * perform client notifications as necessary to prompt the initiator through 27330e7468fSPeter Dunlap * the login process. IDM also keeps a timer running so that if the login 27430e7468fSPeter Dunlap * process doesn't complete in a timely manner it will fail. 275a6d42e7dSPeter Dunlap * 276a6d42e7dSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection 277a6d42e7dSPeter Dunlap * 278a6d42e7dSPeter Dunlap * Returns success if the connection was established, otherwise some kind 279a6d42e7dSPeter Dunlap * of meaningful error code. 280a6d42e7dSPeter Dunlap * 28130e7468fSPeter Dunlap * Upon return the login has either failed or is loggin in (ffp) 282a6d42e7dSPeter Dunlap */ 283a6d42e7dSPeter Dunlap idm_status_t 284a6d42e7dSPeter Dunlap idm_ini_conn_connect(idm_conn_t *ic) 285a6d42e7dSPeter Dunlap { 2865f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_status_t rc; 287a6d42e7dSPeter Dunlap 288a6d42e7dSPeter Dunlap rc = idm_conn_sm_init(ic); 289a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) { 290a6d42e7dSPeter Dunlap return (ic->ic_conn_sm_status); 291a6d42e7dSPeter Dunlap } 29230e7468fSPeter Dunlap 29330e7468fSPeter Dunlap /* Hold connection until we return */ 29430e7468fSPeter Dunlap idm_conn_hold(ic); 29530e7468fSPeter Dunlap 296a6d42e7dSPeter Dunlap /* Kick state machine */ 2978e718be9SToomas Soome idm_conn_event(ic, CE_CONNECT_REQ, (uintptr_t)NULL); 298a6d42e7dSPeter Dunlap 299a6d42e7dSPeter Dunlap /* Wait for login flag */ 300a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 301a6d42e7dSPeter Dunlap while (!(ic->ic_state_flags & CF_LOGIN_READY) && 302a6d42e7dSPeter Dunlap !(ic->ic_state_flags & CF_ERROR)) { 303a6d42e7dSPeter Dunlap cv_wait(&ic->ic_state_cv, &ic->ic_state_mutex); 304a6d42e7dSPeter Dunlap } 305a6d42e7dSPeter Dunlap 3065f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 3075f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * The CN_READY_TO_LOGIN and/or the CN_CONNECT_FAIL call to 3085f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * idm_notify_client has already been generated by the idm conn 3095f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * state machine. If connection fails any time after this 3105f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * check, we will detect it in iscsi_login. 3115f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 312a6d42e7dSPeter Dunlap if (ic->ic_state_flags & CF_ERROR) { 3135f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ic->ic_conn_sm_status; 314a6d42e7dSPeter Dunlap } 3155f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&ic->ic_state_mutex); 31630e7468fSPeter Dunlap idm_conn_rele(ic); 31730e7468fSPeter Dunlap 31830e7468fSPeter Dunlap return (rc); 319a6d42e7dSPeter Dunlap } 320a6d42e7dSPeter Dunlap 321a6d42e7dSPeter Dunlap /* 32230e7468fSPeter Dunlap * idm_ini_conn_disconnect 323a6d42e7dSPeter Dunlap * 32430e7468fSPeter Dunlap * Forces a connection (previously established using idm_ini_conn_connect) 32530e7468fSPeter Dunlap * to perform a controlled shutdown, cleaning up any outstanding requests. 32630e7468fSPeter Dunlap * 32730e7468fSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection 32830e7468fSPeter Dunlap * 32930e7468fSPeter Dunlap * This is asynchronous and will return before the connection is properly 33030e7468fSPeter Dunlap * shutdown 331a6d42e7dSPeter Dunlap */ 33230e7468fSPeter Dunlap /* ARGSUSED */ 33330e7468fSPeter Dunlap void 33430e7468fSPeter Dunlap idm_ini_conn_disconnect(idm_conn_t *ic) 335a6d42e7dSPeter Dunlap { 3368e718be9SToomas Soome idm_conn_event(ic, CE_TRANSPORT_FAIL, (uintptr_t)NULL); 337a6d42e7dSPeter Dunlap } 338a6d42e7dSPeter Dunlap 339a6d42e7dSPeter Dunlap /* 34030e7468fSPeter Dunlap * idm_ini_conn_disconnect_wait 341a6d42e7dSPeter Dunlap * 342a6d42e7dSPeter Dunlap * Forces a connection (previously established using idm_ini_conn_connect) 34330e7468fSPeter Dunlap * to perform a controlled shutdown. Blocks until the connection is 34430e7468fSPeter Dunlap * disconnected. 345a6d42e7dSPeter Dunlap * 346a6d42e7dSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection 347a6d42e7dSPeter Dunlap */ 348a6d42e7dSPeter Dunlap /* ARGSUSED */ 349a6d42e7dSPeter Dunlap void 35030e7468fSPeter Dunlap idm_ini_conn_disconnect_sync(idm_conn_t *ic) 351a6d42e7dSPeter Dunlap { 352a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 35330e7468fSPeter Dunlap if ((ic->ic_state != CS_S9_INIT_ERROR) && 35430e7468fSPeter Dunlap (ic->ic_state != CS_S11_COMPLETE)) { 3558e718be9SToomas Soome idm_conn_event_locked(ic, CE_TRANSPORT_FAIL, (uintptr_t)NULL, 3568e718be9SToomas Soome CT_NONE); 35730e7468fSPeter Dunlap while ((ic->ic_state != CS_S9_INIT_ERROR) && 35830e7468fSPeter Dunlap (ic->ic_state != CS_S11_COMPLETE)) 35930e7468fSPeter Dunlap cv_wait(&ic->ic_state_cv, &ic->ic_state_mutex); 360a6d42e7dSPeter Dunlap } 361a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 362a6d42e7dSPeter Dunlap } 363a6d42e7dSPeter Dunlap 364a6d42e7dSPeter Dunlap /* 365a6d42e7dSPeter Dunlap * idm_tgt_svc_create 366a6d42e7dSPeter Dunlap * 367a6d42e7dSPeter Dunlap * The target calls this service to obtain a service context for each available 368a6d42e7dSPeter Dunlap * transport, starting a service of each type related to the IP address and port 369a6d42e7dSPeter Dunlap * passed. The idm_svc_req_t contains the service parameters. 370a6d42e7dSPeter Dunlap */ 371a6d42e7dSPeter Dunlap idm_status_t 372a6d42e7dSPeter Dunlap idm_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t **new_svc) 373a6d42e7dSPeter Dunlap { 374a6d42e7dSPeter Dunlap idm_transport_type_t type; 375a6d42e7dSPeter Dunlap idm_transport_t *it; 376a6d42e7dSPeter Dunlap idm_svc_t *is; 377a6d42e7dSPeter Dunlap int rc; 378a6d42e7dSPeter Dunlap 379a6d42e7dSPeter Dunlap *new_svc = NULL; 380a6d42e7dSPeter Dunlap is = kmem_zalloc(sizeof (idm_svc_t), KM_SLEEP); 381a6d42e7dSPeter Dunlap 382a6d42e7dSPeter Dunlap /* Initialize transport-agnostic components of the service handle */ 383a6d42e7dSPeter Dunlap is->is_svc_req = *sr; 384a6d42e7dSPeter Dunlap mutex_init(&is->is_mutex, NULL, MUTEX_DEFAULT, NULL); 385a6d42e7dSPeter Dunlap cv_init(&is->is_cv, NULL, CV_DEFAULT, NULL); 386a6d42e7dSPeter Dunlap mutex_init(&is->is_count_mutex, NULL, MUTEX_DEFAULT, NULL); 387a6d42e7dSPeter Dunlap cv_init(&is->is_count_cv, NULL, CV_DEFAULT, NULL); 388a6d42e7dSPeter Dunlap idm_refcnt_init(&is->is_refcnt, is); 389a6d42e7dSPeter Dunlap 390a6d42e7dSPeter Dunlap /* 391a6d42e7dSPeter Dunlap * Make sure all available transports are setup. We call this now 392a6d42e7dSPeter Dunlap * instead of at initialization time in case IB has become available 393a6d42e7dSPeter Dunlap * since we started (hotplug, etc). 394a6d42e7dSPeter Dunlap */ 395bbe72583SJack Meng idm_transport_setup(sr->sr_li, B_FALSE); 396a6d42e7dSPeter Dunlap 397a6d42e7dSPeter Dunlap /* 398a6d42e7dSPeter Dunlap * Loop through the transports, configuring the transport-specific 399a6d42e7dSPeter Dunlap * components of each one. 400a6d42e7dSPeter Dunlap */ 401a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 402a6d42e7dSPeter Dunlap 403a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 404a6d42e7dSPeter Dunlap /* 405a6d42e7dSPeter Dunlap * If it_ops is NULL then the transport is unconfigured 406a6d42e7dSPeter Dunlap * and we shouldn't try to start the service. 407a6d42e7dSPeter Dunlap */ 408a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 409a6d42e7dSPeter Dunlap continue; 410a6d42e7dSPeter Dunlap } 411a6d42e7dSPeter Dunlap 412a6d42e7dSPeter Dunlap rc = it->it_ops->it_tgt_svc_create(sr, is); 413a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) { 414a6d42e7dSPeter Dunlap /* Teardown any configured services */ 415a6d42e7dSPeter Dunlap while (type--) { 416a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 417a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 418a6d42e7dSPeter Dunlap continue; 419a6d42e7dSPeter Dunlap } 420a6d42e7dSPeter Dunlap it->it_ops->it_tgt_svc_destroy(is); 421a6d42e7dSPeter Dunlap } 422a6d42e7dSPeter Dunlap /* Free the svc context and return */ 423a6d42e7dSPeter Dunlap kmem_free(is, sizeof (idm_svc_t)); 424a6d42e7dSPeter Dunlap return (rc); 425a6d42e7dSPeter Dunlap } 426a6d42e7dSPeter Dunlap } 427a6d42e7dSPeter Dunlap 428a6d42e7dSPeter Dunlap *new_svc = is; 429a6d42e7dSPeter Dunlap 430a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 431a6d42e7dSPeter Dunlap list_insert_tail(&idm.idm_tgt_svc_list, is); 432a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 433a6d42e7dSPeter Dunlap 434a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 435a6d42e7dSPeter Dunlap } 436a6d42e7dSPeter Dunlap 437a6d42e7dSPeter Dunlap /* 438a6d42e7dSPeter Dunlap * idm_tgt_svc_destroy 439a6d42e7dSPeter Dunlap * 440a6d42e7dSPeter Dunlap * is - idm_svc_t returned by the call to idm_tgt_svc_create 441a6d42e7dSPeter Dunlap * 442a6d42e7dSPeter Dunlap * Cleanup any resources associated with the idm_svc_t. 443a6d42e7dSPeter Dunlap */ 444a6d42e7dSPeter Dunlap void 445a6d42e7dSPeter Dunlap idm_tgt_svc_destroy(idm_svc_t *is) 446a6d42e7dSPeter Dunlap { 447a6d42e7dSPeter Dunlap idm_transport_type_t type; 448a6d42e7dSPeter Dunlap idm_transport_t *it; 449a6d42e7dSPeter Dunlap 450a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 451a6d42e7dSPeter Dunlap /* remove this service from the global list */ 452a6d42e7dSPeter Dunlap list_remove(&idm.idm_tgt_svc_list, is); 453a6d42e7dSPeter Dunlap /* wakeup any waiters for service change */ 454a6d42e7dSPeter Dunlap cv_broadcast(&idm.idm_tgt_svc_cv); 455a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 456a6d42e7dSPeter Dunlap 457a6d42e7dSPeter Dunlap /* teardown each transport-specific service */ 458a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 459a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 460a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 461a6d42e7dSPeter Dunlap continue; 462a6d42e7dSPeter Dunlap } 463a6d42e7dSPeter Dunlap 464a6d42e7dSPeter Dunlap it->it_ops->it_tgt_svc_destroy(is); 465a6d42e7dSPeter Dunlap } 466a6d42e7dSPeter Dunlap 46730e7468fSPeter Dunlap /* tear down the svc resources */ 46830e7468fSPeter Dunlap idm_refcnt_destroy(&is->is_refcnt); 46930e7468fSPeter Dunlap cv_destroy(&is->is_count_cv); 47030e7468fSPeter Dunlap mutex_destroy(&is->is_count_mutex); 47130e7468fSPeter Dunlap cv_destroy(&is->is_cv); 47230e7468fSPeter Dunlap mutex_destroy(&is->is_mutex); 47330e7468fSPeter Dunlap 474a6d42e7dSPeter Dunlap /* free the svc handle */ 475a6d42e7dSPeter Dunlap kmem_free(is, sizeof (idm_svc_t)); 476a6d42e7dSPeter Dunlap } 477a6d42e7dSPeter Dunlap 478a6d42e7dSPeter Dunlap void 479a6d42e7dSPeter Dunlap idm_tgt_svc_hold(idm_svc_t *is) 480a6d42e7dSPeter Dunlap { 481a6d42e7dSPeter Dunlap idm_refcnt_hold(&is->is_refcnt); 482a6d42e7dSPeter Dunlap } 483a6d42e7dSPeter Dunlap 484a6d42e7dSPeter Dunlap void 485a6d42e7dSPeter Dunlap idm_tgt_svc_rele_and_destroy(idm_svc_t *is) 486a6d42e7dSPeter Dunlap { 487a6d42e7dSPeter Dunlap idm_refcnt_rele_and_destroy(&is->is_refcnt, 488a6d42e7dSPeter Dunlap (idm_refcnt_cb_t *)&idm_tgt_svc_destroy); 489a6d42e7dSPeter Dunlap } 490a6d42e7dSPeter Dunlap 491a6d42e7dSPeter Dunlap /* 492a6d42e7dSPeter Dunlap * idm_tgt_svc_online 493a6d42e7dSPeter Dunlap * 494a6d42e7dSPeter Dunlap * is - idm_svc_t returned by the call to idm_tgt_svc_create 495a6d42e7dSPeter Dunlap * 496a6d42e7dSPeter Dunlap * Online each transport service, as we want this target to be accessible 497a6d42e7dSPeter Dunlap * via any configured transport. 498a6d42e7dSPeter Dunlap * 499a6d42e7dSPeter Dunlap * When the initiator establishes a new connection to the target, IDM will 500a6d42e7dSPeter Dunlap * call the "new connect" callback defined in the idm_svc_req_t structure 501a6d42e7dSPeter Dunlap * and it will pass an idm_conn_t structure representing that new connection. 502a6d42e7dSPeter Dunlap */ 503a6d42e7dSPeter Dunlap idm_status_t 504a6d42e7dSPeter Dunlap idm_tgt_svc_online(idm_svc_t *is) 505a6d42e7dSPeter Dunlap { 506a6d42e7dSPeter Dunlap 50730e7468fSPeter Dunlap idm_transport_type_t type, last_type; 508a6d42e7dSPeter Dunlap idm_transport_t *it; 50930e7468fSPeter Dunlap int rc = IDM_STATUS_SUCCESS; 510a6d42e7dSPeter Dunlap 511a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 512a6d42e7dSPeter Dunlap if (is->is_online == 0) { 51330e7468fSPeter Dunlap /* Walk through each of the transports and online them */ 514a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 515a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 516a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 517a6d42e7dSPeter Dunlap /* transport is not registered */ 518a6d42e7dSPeter Dunlap continue; 519a6d42e7dSPeter Dunlap } 520a6d42e7dSPeter Dunlap 521a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 522a6d42e7dSPeter Dunlap rc = it->it_ops->it_tgt_svc_online(is); 523a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 52430e7468fSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) { 52530e7468fSPeter Dunlap last_type = type; 52630e7468fSPeter Dunlap break; 52730e7468fSPeter Dunlap } 52830e7468fSPeter Dunlap } 52930e7468fSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) { 53030e7468fSPeter Dunlap /* 53130e7468fSPeter Dunlap * The last transport failed to online. 53230e7468fSPeter Dunlap * Offline any transport onlined above and 53330e7468fSPeter Dunlap * do not online the target. 53430e7468fSPeter Dunlap */ 53530e7468fSPeter Dunlap for (type = 0; type < last_type; type++) { 53630e7468fSPeter Dunlap it = &idm_transport_list[type]; 53730e7468fSPeter Dunlap if (it->it_ops == NULL) { 53830e7468fSPeter Dunlap /* transport is not registered */ 53930e7468fSPeter Dunlap continue; 54030e7468fSPeter Dunlap } 54130e7468fSPeter Dunlap 54230e7468fSPeter Dunlap mutex_exit(&is->is_mutex); 54330e7468fSPeter Dunlap it->it_ops->it_tgt_svc_offline(is); 54430e7468fSPeter Dunlap mutex_enter(&is->is_mutex); 545a6d42e7dSPeter Dunlap } 54630e7468fSPeter Dunlap } else { 54730e7468fSPeter Dunlap /* Target service now online */ 54830e7468fSPeter Dunlap is->is_online = 1; 549a6d42e7dSPeter Dunlap } 550a6d42e7dSPeter Dunlap } else { 55130e7468fSPeter Dunlap /* Target service already online, just bump the count */ 552a6d42e7dSPeter Dunlap is->is_online++; 55330e7468fSPeter Dunlap } 554a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 555a6d42e7dSPeter Dunlap 55630e7468fSPeter Dunlap return (rc); 557a6d42e7dSPeter Dunlap } 558a6d42e7dSPeter Dunlap 559a6d42e7dSPeter Dunlap /* 560a6d42e7dSPeter Dunlap * idm_tgt_svc_offline 561a6d42e7dSPeter Dunlap * 562a6d42e7dSPeter Dunlap * is - idm_svc_t returned by the call to idm_tgt_svc_create 563a6d42e7dSPeter Dunlap * 564a6d42e7dSPeter Dunlap * Shutdown any online target services. 565a6d42e7dSPeter Dunlap */ 566a6d42e7dSPeter Dunlap void 567a6d42e7dSPeter Dunlap idm_tgt_svc_offline(idm_svc_t *is) 568a6d42e7dSPeter Dunlap { 569a6d42e7dSPeter Dunlap idm_transport_type_t type; 570a6d42e7dSPeter Dunlap idm_transport_t *it; 571a6d42e7dSPeter Dunlap 572a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 573a6d42e7dSPeter Dunlap is->is_online--; 574a6d42e7dSPeter Dunlap if (is->is_online == 0) { 575a6d42e7dSPeter Dunlap /* Walk through each of the transports and offline them */ 576a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 577a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 578a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 579a6d42e7dSPeter Dunlap /* transport is not registered */ 580a6d42e7dSPeter Dunlap continue; 581a6d42e7dSPeter Dunlap } 582a6d42e7dSPeter Dunlap 583a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 584a6d42e7dSPeter Dunlap it->it_ops->it_tgt_svc_offline(is); 585a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 586a6d42e7dSPeter Dunlap } 587a6d42e7dSPeter Dunlap } 588a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 589a6d42e7dSPeter Dunlap } 590a6d42e7dSPeter Dunlap 591a6d42e7dSPeter Dunlap /* 592a6d42e7dSPeter Dunlap * idm_tgt_svc_lookup 593a6d42e7dSPeter Dunlap * 594a6d42e7dSPeter Dunlap * Lookup a service instance listening on the specified port 595a6d42e7dSPeter Dunlap */ 596a6d42e7dSPeter Dunlap 597a6d42e7dSPeter Dunlap idm_svc_t * 598a6d42e7dSPeter Dunlap idm_tgt_svc_lookup(uint16_t port) 599a6d42e7dSPeter Dunlap { 600a6d42e7dSPeter Dunlap idm_svc_t *result; 601a6d42e7dSPeter Dunlap 602a6d42e7dSPeter Dunlap retry: 603a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 604a6d42e7dSPeter Dunlap for (result = list_head(&idm.idm_tgt_svc_list); 605a6d42e7dSPeter Dunlap result != NULL; 606a6d42e7dSPeter Dunlap result = list_next(&idm.idm_tgt_svc_list, result)) { 607a6d42e7dSPeter Dunlap if (result->is_svc_req.sr_port == port) { 608a6d42e7dSPeter Dunlap if (result->is_online == 0) { 609a6d42e7dSPeter Dunlap /* 610a6d42e7dSPeter Dunlap * A service exists on this port, but it 611a6d42e7dSPeter Dunlap * is going away, wait for it to cleanup. 612a6d42e7dSPeter Dunlap */ 613a6d42e7dSPeter Dunlap cv_wait(&idm.idm_tgt_svc_cv, 614a6d42e7dSPeter Dunlap &idm.idm_global_mutex); 615a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 616a6d42e7dSPeter Dunlap goto retry; 617a6d42e7dSPeter Dunlap } 618a6d42e7dSPeter Dunlap idm_tgt_svc_hold(result); 619a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 620a6d42e7dSPeter Dunlap return (result); 621a6d42e7dSPeter Dunlap } 622a6d42e7dSPeter Dunlap } 623a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 624a6d42e7dSPeter Dunlap 625a6d42e7dSPeter Dunlap return (NULL); 626a6d42e7dSPeter Dunlap } 627a6d42e7dSPeter Dunlap 628a6d42e7dSPeter Dunlap /* 629a6d42e7dSPeter Dunlap * idm_negotiate_key_values() 630a6d42e7dSPeter Dunlap * Give IDM level a chance to negotiate any login parameters it should own. 631a6d42e7dSPeter Dunlap * -- leave unhandled parameters alone on request_nvl 632a6d42e7dSPeter Dunlap * -- move all handled parameters to response_nvl with an appropriate response 633a6d42e7dSPeter Dunlap * -- also add an entry to negotiated_nvl for any accepted parameters 634a6d42e7dSPeter Dunlap */ 635a6d42e7dSPeter Dunlap kv_status_t 636a6d42e7dSPeter Dunlap idm_negotiate_key_values(idm_conn_t *ic, nvlist_t *request_nvl, 637a6d42e7dSPeter Dunlap nvlist_t *response_nvl, nvlist_t *negotiated_nvl) 638a6d42e7dSPeter Dunlap { 639a6d42e7dSPeter Dunlap ASSERT(ic->ic_transport_ops != NULL); 640a6d42e7dSPeter Dunlap return (ic->ic_transport_ops->it_negotiate_key_values(ic, 641a6d42e7dSPeter Dunlap request_nvl, response_nvl, negotiated_nvl)); 642a6d42e7dSPeter Dunlap } 643a6d42e7dSPeter Dunlap 644a6d42e7dSPeter Dunlap /* 645a6d42e7dSPeter Dunlap * idm_notice_key_values() 646a6d42e7dSPeter Dunlap * Activate at the IDM level any parameters that have been negotiated. 647a6d42e7dSPeter Dunlap * Passes the set of key value pairs to the transport for activation. 648a6d42e7dSPeter Dunlap * This will be invoked as the connection is entering full-feature mode. 649a6d42e7dSPeter Dunlap */ 65030e7468fSPeter Dunlap void 651a6d42e7dSPeter Dunlap idm_notice_key_values(idm_conn_t *ic, nvlist_t *negotiated_nvl) 652a6d42e7dSPeter Dunlap { 653a6d42e7dSPeter Dunlap ASSERT(ic->ic_transport_ops != NULL); 65430e7468fSPeter Dunlap ic->ic_transport_ops->it_notice_key_values(ic, negotiated_nvl); 655a6d42e7dSPeter Dunlap } 656a6d42e7dSPeter Dunlap 65756261083SCharles Ting /* 65856261083SCharles Ting * idm_declare_key_values() 65956261083SCharles Ting * Activate an operational set of declarative parameters from the config_nvl, 66056261083SCharles Ting * and return the selected values in the outgoing_nvl. 66156261083SCharles Ting */ 66256261083SCharles Ting kv_status_t 66356261083SCharles Ting idm_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl, 66456261083SCharles Ting nvlist_t *outgoing_nvl) 66556261083SCharles Ting { 66656261083SCharles Ting ASSERT(ic->ic_transport_ops != NULL); 66756261083SCharles Ting return (ic->ic_transport_ops->it_declare_key_values(ic, config_nvl, 66856261083SCharles Ting outgoing_nvl)); 66956261083SCharles Ting } 67056261083SCharles Ting 671a6d42e7dSPeter Dunlap /* 672a6d42e7dSPeter Dunlap * idm_buf_tx_to_ini 673a6d42e7dSPeter Dunlap * 674a6d42e7dSPeter Dunlap * This is IDM's implementation of the 'Put_Data' operational primitive. 675a6d42e7dSPeter Dunlap * 676a6d42e7dSPeter Dunlap * This function is invoked by a target iSCSI layer to request its local 677a6d42e7dSPeter Dunlap * Datamover layer to transmit the Data-In PDU to the peer iSCSI layer 678a6d42e7dSPeter Dunlap * on the remote iSCSI node. The I/O buffer represented by 'idb' is 679a6d42e7dSPeter Dunlap * transferred to the initiator associated with task 'idt'. The connection 680a6d42e7dSPeter Dunlap * info, contents of the Data-In PDU header, the DataDescriptorIn, BHS, 681a6d42e7dSPeter Dunlap * and the callback (idb->idb_buf_cb) at transfer completion are 682a6d42e7dSPeter Dunlap * provided as input. 683a6d42e7dSPeter Dunlap * 684a6d42e7dSPeter Dunlap * This data transfer takes place transparently to the remote iSCSI layer, 685a6d42e7dSPeter Dunlap * i.e. without its participation. 686a6d42e7dSPeter Dunlap * 687a6d42e7dSPeter Dunlap * Using sockets, IDM implements the data transfer by segmenting the data 688a6d42e7dSPeter Dunlap * buffer into appropriately sized iSCSI PDUs and transmitting them to the 689a6d42e7dSPeter Dunlap * initiator. iSER performs the transfer using RDMA write. 690a6d42e7dSPeter Dunlap * 691a6d42e7dSPeter Dunlap */ 692a6d42e7dSPeter Dunlap idm_status_t 693a6d42e7dSPeter Dunlap idm_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb, 694a6d42e7dSPeter Dunlap uint32_t offset, uint32_t xfer_len, 695a6d42e7dSPeter Dunlap idm_buf_cb_t idb_buf_cb, void *cb_arg) 696a6d42e7dSPeter Dunlap { 697a6d42e7dSPeter Dunlap idm_status_t rc; 698a6d42e7dSPeter Dunlap 699a6d42e7dSPeter Dunlap idb->idb_bufoffset = offset; 700a6d42e7dSPeter Dunlap idb->idb_xfer_len = xfer_len; 701a6d42e7dSPeter Dunlap idb->idb_buf_cb = idb_buf_cb; 702a6d42e7dSPeter Dunlap idb->idb_cb_arg = cb_arg; 70330e7468fSPeter Dunlap gethrestime(&idb->idb_xfer_start); 70430e7468fSPeter Dunlap 70530e7468fSPeter Dunlap /* 70630e7468fSPeter Dunlap * Buffer should not contain the pattern. If the pattern is 70730e7468fSPeter Dunlap * present then we've been asked to transmit initialized data 70830e7468fSPeter Dunlap */ 70930e7468fSPeter Dunlap IDM_BUFPAT_CHECK(idb, xfer_len, BP_CHECK_ASSERT); 710a6d42e7dSPeter Dunlap 711a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 712a6d42e7dSPeter Dunlap switch (idt->idt_state) { 713a6d42e7dSPeter Dunlap case TASK_ACTIVE: 714a6d42e7dSPeter Dunlap idt->idt_tx_to_ini_start++; 715a6d42e7dSPeter Dunlap idm_task_hold(idt); 716a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idt, idb); 717a6d42e7dSPeter Dunlap idb->idb_in_transport = B_TRUE; 718a6d42e7dSPeter Dunlap rc = (*idt->idt_ic->ic_transport_ops->it_buf_tx_to_ini) 719a6d42e7dSPeter Dunlap (idt, idb); 720a6d42e7dSPeter Dunlap return (rc); 721a6d42e7dSPeter Dunlap 722a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 723a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 724a6d42e7dSPeter Dunlap /* 725a6d42e7dSPeter Dunlap * Bind buffer but don't start a transfer since the task 726a6d42e7dSPeter Dunlap * is suspended 727a6d42e7dSPeter Dunlap */ 728a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idt, idb); 729a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 730a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 731a6d42e7dSPeter Dunlap 732a6d42e7dSPeter Dunlap case TASK_ABORTING: 733a6d42e7dSPeter Dunlap case TASK_ABORTED: 734a6d42e7dSPeter Dunlap /* 735a6d42e7dSPeter Dunlap * Once the task is aborted, any buffers added to the 736a6d42e7dSPeter Dunlap * idt_inbufv will never get cleaned up, so just return 737a6d42e7dSPeter Dunlap * SUCCESS. The buffer should get cleaned up by the 738a6d42e7dSPeter Dunlap * client or framework once task_aborted has completed. 739a6d42e7dSPeter Dunlap */ 740a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 741a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 742a6d42e7dSPeter Dunlap 743a6d42e7dSPeter Dunlap default: 744a6d42e7dSPeter Dunlap ASSERT(0); 745a6d42e7dSPeter Dunlap break; 746a6d42e7dSPeter Dunlap } 747a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 748a6d42e7dSPeter Dunlap 749a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 750a6d42e7dSPeter Dunlap } 751a6d42e7dSPeter Dunlap 752a6d42e7dSPeter Dunlap /* 753a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini 754a6d42e7dSPeter Dunlap * 755a6d42e7dSPeter Dunlap * This is IDM's implementation of the 'Get_Data' operational primitive. 756a6d42e7dSPeter Dunlap * 757a6d42e7dSPeter Dunlap * This function is invoked by a target iSCSI layer to request its local 758a6d42e7dSPeter Dunlap * Datamover layer to retrieve certain data identified by the R2T PDU from the 759a6d42e7dSPeter Dunlap * peer iSCSI layer on the remote node. The retrieved Data-Out PDU will be 760a6d42e7dSPeter Dunlap * mapped to the respective buffer by the task tags (ITT & TTT). 761a6d42e7dSPeter Dunlap * The connection information, contents of an R2T PDU, DataDescriptor, BHS, and 762a6d42e7dSPeter Dunlap * the callback (idb->idb_buf_cb) notification for data transfer completion are 763a6d42e7dSPeter Dunlap * are provided as input. 764a6d42e7dSPeter Dunlap * 765a6d42e7dSPeter Dunlap * When an iSCSI node sends an R2T PDU to its local Datamover layer, the local 766a6d42e7dSPeter Dunlap * Datamover layer, the local and remote Datamover layers transparently bring 767a6d42e7dSPeter Dunlap * about the data transfer requested by the R2T PDU, without the participation 768a6d42e7dSPeter Dunlap * of the iSCSI layers. 769a6d42e7dSPeter Dunlap * 770a6d42e7dSPeter Dunlap * Using sockets, IDM transmits an R2T PDU for each buffer and the rx_data_out() 771a6d42e7dSPeter Dunlap * assembles the Data-Out PDUs into the buffer. iSER uses RDMA read. 772a6d42e7dSPeter Dunlap * 773a6d42e7dSPeter Dunlap */ 774a6d42e7dSPeter Dunlap idm_status_t 775a6d42e7dSPeter Dunlap idm_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb, 776a6d42e7dSPeter Dunlap uint32_t offset, uint32_t xfer_len, 777a6d42e7dSPeter Dunlap idm_buf_cb_t idb_buf_cb, void *cb_arg) 778a6d42e7dSPeter Dunlap { 779a6d42e7dSPeter Dunlap idm_status_t rc; 780a6d42e7dSPeter Dunlap 781a6d42e7dSPeter Dunlap idb->idb_bufoffset = offset; 782a6d42e7dSPeter Dunlap idb->idb_xfer_len = xfer_len; 783a6d42e7dSPeter Dunlap idb->idb_buf_cb = idb_buf_cb; 784a6d42e7dSPeter Dunlap idb->idb_cb_arg = cb_arg; 78530e7468fSPeter Dunlap gethrestime(&idb->idb_xfer_start); 786a6d42e7dSPeter Dunlap 787a6d42e7dSPeter Dunlap /* 788a6d42e7dSPeter Dunlap * "In" buf list is for "Data In" PDU's, "Out" buf list is for 789a6d42e7dSPeter Dunlap * "Data Out" PDU's 790a6d42e7dSPeter Dunlap */ 791a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 792a6d42e7dSPeter Dunlap switch (idt->idt_state) { 793a6d42e7dSPeter Dunlap case TASK_ACTIVE: 794a6d42e7dSPeter Dunlap idt->idt_rx_from_ini_start++; 795a6d42e7dSPeter Dunlap idm_task_hold(idt); 796a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idt, idb); 797a6d42e7dSPeter Dunlap idb->idb_in_transport = B_TRUE; 798a6d42e7dSPeter Dunlap rc = (*idt->idt_ic->ic_transport_ops->it_buf_rx_from_ini) 799a6d42e7dSPeter Dunlap (idt, idb); 800a6d42e7dSPeter Dunlap return (rc); 801a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 802a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 803a6d42e7dSPeter Dunlap case TASK_ABORTING: 804a6d42e7dSPeter Dunlap case TASK_ABORTED: 805a6d42e7dSPeter Dunlap /* 806a6d42e7dSPeter Dunlap * Bind buffer but don't start a transfer since the task 807a6d42e7dSPeter Dunlap * is suspended 808a6d42e7dSPeter Dunlap */ 809a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idt, idb); 810a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 811a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 812a6d42e7dSPeter Dunlap default: 813a6d42e7dSPeter Dunlap ASSERT(0); 814a6d42e7dSPeter Dunlap break; 815a6d42e7dSPeter Dunlap } 816a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 817a6d42e7dSPeter Dunlap 818a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 819a6d42e7dSPeter Dunlap } 820a6d42e7dSPeter Dunlap 821a6d42e7dSPeter Dunlap /* 822a6d42e7dSPeter Dunlap * idm_buf_tx_to_ini_done 823a6d42e7dSPeter Dunlap * 824a6d42e7dSPeter Dunlap * The transport calls this after it has completed a transfer requested by 825a6d42e7dSPeter Dunlap * a call to transport_buf_tx_to_ini 826a6d42e7dSPeter Dunlap * 827a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex, idt->idt_mutex is released before returning. 828a6d42e7dSPeter Dunlap * idt may be freed after the call to idb->idb_buf_cb. 829a6d42e7dSPeter Dunlap */ 830a6d42e7dSPeter Dunlap void 831a6d42e7dSPeter Dunlap idm_buf_tx_to_ini_done(idm_task_t *idt, idm_buf_t *idb, idm_status_t status) 832a6d42e7dSPeter Dunlap { 833a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 834a6d42e7dSPeter Dunlap idb->idb_in_transport = B_FALSE; 835a6d42e7dSPeter Dunlap idb->idb_tx_thread = B_FALSE; 836a6d42e7dSPeter Dunlap idt->idt_tx_to_ini_done++; 83730e7468fSPeter Dunlap gethrestime(&idb->idb_xfer_done); 838a6d42e7dSPeter Dunlap 839a6d42e7dSPeter Dunlap /* 840a6d42e7dSPeter Dunlap * idm_refcnt_rele may cause TASK_SUSPENDING --> TASK_SUSPENDED or 841a6d42e7dSPeter Dunlap * TASK_ABORTING --> TASK_ABORTED transistion if the refcount goes 842a6d42e7dSPeter Dunlap * to 0. 843a6d42e7dSPeter Dunlap */ 844a6d42e7dSPeter Dunlap idm_task_rele(idt); 845a6d42e7dSPeter Dunlap idb->idb_status = status; 846a6d42e7dSPeter Dunlap 847a6d42e7dSPeter Dunlap switch (idt->idt_state) { 848a6d42e7dSPeter Dunlap case TASK_ACTIVE: 84972cf3143Speter dunlap idt->idt_ic->ic_timestamp = ddi_get_lbolt(); 850a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idt, idb); 851a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 852a6d42e7dSPeter Dunlap (*idb->idb_buf_cb)(idb, status); 853a6d42e7dSPeter Dunlap return; 854a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 855a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 856a6d42e7dSPeter Dunlap case TASK_ABORTING: 857a6d42e7dSPeter Dunlap case TASK_ABORTED: 858a6d42e7dSPeter Dunlap /* 859a6d42e7dSPeter Dunlap * To keep things simple we will ignore the case where the 860a6d42e7dSPeter Dunlap * transfer was successful and leave all buffers bound to the 861a6d42e7dSPeter Dunlap * task. This allows us to also ignore the case where we've 862a6d42e7dSPeter Dunlap * been asked to abort a task but the last transfer of the 863a6d42e7dSPeter Dunlap * task has completed. IDM has no idea whether this was, in 864a6d42e7dSPeter Dunlap * fact, the last transfer of the task so it would be difficult 865a6d42e7dSPeter Dunlap * to handle this case. Everything should get sorted out again 866a6d42e7dSPeter Dunlap * after task reassignment is complete. 867a6d42e7dSPeter Dunlap * 868a6d42e7dSPeter Dunlap * In the case of TASK_ABORTING we could conceivably call the 869a6d42e7dSPeter Dunlap * buffer callback here but the timing of when the client's 870a6d42e7dSPeter Dunlap * client_task_aborted callback is invoked vs. when the client's 871a6d42e7dSPeter Dunlap * buffer callback gets invoked gets sticky. We don't want 872a6d42e7dSPeter Dunlap * the client to here from us again after the call to 873a6d42e7dSPeter Dunlap * client_task_aborted() but we don't want to give it a bunch 874a6d42e7dSPeter Dunlap * of failed buffer transfers until we've called 875a6d42e7dSPeter Dunlap * client_task_aborted(). Instead we'll just leave all the 876a6d42e7dSPeter Dunlap * buffers bound and allow the client to cleanup. 877a6d42e7dSPeter Dunlap */ 878a6d42e7dSPeter Dunlap break; 879a6d42e7dSPeter Dunlap default: 880a6d42e7dSPeter Dunlap ASSERT(0); 881a6d42e7dSPeter Dunlap } 882a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 883a6d42e7dSPeter Dunlap } 884a6d42e7dSPeter Dunlap 885a6d42e7dSPeter Dunlap /* 886a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done 887a6d42e7dSPeter Dunlap * 888a6d42e7dSPeter Dunlap * The transport calls this after it has completed a transfer requested by 889a6d42e7dSPeter Dunlap * a call totransport_buf_tx_to_ini 890a6d42e7dSPeter Dunlap * 891a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex, idt->idt_mutex is released before returning. 892a6d42e7dSPeter Dunlap * idt may be freed after the call to idb->idb_buf_cb. 893a6d42e7dSPeter Dunlap */ 894a6d42e7dSPeter Dunlap void 895a6d42e7dSPeter Dunlap idm_buf_rx_from_ini_done(idm_task_t *idt, idm_buf_t *idb, idm_status_t status) 896a6d42e7dSPeter Dunlap { 897a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 898a6d42e7dSPeter Dunlap idb->idb_in_transport = B_FALSE; 899a6d42e7dSPeter Dunlap idt->idt_rx_from_ini_done++; 90030e7468fSPeter Dunlap gethrestime(&idb->idb_xfer_done); 901a6d42e7dSPeter Dunlap 902a6d42e7dSPeter Dunlap /* 903a6d42e7dSPeter Dunlap * idm_refcnt_rele may cause TASK_SUSPENDING --> TASK_SUSPENDED or 904a6d42e7dSPeter Dunlap * TASK_ABORTING --> TASK_ABORTED transistion if the refcount goes 905a6d42e7dSPeter Dunlap * to 0. 906a6d42e7dSPeter Dunlap */ 907a6d42e7dSPeter Dunlap idm_task_rele(idt); 908a6d42e7dSPeter Dunlap idb->idb_status = status; 909a6d42e7dSPeter Dunlap 91030e7468fSPeter Dunlap if (status == IDM_STATUS_SUCCESS) { 91130e7468fSPeter Dunlap /* 91230e7468fSPeter Dunlap * Buffer should not contain the pattern. If it does then 91330e7468fSPeter Dunlap * we did not get the data from the remote host. 91430e7468fSPeter Dunlap */ 91530e7468fSPeter Dunlap IDM_BUFPAT_CHECK(idb, idb->idb_xfer_len, BP_CHECK_ASSERT); 91630e7468fSPeter Dunlap } 91730e7468fSPeter Dunlap 918a6d42e7dSPeter Dunlap switch (idt->idt_state) { 919a6d42e7dSPeter Dunlap case TASK_ACTIVE: 92072cf3143Speter dunlap idt->idt_ic->ic_timestamp = ddi_get_lbolt(); 921a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idt, idb); 922a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 923a6d42e7dSPeter Dunlap (*idb->idb_buf_cb)(idb, status); 924a6d42e7dSPeter Dunlap return; 925a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 926a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 927a6d42e7dSPeter Dunlap case TASK_ABORTING: 928a6d42e7dSPeter Dunlap case TASK_ABORTED: 929a6d42e7dSPeter Dunlap /* 930a6d42e7dSPeter Dunlap * To keep things simple we will ignore the case where the 931a6d42e7dSPeter Dunlap * transfer was successful and leave all buffers bound to the 932a6d42e7dSPeter Dunlap * task. This allows us to also ignore the case where we've 933a6d42e7dSPeter Dunlap * been asked to abort a task but the last transfer of the 934a6d42e7dSPeter Dunlap * task has completed. IDM has no idea whether this was, in 935a6d42e7dSPeter Dunlap * fact, the last transfer of the task so it would be difficult 936a6d42e7dSPeter Dunlap * to handle this case. Everything should get sorted out again 937a6d42e7dSPeter Dunlap * after task reassignment is complete. 938a6d42e7dSPeter Dunlap * 939a6d42e7dSPeter Dunlap * In the case of TASK_ABORTING we could conceivably call the 940a6d42e7dSPeter Dunlap * buffer callback here but the timing of when the client's 941a6d42e7dSPeter Dunlap * client_task_aborted callback is invoked vs. when the client's 942a6d42e7dSPeter Dunlap * buffer callback gets invoked gets sticky. We don't want 943a6d42e7dSPeter Dunlap * the client to here from us again after the call to 944a6d42e7dSPeter Dunlap * client_task_aborted() but we don't want to give it a bunch 945a6d42e7dSPeter Dunlap * of failed buffer transfers until we've called 946a6d42e7dSPeter Dunlap * client_task_aborted(). Instead we'll just leave all the 947a6d42e7dSPeter Dunlap * buffers bound and allow the client to cleanup. 948a6d42e7dSPeter Dunlap */ 949a6d42e7dSPeter Dunlap break; 950a6d42e7dSPeter Dunlap default: 951a6d42e7dSPeter Dunlap ASSERT(0); 952a6d42e7dSPeter Dunlap } 953a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 954a6d42e7dSPeter Dunlap } 955a6d42e7dSPeter Dunlap 956a6d42e7dSPeter Dunlap /* 957a6d42e7dSPeter Dunlap * idm_buf_alloc 958a6d42e7dSPeter Dunlap * 959a6d42e7dSPeter Dunlap * Allocates a buffer handle and registers it for use with the transport 960a6d42e7dSPeter Dunlap * layer. If a buffer is not passed on bufptr, the buffer will be allocated 961a6d42e7dSPeter Dunlap * as well as the handle. 962a6d42e7dSPeter Dunlap * 963a6d42e7dSPeter Dunlap * ic - connection on which the buffer will be transferred 964a6d42e7dSPeter Dunlap * bufptr - allocate memory for buffer if NULL, else assign to buffer 965a6d42e7dSPeter Dunlap * buflen - length of buffer 966a6d42e7dSPeter Dunlap * 967a6d42e7dSPeter Dunlap * Returns idm_buf_t handle if successful, otherwise NULL 968a6d42e7dSPeter Dunlap */ 969a6d42e7dSPeter Dunlap idm_buf_t * 970a6d42e7dSPeter Dunlap idm_buf_alloc(idm_conn_t *ic, void *bufptr, uint64_t buflen) 971a6d42e7dSPeter Dunlap { 972a6d42e7dSPeter Dunlap idm_buf_t *buf = NULL; 973a6d42e7dSPeter Dunlap int rc; 974a6d42e7dSPeter Dunlap 975a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 976a6d42e7dSPeter Dunlap ASSERT(idm.idm_buf_cache != NULL); 977a6d42e7dSPeter Dunlap ASSERT(buflen > 0); 978a6d42e7dSPeter Dunlap 979a6d42e7dSPeter Dunlap /* Don't allocate new buffers if we are not in FFP */ 980a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 981a6d42e7dSPeter Dunlap if (!ic->ic_ffp) { 982a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 983a6d42e7dSPeter Dunlap return (NULL); 984a6d42e7dSPeter Dunlap } 985a6d42e7dSPeter Dunlap 986a6d42e7dSPeter Dunlap 987a6d42e7dSPeter Dunlap idm_conn_hold(ic); 988a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 989a6d42e7dSPeter Dunlap 990a6d42e7dSPeter Dunlap buf = kmem_cache_alloc(idm.idm_buf_cache, KM_NOSLEEP); 991a6d42e7dSPeter Dunlap if (buf == NULL) { 992a6d42e7dSPeter Dunlap idm_conn_rele(ic); 993a6d42e7dSPeter Dunlap return (NULL); 994a6d42e7dSPeter Dunlap } 995a6d42e7dSPeter Dunlap 996a6d42e7dSPeter Dunlap buf->idb_ic = ic; 997a6d42e7dSPeter Dunlap buf->idb_buflen = buflen; 998a6d42e7dSPeter Dunlap buf->idb_exp_offset = 0; 999a6d42e7dSPeter Dunlap buf->idb_bufoffset = 0; 10008e718be9SToomas Soome buf->idb_xfer_len = 0; 1001a6d42e7dSPeter Dunlap buf->idb_magic = IDM_BUF_MAGIC; 100230e7468fSPeter Dunlap buf->idb_in_transport = B_FALSE; 100330e7468fSPeter Dunlap buf->idb_bufbcopy = B_FALSE; 1004a6d42e7dSPeter Dunlap 1005a6d42e7dSPeter Dunlap /* 1006a6d42e7dSPeter Dunlap * If bufptr is NULL, we have an implicit request to allocate 1007a6d42e7dSPeter Dunlap * memory for this IDM buffer handle and register it for use 1008a6d42e7dSPeter Dunlap * with the transport. To simplify this, and to give more freedom 1009a6d42e7dSPeter Dunlap * to the transport layer for it's own buffer management, both of 1010a6d42e7dSPeter Dunlap * these actions will take place in the transport layer. 1011a6d42e7dSPeter Dunlap * If bufptr is set, then the caller has allocated memory (or more 1012a6d42e7dSPeter Dunlap * likely it's been passed from an upper layer), and we need only 1013a6d42e7dSPeter Dunlap * register the buffer for use with the transport layer. 1014a6d42e7dSPeter Dunlap */ 1015a6d42e7dSPeter Dunlap if (bufptr == NULL) { 1016a6d42e7dSPeter Dunlap /* 1017a6d42e7dSPeter Dunlap * Allocate a buffer from the transport layer (which 1018a6d42e7dSPeter Dunlap * will also register the buffer for use). 1019a6d42e7dSPeter Dunlap */ 1020a6d42e7dSPeter Dunlap rc = ic->ic_transport_ops->it_buf_alloc(buf, buflen); 1021a6d42e7dSPeter Dunlap if (rc != 0) { 1022a6d42e7dSPeter Dunlap idm_conn_rele(ic); 1023a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_buf_cache, buf); 1024a6d42e7dSPeter Dunlap return (NULL); 1025a6d42e7dSPeter Dunlap } 1026a6d42e7dSPeter Dunlap /* Set the bufalloc'd flag */ 1027a6d42e7dSPeter Dunlap buf->idb_bufalloc = B_TRUE; 1028a6d42e7dSPeter Dunlap } else { 1029a6d42e7dSPeter Dunlap /* 103030e7468fSPeter Dunlap * For large transfers, Set the passed bufptr into 103130e7468fSPeter Dunlap * the buf handle, and register the handle with the 103230e7468fSPeter Dunlap * transport layer. As memory registration with the 103330e7468fSPeter Dunlap * transport layer is a time/cpu intensive operation, 103430e7468fSPeter Dunlap * for small transfers (up to a pre-defined bcopy 103530e7468fSPeter Dunlap * threshold), use pre-registered memory buffers 103630e7468fSPeter Dunlap * and bcopy data at the appropriate time. 1037a6d42e7dSPeter Dunlap */ 1038a6d42e7dSPeter Dunlap buf->idb_buf = bufptr; 1039a6d42e7dSPeter Dunlap 1040a6d42e7dSPeter Dunlap rc = ic->ic_transport_ops->it_buf_setup(buf); 1041a6d42e7dSPeter Dunlap if (rc != 0) { 1042a6d42e7dSPeter Dunlap idm_conn_rele(ic); 1043a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_buf_cache, buf); 1044a6d42e7dSPeter Dunlap return (NULL); 1045a6d42e7dSPeter Dunlap } 104630e7468fSPeter Dunlap /* 104730e7468fSPeter Dunlap * The transport layer is now expected to set the idb_bufalloc 104830e7468fSPeter Dunlap * correctly to indicate if resources have been allocated. 104930e7468fSPeter Dunlap */ 1050a6d42e7dSPeter Dunlap } 1051a6d42e7dSPeter Dunlap 105230e7468fSPeter Dunlap IDM_BUFPAT_SET(buf); 1053a6d42e7dSPeter Dunlap 105430e7468fSPeter Dunlap return (buf); 1055a6d42e7dSPeter Dunlap } 1056a6d42e7dSPeter Dunlap 1057a6d42e7dSPeter Dunlap /* 1058a6d42e7dSPeter Dunlap * idm_buf_free 1059a6d42e7dSPeter Dunlap * 1060a6d42e7dSPeter Dunlap * Release a buffer handle along with the associated buffer that was allocated 1061a6d42e7dSPeter Dunlap * or assigned with idm_buf_alloc 1062a6d42e7dSPeter Dunlap */ 1063a6d42e7dSPeter Dunlap void 1064a6d42e7dSPeter Dunlap idm_buf_free(idm_buf_t *buf) 1065a6d42e7dSPeter Dunlap { 1066a6d42e7dSPeter Dunlap idm_conn_t *ic = buf->idb_ic; 1067a6d42e7dSPeter Dunlap 1068a6d42e7dSPeter Dunlap 1069a6d42e7dSPeter Dunlap buf->idb_task_binding = NULL; 1070a6d42e7dSPeter Dunlap 1071a6d42e7dSPeter Dunlap if (buf->idb_bufalloc) { 1072a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_buf_free(buf); 1073a6d42e7dSPeter Dunlap } else { 1074a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_buf_teardown(buf); 1075a6d42e7dSPeter Dunlap } 1076a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_buf_cache, buf); 1077a6d42e7dSPeter Dunlap idm_conn_rele(ic); 1078a6d42e7dSPeter Dunlap } 1079a6d42e7dSPeter Dunlap 1080a6d42e7dSPeter Dunlap /* 1081a6d42e7dSPeter Dunlap * idm_buf_bind_in 1082a6d42e7dSPeter Dunlap * 1083a6d42e7dSPeter Dunlap * This function associates a buffer with a task. This is only for use by the 1084a6d42e7dSPeter Dunlap * iSCSI initiator that will have only one buffer per transfer direction 1085a6d42e7dSPeter Dunlap * 1086a6d42e7dSPeter Dunlap */ 1087a6d42e7dSPeter Dunlap void 1088a6d42e7dSPeter Dunlap idm_buf_bind_in(idm_task_t *idt, idm_buf_t *buf) 1089a6d42e7dSPeter Dunlap { 1090a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1091a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idt, buf); 1092a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1093a6d42e7dSPeter Dunlap } 1094a6d42e7dSPeter Dunlap 1095a6d42e7dSPeter Dunlap static void 1096a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf) 1097a6d42e7dSPeter Dunlap { 1098a6d42e7dSPeter Dunlap buf->idb_task_binding = idt; 1099a6d42e7dSPeter Dunlap buf->idb_ic = idt->idt_ic; 1100a6d42e7dSPeter Dunlap idm_listbuf_insert(&idt->idt_inbufv, buf); 1101a6d42e7dSPeter Dunlap } 1102a6d42e7dSPeter Dunlap 1103a6d42e7dSPeter Dunlap void 1104a6d42e7dSPeter Dunlap idm_buf_bind_out(idm_task_t *idt, idm_buf_t *buf) 1105a6d42e7dSPeter Dunlap { 110630e7468fSPeter Dunlap /* 110730e7468fSPeter Dunlap * For small transfers, the iSER transport delegates the IDM 110830e7468fSPeter Dunlap * layer to bcopy the SCSI Write data for faster IOPS. 110930e7468fSPeter Dunlap */ 111030e7468fSPeter Dunlap if (buf->idb_bufbcopy == B_TRUE) { 111130e7468fSPeter Dunlap 111230e7468fSPeter Dunlap bcopy(buf->idb_bufptr, buf->idb_buf, buf->idb_buflen); 111330e7468fSPeter Dunlap } 1114a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1115a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idt, buf); 1116a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1117a6d42e7dSPeter Dunlap } 1118a6d42e7dSPeter Dunlap 1119a6d42e7dSPeter Dunlap static void 1120a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf) 1121a6d42e7dSPeter Dunlap { 1122a6d42e7dSPeter Dunlap buf->idb_task_binding = idt; 1123a6d42e7dSPeter Dunlap buf->idb_ic = idt->idt_ic; 1124a6d42e7dSPeter Dunlap idm_listbuf_insert(&idt->idt_outbufv, buf); 1125a6d42e7dSPeter Dunlap } 1126a6d42e7dSPeter Dunlap 1127a6d42e7dSPeter Dunlap void 1128a6d42e7dSPeter Dunlap idm_buf_unbind_in(idm_task_t *idt, idm_buf_t *buf) 1129a6d42e7dSPeter Dunlap { 113030e7468fSPeter Dunlap /* 113130e7468fSPeter Dunlap * For small transfers, the iSER transport delegates the IDM 113230e7468fSPeter Dunlap * layer to bcopy the SCSI Read data into the read buufer 113330e7468fSPeter Dunlap * for faster IOPS. 113430e7468fSPeter Dunlap */ 113530e7468fSPeter Dunlap if (buf->idb_bufbcopy == B_TRUE) { 113630e7468fSPeter Dunlap bcopy(buf->idb_buf, buf->idb_bufptr, buf->idb_buflen); 113730e7468fSPeter Dunlap } 1138a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1139a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idt, buf); 1140a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1141a6d42e7dSPeter Dunlap } 1142a6d42e7dSPeter Dunlap 1143a6d42e7dSPeter Dunlap static void 1144a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf) 1145a6d42e7dSPeter Dunlap { 1146a6d42e7dSPeter Dunlap list_remove(&idt->idt_inbufv, buf); 1147a6d42e7dSPeter Dunlap } 1148a6d42e7dSPeter Dunlap 1149a6d42e7dSPeter Dunlap void 1150a6d42e7dSPeter Dunlap idm_buf_unbind_out(idm_task_t *idt, idm_buf_t *buf) 1151a6d42e7dSPeter Dunlap { 1152a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1153a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idt, buf); 1154a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1155a6d42e7dSPeter Dunlap } 1156a6d42e7dSPeter Dunlap 1157a6d42e7dSPeter Dunlap static void 1158a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf) 1159a6d42e7dSPeter Dunlap { 1160a6d42e7dSPeter Dunlap list_remove(&idt->idt_outbufv, buf); 1161a6d42e7dSPeter Dunlap } 1162a6d42e7dSPeter Dunlap 1163a6d42e7dSPeter Dunlap /* 1164a6d42e7dSPeter Dunlap * idm_buf_find() will lookup the idm_buf_t based on the relative offset in the 1165a6d42e7dSPeter Dunlap * iSCSI PDU 1166a6d42e7dSPeter Dunlap */ 1167a6d42e7dSPeter Dunlap idm_buf_t * 1168a6d42e7dSPeter Dunlap idm_buf_find(void *lbuf, size_t data_offset) 1169a6d42e7dSPeter Dunlap { 1170a6d42e7dSPeter Dunlap idm_buf_t *idb; 1171a6d42e7dSPeter Dunlap list_t *lst = (list_t *)lbuf; 1172a6d42e7dSPeter Dunlap 1173a6d42e7dSPeter Dunlap /* iterate through the list to find the buffer */ 1174a6d42e7dSPeter Dunlap for (idb = list_head(lst); idb != NULL; idb = list_next(lst, idb)) { 1175a6d42e7dSPeter Dunlap 1176a6d42e7dSPeter Dunlap ASSERT((idb->idb_ic->ic_conn_type == CONN_TYPE_TGT) || 1177a6d42e7dSPeter Dunlap (idb->idb_bufoffset == 0)); 1178a6d42e7dSPeter Dunlap 1179a6d42e7dSPeter Dunlap if ((data_offset >= idb->idb_bufoffset) && 1180a6d42e7dSPeter Dunlap (data_offset < (idb->idb_bufoffset + idb->idb_buflen))) { 1181a6d42e7dSPeter Dunlap 1182a6d42e7dSPeter Dunlap return (idb); 1183a6d42e7dSPeter Dunlap } 1184a6d42e7dSPeter Dunlap } 1185a6d42e7dSPeter Dunlap 1186a6d42e7dSPeter Dunlap return (NULL); 1187a6d42e7dSPeter Dunlap } 1188a6d42e7dSPeter Dunlap 118930e7468fSPeter Dunlap void 119030e7468fSPeter Dunlap idm_bufpat_set(idm_buf_t *idb) 119130e7468fSPeter Dunlap { 119230e7468fSPeter Dunlap idm_bufpat_t *bufpat; 119330e7468fSPeter Dunlap int len, i; 119430e7468fSPeter Dunlap 119530e7468fSPeter Dunlap len = idb->idb_buflen; 119630e7468fSPeter Dunlap len = (len / sizeof (idm_bufpat_t)) * sizeof (idm_bufpat_t); 119730e7468fSPeter Dunlap 119830e7468fSPeter Dunlap bufpat = idb->idb_buf; 119930e7468fSPeter Dunlap for (i = 0; i < len; i += sizeof (idm_bufpat_t)) { 120030e7468fSPeter Dunlap bufpat->bufpat_idb = idb; 120130e7468fSPeter Dunlap bufpat->bufpat_bufmagic = IDM_BUF_MAGIC; 120230e7468fSPeter Dunlap bufpat->bufpat_offset = i; 120330e7468fSPeter Dunlap bufpat++; 120430e7468fSPeter Dunlap } 120530e7468fSPeter Dunlap } 120630e7468fSPeter Dunlap 120730e7468fSPeter Dunlap boolean_t 120830e7468fSPeter Dunlap idm_bufpat_check(idm_buf_t *idb, int check_len, idm_bufpat_check_type_t type) 120930e7468fSPeter Dunlap { 121030e7468fSPeter Dunlap idm_bufpat_t *bufpat; 121130e7468fSPeter Dunlap int len, i; 121230e7468fSPeter Dunlap 121330e7468fSPeter Dunlap len = (type == BP_CHECK_QUICK) ? sizeof (idm_bufpat_t) : check_len; 121430e7468fSPeter Dunlap len = (len / sizeof (idm_bufpat_t)) * sizeof (idm_bufpat_t); 121530e7468fSPeter Dunlap ASSERT(len <= idb->idb_buflen); 121630e7468fSPeter Dunlap bufpat = idb->idb_buf; 121730e7468fSPeter Dunlap 121830e7468fSPeter Dunlap /* 121930e7468fSPeter Dunlap * Don't check the pattern in buffers that came from outside IDM 122030e7468fSPeter Dunlap * (these will be buffers from the initiator that we opted not 122130e7468fSPeter Dunlap * to double-buffer) 122230e7468fSPeter Dunlap */ 122330e7468fSPeter Dunlap if (!idb->idb_bufalloc) 122430e7468fSPeter Dunlap return (B_FALSE); 122530e7468fSPeter Dunlap 122630e7468fSPeter Dunlap /* 122730e7468fSPeter Dunlap * Return true if we find the pattern anywhere in the buffer 122830e7468fSPeter Dunlap */ 122930e7468fSPeter Dunlap for (i = 0; i < len; i += sizeof (idm_bufpat_t)) { 123030e7468fSPeter Dunlap if (BUFPAT_MATCH(bufpat, idb)) { 123130e7468fSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_bufpat_check found: " 123230e7468fSPeter Dunlap "idb %p bufpat %p " 123330e7468fSPeter Dunlap "bufpat_idb=%p bufmagic=%08x offset=%08x", 123430e7468fSPeter Dunlap (void *)idb, (void *)bufpat, bufpat->bufpat_idb, 123530e7468fSPeter Dunlap bufpat->bufpat_bufmagic, bufpat->bufpat_offset); 123630e7468fSPeter Dunlap DTRACE_PROBE2(bufpat__pattern__found, 123730e7468fSPeter Dunlap idm_buf_t *, idb, idm_bufpat_t *, bufpat); 123830e7468fSPeter Dunlap if (type == BP_CHECK_ASSERT) { 123930e7468fSPeter Dunlap ASSERT(0); 124030e7468fSPeter Dunlap } 124130e7468fSPeter Dunlap return (B_TRUE); 124230e7468fSPeter Dunlap } 124330e7468fSPeter Dunlap bufpat++; 124430e7468fSPeter Dunlap } 124530e7468fSPeter Dunlap 124630e7468fSPeter Dunlap return (B_FALSE); 124730e7468fSPeter Dunlap } 124830e7468fSPeter Dunlap 1249a6d42e7dSPeter Dunlap /* 1250a6d42e7dSPeter Dunlap * idm_task_alloc 1251a6d42e7dSPeter Dunlap * 1252a6d42e7dSPeter Dunlap * This function will allocate a idm_task_t structure. A task tag is also 1253a6d42e7dSPeter Dunlap * generated and saved in idt_tt. The task is not active. 1254a6d42e7dSPeter Dunlap */ 1255a6d42e7dSPeter Dunlap idm_task_t * 1256a6d42e7dSPeter Dunlap idm_task_alloc(idm_conn_t *ic) 1257a6d42e7dSPeter Dunlap { 1258a6d42e7dSPeter Dunlap idm_task_t *idt; 1259a6d42e7dSPeter Dunlap 1260a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1261a6d42e7dSPeter Dunlap 1262a6d42e7dSPeter Dunlap /* Don't allocate new tasks if we are not in FFP */ 1263a6d42e7dSPeter Dunlap if (!ic->ic_ffp) { 1264a6d42e7dSPeter Dunlap return (NULL); 1265a6d42e7dSPeter Dunlap } 1266a6d42e7dSPeter Dunlap idt = kmem_cache_alloc(idm.idm_task_cache, KM_NOSLEEP); 1267a6d42e7dSPeter Dunlap if (idt == NULL) { 1268a6d42e7dSPeter Dunlap return (NULL); 1269a6d42e7dSPeter Dunlap } 1270a6d42e7dSPeter Dunlap 1271a6d42e7dSPeter Dunlap ASSERT(list_is_empty(&idt->idt_inbufv)); 1272a6d42e7dSPeter Dunlap ASSERT(list_is_empty(&idt->idt_outbufv)); 1273a6d42e7dSPeter Dunlap 127492adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_enter(&ic->ic_state_mutex); 127592adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (!ic->ic_ffp) { 127692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&ic->ic_state_mutex); 127792adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States kmem_cache_free(idm.idm_task_cache, idt); 127892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (NULL); 127992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 1280a6d42e7dSPeter Dunlap idm_conn_hold(ic); 1281a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 1282a6d42e7dSPeter Dunlap 1283a6d42e7dSPeter Dunlap idt->idt_state = TASK_IDLE; 1284a6d42e7dSPeter Dunlap idt->idt_ic = ic; 12858e718be9SToomas Soome idt->idt_private = NULL; 1286a6d42e7dSPeter Dunlap idt->idt_exp_datasn = 0; 1287a6d42e7dSPeter Dunlap idt->idt_exp_rttsn = 0; 128860220f10SPriya Krishnan idt->idt_flags = 0; 1289a6d42e7dSPeter Dunlap return (idt); 1290a6d42e7dSPeter Dunlap } 1291a6d42e7dSPeter Dunlap 1292a6d42e7dSPeter Dunlap /* 1293a6d42e7dSPeter Dunlap * idm_task_start 1294a6d42e7dSPeter Dunlap * 129530e7468fSPeter Dunlap * Mark the task active and initialize some stats. The caller 1296a6d42e7dSPeter Dunlap * sets up the idm_task_t structure with a prior call to idm_task_alloc(). 1297a6d42e7dSPeter Dunlap * The task service does not function as a task/work engine, it is the 1298a6d42e7dSPeter Dunlap * responsibility of the initiator to start the data transfer and free the 1299a6d42e7dSPeter Dunlap * resources. 1300a6d42e7dSPeter Dunlap */ 1301a6d42e7dSPeter Dunlap void 1302a6d42e7dSPeter Dunlap idm_task_start(idm_task_t *idt, uintptr_t handle) 1303a6d42e7dSPeter Dunlap { 1304a6d42e7dSPeter Dunlap ASSERT(idt != NULL); 1305a6d42e7dSPeter Dunlap 1306a6d42e7dSPeter Dunlap /* mark the task as ACTIVE */ 1307a6d42e7dSPeter Dunlap idt->idt_state = TASK_ACTIVE; 1308a6d42e7dSPeter Dunlap idt->idt_client_handle = handle; 1309a6d42e7dSPeter Dunlap idt->idt_tx_to_ini_start = idt->idt_tx_to_ini_done = 131030e7468fSPeter Dunlap idt->idt_rx_from_ini_start = idt->idt_rx_from_ini_done = 131130e7468fSPeter Dunlap idt->idt_tx_bytes = idt->idt_rx_bytes = 0; 1312a6d42e7dSPeter Dunlap } 1313a6d42e7dSPeter Dunlap 1314a6d42e7dSPeter Dunlap /* 1315a6d42e7dSPeter Dunlap * idm_task_done 1316a6d42e7dSPeter Dunlap * 131730e7468fSPeter Dunlap * This function sets the state to indicate that the task is no longer active. 1318a6d42e7dSPeter Dunlap */ 1319a6d42e7dSPeter Dunlap void 1320a6d42e7dSPeter Dunlap idm_task_done(idm_task_t *idt) 1321a6d42e7dSPeter Dunlap { 1322a6d42e7dSPeter Dunlap ASSERT(idt != NULL); 1323a6d42e7dSPeter Dunlap 132430e7468fSPeter Dunlap mutex_enter(&idt->idt_mutex); 1325a6d42e7dSPeter Dunlap idt->idt_state = TASK_IDLE; 132630e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 132730e7468fSPeter Dunlap 132830e7468fSPeter Dunlap /* 132930e7468fSPeter Dunlap * Although unlikely it is possible for a reference to come in after 133030e7468fSPeter Dunlap * the client has decided the task is over but before we've marked 133130e7468fSPeter Dunlap * the task idle. One specific unavoidable scenario is the case where 133230e7468fSPeter Dunlap * received PDU with the matching ITT/TTT results in a successful 133330e7468fSPeter Dunlap * lookup of this task. We are at the mercy of the remote node in 133430e7468fSPeter Dunlap * that case so we need to handle it. Now that the task state 133530e7468fSPeter Dunlap * has changed no more references will occur so a simple call to 133630e7468fSPeter Dunlap * idm_refcnt_wait_ref should deal with the situation. 133730e7468fSPeter Dunlap */ 133830e7468fSPeter Dunlap idm_refcnt_wait_ref(&idt->idt_refcnt); 1339a6d42e7dSPeter Dunlap idm_refcnt_reset(&idt->idt_refcnt); 1340a6d42e7dSPeter Dunlap } 1341a6d42e7dSPeter Dunlap 1342a6d42e7dSPeter Dunlap /* 1343a6d42e7dSPeter Dunlap * idm_task_free 1344a6d42e7dSPeter Dunlap * 1345a6d42e7dSPeter Dunlap * This function will free the Task Tag and the memory allocated for the task 1346a6d42e7dSPeter Dunlap * idm_task_done should be called prior to this call 1347a6d42e7dSPeter Dunlap */ 1348a6d42e7dSPeter Dunlap void 1349a6d42e7dSPeter Dunlap idm_task_free(idm_task_t *idt) 1350a6d42e7dSPeter Dunlap { 135130e7468fSPeter Dunlap idm_conn_t *ic; 1352a6d42e7dSPeter Dunlap 1353a6d42e7dSPeter Dunlap ASSERT(idt != NULL); 135430e7468fSPeter Dunlap ASSERT(idt->idt_refcnt.ir_refcnt == 0); 1355a6d42e7dSPeter Dunlap ASSERT(idt->idt_state == TASK_IDLE); 1356a6d42e7dSPeter Dunlap 135730e7468fSPeter Dunlap ic = idt->idt_ic; 135830e7468fSPeter Dunlap 1359a6d42e7dSPeter Dunlap /* 1360a6d42e7dSPeter Dunlap * It's possible for items to still be in the idt_inbufv list if 136192adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * they were added after idm_free_task_rsrc was called. We rely on 1362a6d42e7dSPeter Dunlap * STMF to free all buffers associated with the task however STMF 1363a6d42e7dSPeter Dunlap * doesn't know that we have this reference to the buffers. 1364a6d42e7dSPeter Dunlap * Use list_create so that we don't end up with stale references 1365a6d42e7dSPeter Dunlap * to these buffers. 1366a6d42e7dSPeter Dunlap */ 1367a6d42e7dSPeter Dunlap list_create(&idt->idt_inbufv, sizeof (idm_buf_t), 1368a6d42e7dSPeter Dunlap offsetof(idm_buf_t, idb_buflink)); 1369a6d42e7dSPeter Dunlap list_create(&idt->idt_outbufv, sizeof (idm_buf_t), 1370a6d42e7dSPeter Dunlap offsetof(idm_buf_t, idb_buflink)); 1371a6d42e7dSPeter Dunlap 1372a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_task_cache, idt); 1373a6d42e7dSPeter Dunlap 1374a6d42e7dSPeter Dunlap idm_conn_rele(ic); 1375a6d42e7dSPeter Dunlap } 1376a6d42e7dSPeter Dunlap 1377a6d42e7dSPeter Dunlap /* 137830e7468fSPeter Dunlap * idm_task_find_common 137930e7468fSPeter Dunlap * common code for idm_task_find() and idm_task_find_and_complete() 1380a6d42e7dSPeter Dunlap */ 1381a6d42e7dSPeter Dunlap /*ARGSUSED*/ 138230e7468fSPeter Dunlap static idm_task_t * 138330e7468fSPeter Dunlap idm_task_find_common(idm_conn_t *ic, uint32_t itt, uint32_t ttt, 138430e7468fSPeter Dunlap boolean_t complete) 1385a6d42e7dSPeter Dunlap { 1386a6d42e7dSPeter Dunlap uint32_t tt, client_handle; 1387a6d42e7dSPeter Dunlap idm_task_t *idt; 1388a6d42e7dSPeter Dunlap 1389a6d42e7dSPeter Dunlap /* 1390a6d42e7dSPeter Dunlap * Must match both itt and ttt. The table is indexed by itt 1391a6d42e7dSPeter Dunlap * for initiator connections and ttt for target connections. 1392a6d42e7dSPeter Dunlap */ 1393a6d42e7dSPeter Dunlap if (IDM_CONN_ISTGT(ic)) { 1394a6d42e7dSPeter Dunlap tt = ttt; 1395a6d42e7dSPeter Dunlap client_handle = itt; 1396a6d42e7dSPeter Dunlap } else { 1397a6d42e7dSPeter Dunlap tt = itt; 1398a6d42e7dSPeter Dunlap client_handle = ttt; 1399a6d42e7dSPeter Dunlap } 1400a6d42e7dSPeter Dunlap 1401a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER); 1402a6d42e7dSPeter Dunlap if (tt >= idm.idm_taskid_max) { 1403a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1404a6d42e7dSPeter Dunlap return (NULL); 1405a6d42e7dSPeter Dunlap } 1406a6d42e7dSPeter Dunlap 1407a6d42e7dSPeter Dunlap idt = idm.idm_taskid_table[tt]; 1408a6d42e7dSPeter Dunlap 1409a6d42e7dSPeter Dunlap if (idt != NULL) { 1410a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1411a6d42e7dSPeter Dunlap if ((idt->idt_state != TASK_ACTIVE) || 141230e7468fSPeter Dunlap (idt->idt_ic != ic) || 1413a6d42e7dSPeter Dunlap (IDM_CONN_ISTGT(ic) && 1414a6d42e7dSPeter Dunlap (idt->idt_client_handle != client_handle))) { 1415a6d42e7dSPeter Dunlap /* 141630e7468fSPeter Dunlap * Task doesn't match or task is aborting and 141730e7468fSPeter Dunlap * we don't want any more references. 1418a6d42e7dSPeter Dunlap */ 141930e7468fSPeter Dunlap if ((idt->idt_ic != ic) && 142030e7468fSPeter Dunlap (idt->idt_state == TASK_ACTIVE) && 142130e7468fSPeter Dunlap (IDM_CONN_ISINI(ic) || idt->idt_client_handle == 142230e7468fSPeter Dunlap client_handle)) { 142330e7468fSPeter Dunlap IDM_CONN_LOG(CE_WARN, 142430e7468fSPeter Dunlap "idm_task_find: wrong connection %p != %p", 142530e7468fSPeter Dunlap (void *)ic, (void *)idt->idt_ic); 142630e7468fSPeter Dunlap } 1427a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1428a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1429a6d42e7dSPeter Dunlap return (NULL); 1430a6d42e7dSPeter Dunlap } 1431a6d42e7dSPeter Dunlap idm_task_hold(idt); 143230e7468fSPeter Dunlap /* 143330e7468fSPeter Dunlap * Set the task state to TASK_COMPLETE so it can no longer 143430e7468fSPeter Dunlap * be found or aborted. 143530e7468fSPeter Dunlap */ 143630e7468fSPeter Dunlap if (B_TRUE == complete) 143730e7468fSPeter Dunlap idt->idt_state = TASK_COMPLETE; 1438a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1439a6d42e7dSPeter Dunlap } 1440a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1441a6d42e7dSPeter Dunlap 1442a6d42e7dSPeter Dunlap return (idt); 1443a6d42e7dSPeter Dunlap } 1444a6d42e7dSPeter Dunlap 144530e7468fSPeter Dunlap /* 144630e7468fSPeter Dunlap * This function looks up a task by task tag. 144730e7468fSPeter Dunlap */ 144830e7468fSPeter Dunlap idm_task_t * 144930e7468fSPeter Dunlap idm_task_find(idm_conn_t *ic, uint32_t itt, uint32_t ttt) 145030e7468fSPeter Dunlap { 145130e7468fSPeter Dunlap return (idm_task_find_common(ic, itt, ttt, B_FALSE)); 145230e7468fSPeter Dunlap } 145330e7468fSPeter Dunlap 145430e7468fSPeter Dunlap /* 145530e7468fSPeter Dunlap * This function looks up a task by task tag. If found, the task state 145630e7468fSPeter Dunlap * is atomically set to TASK_COMPLETE so it can longer be found or aborted. 145730e7468fSPeter Dunlap */ 145830e7468fSPeter Dunlap idm_task_t * 145930e7468fSPeter Dunlap idm_task_find_and_complete(idm_conn_t *ic, uint32_t itt, uint32_t ttt) 146030e7468fSPeter Dunlap { 146130e7468fSPeter Dunlap return (idm_task_find_common(ic, itt, ttt, B_TRUE)); 146230e7468fSPeter Dunlap } 146330e7468fSPeter Dunlap 1464a6d42e7dSPeter Dunlap /* 1465a6d42e7dSPeter Dunlap * idm_task_find_by_handle 1466a6d42e7dSPeter Dunlap * 1467a6d42e7dSPeter Dunlap * This function looks up a task by the client-private idt_client_handle. 1468a6d42e7dSPeter Dunlap * 1469a6d42e7dSPeter Dunlap * This function should NEVER be called in the performance path. It is 1470a6d42e7dSPeter Dunlap * intended strictly for error recovery/task management. 1471a6d42e7dSPeter Dunlap */ 1472a6d42e7dSPeter Dunlap /*ARGSUSED*/ 1473a6d42e7dSPeter Dunlap void * 1474a6d42e7dSPeter Dunlap idm_task_find_by_handle(idm_conn_t *ic, uintptr_t handle) 1475a6d42e7dSPeter Dunlap { 1476a6d42e7dSPeter Dunlap idm_task_t *idt = NULL; 1477a6d42e7dSPeter Dunlap int idx = 0; 1478a6d42e7dSPeter Dunlap 1479a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER); 1480a6d42e7dSPeter Dunlap 1481a6d42e7dSPeter Dunlap for (idx = 0; idx < idm.idm_taskid_max; idx++) { 1482a6d42e7dSPeter Dunlap idt = idm.idm_taskid_table[idx]; 1483a6d42e7dSPeter Dunlap 1484a6d42e7dSPeter Dunlap if (idt == NULL) 1485a6d42e7dSPeter Dunlap continue; 1486a6d42e7dSPeter Dunlap 1487a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1488a6d42e7dSPeter Dunlap 1489a6d42e7dSPeter Dunlap if (idt->idt_state != TASK_ACTIVE) { 1490a6d42e7dSPeter Dunlap /* 1491a6d42e7dSPeter Dunlap * Task is either in suspend, abort, or already 1492a6d42e7dSPeter Dunlap * complete. 1493a6d42e7dSPeter Dunlap */ 1494a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1495a6d42e7dSPeter Dunlap continue; 1496a6d42e7dSPeter Dunlap } 1497a6d42e7dSPeter Dunlap 1498a6d42e7dSPeter Dunlap if (idt->idt_client_handle == handle) { 1499a6d42e7dSPeter Dunlap idm_task_hold(idt); 1500a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1501a6d42e7dSPeter Dunlap break; 1502a6d42e7dSPeter Dunlap } 1503a6d42e7dSPeter Dunlap 1504a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1505a6d42e7dSPeter Dunlap } 1506a6d42e7dSPeter Dunlap 1507a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1508a6d42e7dSPeter Dunlap 1509a6d42e7dSPeter Dunlap if ((idt == NULL) || (idx == idm.idm_taskid_max)) 1510a6d42e7dSPeter Dunlap return (NULL); 1511a6d42e7dSPeter Dunlap 1512a6d42e7dSPeter Dunlap return (idt->idt_private); 1513a6d42e7dSPeter Dunlap } 1514a6d42e7dSPeter Dunlap 1515a6d42e7dSPeter Dunlap void 1516a6d42e7dSPeter Dunlap idm_task_hold(idm_task_t *idt) 1517a6d42e7dSPeter Dunlap { 1518a6d42e7dSPeter Dunlap idm_refcnt_hold(&idt->idt_refcnt); 1519a6d42e7dSPeter Dunlap } 1520a6d42e7dSPeter Dunlap 1521a6d42e7dSPeter Dunlap void 1522a6d42e7dSPeter Dunlap idm_task_rele(idm_task_t *idt) 1523a6d42e7dSPeter Dunlap { 1524a6d42e7dSPeter Dunlap idm_refcnt_rele(&idt->idt_refcnt); 1525a6d42e7dSPeter Dunlap } 1526a6d42e7dSPeter Dunlap 1527*61dfa509SRick McNeal stmf_status_t 1528a6d42e7dSPeter Dunlap idm_task_abort(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type) 1529a6d42e7dSPeter Dunlap { 1530a6d42e7dSPeter Dunlap idm_task_t *task; 1531a6d42e7dSPeter Dunlap int idx; 1532*61dfa509SRick McNeal stmf_status_t s = STMF_SUCCESS; 1533a6d42e7dSPeter Dunlap 1534a6d42e7dSPeter Dunlap /* 1535a6d42e7dSPeter Dunlap * Passing NULL as the task indicates that all tasks 1536a6d42e7dSPeter Dunlap * for this connection should be aborted. 1537a6d42e7dSPeter Dunlap */ 1538a6d42e7dSPeter Dunlap if (idt == NULL) { 1539a6d42e7dSPeter Dunlap /* 1540a6d42e7dSPeter Dunlap * Only the connection state machine should ask for 1541a6d42e7dSPeter Dunlap * all tasks to abort and this should never happen in FFP. 1542a6d42e7dSPeter Dunlap */ 1543a6d42e7dSPeter Dunlap ASSERT(!ic->ic_ffp); 1544a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER); 1545a6d42e7dSPeter Dunlap for (idx = 0; idx < idm.idm_taskid_max; idx++) { 1546a6d42e7dSPeter Dunlap task = idm.idm_taskid_table[idx]; 154730e7468fSPeter Dunlap if (task == NULL) 154830e7468fSPeter Dunlap continue; 154930e7468fSPeter Dunlap mutex_enter(&task->idt_mutex); 155030e7468fSPeter Dunlap if ((task->idt_state != TASK_IDLE) && 155130e7468fSPeter Dunlap (task->idt_state != TASK_COMPLETE) && 1552a6d42e7dSPeter Dunlap (task->idt_ic == ic)) { 1553a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1554*61dfa509SRick McNeal s = idm_task_abort_one(ic, task, abort_type); 1555a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER); 155630e7468fSPeter Dunlap } else 155730e7468fSPeter Dunlap mutex_exit(&task->idt_mutex); 1558a6d42e7dSPeter Dunlap } 1559a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1560a6d42e7dSPeter Dunlap } else { 156130e7468fSPeter Dunlap mutex_enter(&idt->idt_mutex); 1562*61dfa509SRick McNeal s = idm_task_abort_one(ic, idt, abort_type); 1563a6d42e7dSPeter Dunlap } 1564*61dfa509SRick McNeal return (s); 1565a6d42e7dSPeter Dunlap } 1566a6d42e7dSPeter Dunlap 1567a6d42e7dSPeter Dunlap static void 1568a6d42e7dSPeter Dunlap idm_task_abort_unref_cb(void *ref) 1569a6d42e7dSPeter Dunlap { 1570a6d42e7dSPeter Dunlap idm_task_t *idt = ref; 1571a6d42e7dSPeter Dunlap 1572a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1573a6d42e7dSPeter Dunlap switch (idt->idt_state) { 1574a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 1575a6d42e7dSPeter Dunlap idt->idt_state = TASK_SUSPENDED; 1576a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1577a6d42e7dSPeter Dunlap idm_task_aborted(idt, IDM_STATUS_SUSPENDED); 1578a6d42e7dSPeter Dunlap return; 1579a6d42e7dSPeter Dunlap case TASK_ABORTING: 1580a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTED; 1581a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1582a6d42e7dSPeter Dunlap idm_task_aborted(idt, IDM_STATUS_ABORTED); 1583a6d42e7dSPeter Dunlap return; 1584a6d42e7dSPeter Dunlap default: 1585a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1586a6d42e7dSPeter Dunlap ASSERT(0); 1587a6d42e7dSPeter Dunlap break; 1588a6d42e7dSPeter Dunlap } 1589a6d42e7dSPeter Dunlap } 1590a6d42e7dSPeter Dunlap 159130e7468fSPeter Dunlap /* 159230e7468fSPeter Dunlap * Abort the idm task. 159330e7468fSPeter Dunlap * Caller must hold the task mutex, which will be released before return 159430e7468fSPeter Dunlap */ 1595*61dfa509SRick McNeal static stmf_status_t 1596a6d42e7dSPeter Dunlap idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type) 1597a6d42e7dSPeter Dunlap { 1598*61dfa509SRick McNeal stmf_status_t s = STMF_SUCCESS; 1599*61dfa509SRick McNeal 1600a6d42e7dSPeter Dunlap /* Caller must hold connection mutex */ 160130e7468fSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 1602a6d42e7dSPeter Dunlap switch (idt->idt_state) { 1603a6d42e7dSPeter Dunlap case TASK_ACTIVE: 1604a6d42e7dSPeter Dunlap switch (abort_type) { 1605a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND: 1606a6d42e7dSPeter Dunlap /* Call transport to release any resources */ 1607a6d42e7dSPeter Dunlap idt->idt_state = TASK_SUSPENDING; 1608a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1609a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_free_task_rsrc(idt); 1610a6d42e7dSPeter Dunlap 1611a6d42e7dSPeter Dunlap /* 1612a6d42e7dSPeter Dunlap * Wait for outstanding references. When all 1613a6d42e7dSPeter Dunlap * references are released the callback will call 1614a6d42e7dSPeter Dunlap * idm_task_aborted(). 1615a6d42e7dSPeter Dunlap */ 1616a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(&idt->idt_refcnt, 1617a6d42e7dSPeter Dunlap &idm_task_abort_unref_cb); 1618*61dfa509SRick McNeal return (s); 1619a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT: 1620a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT: 1621a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTING; 1622a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1623a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_free_task_rsrc(idt); 1624a6d42e7dSPeter Dunlap 1625a6d42e7dSPeter Dunlap /* 1626a6d42e7dSPeter Dunlap * Wait for outstanding references. When all 1627a6d42e7dSPeter Dunlap * references are released the callback will call 1628a6d42e7dSPeter Dunlap * idm_task_aborted(). 1629a6d42e7dSPeter Dunlap */ 1630a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(&idt->idt_refcnt, 1631a6d42e7dSPeter Dunlap &idm_task_abort_unref_cb); 1632*61dfa509SRick McNeal return (s); 1633a6d42e7dSPeter Dunlap default: 1634a6d42e7dSPeter Dunlap ASSERT(0); 1635a6d42e7dSPeter Dunlap } 1636a6d42e7dSPeter Dunlap break; 1637a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 1638a6d42e7dSPeter Dunlap /* Already called transport_free_task_rsrc(); */ 1639a6d42e7dSPeter Dunlap switch (abort_type) { 1640a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND: 1641a6d42e7dSPeter Dunlap /* Already doing it */ 1642a6d42e7dSPeter Dunlap break; 1643a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT: 1644a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT: 1645a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTING; 1646a6d42e7dSPeter Dunlap break; 1647a6d42e7dSPeter Dunlap default: 1648a6d42e7dSPeter Dunlap ASSERT(0); 1649a6d42e7dSPeter Dunlap } 1650a6d42e7dSPeter Dunlap break; 1651a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 1652a6d42e7dSPeter Dunlap /* Already called transport_free_task_rsrc(); */ 1653a6d42e7dSPeter Dunlap switch (abort_type) { 1654a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND: 1655a6d42e7dSPeter Dunlap /* Already doing it */ 1656a6d42e7dSPeter Dunlap break; 1657a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT: 1658a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT: 1659a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTING; 1660a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1661a6d42e7dSPeter Dunlap 1662a6d42e7dSPeter Dunlap /* 1663a6d42e7dSPeter Dunlap * We could probably call idm_task_aborted directly 1664a6d42e7dSPeter Dunlap * here but we may be holding the conn lock. It's 1665a6d42e7dSPeter Dunlap * easier to just switch contexts. Even though 1666a6d42e7dSPeter Dunlap * we shouldn't really have any references we'll 1667a6d42e7dSPeter Dunlap * set the state to TASK_ABORTING instead of 1668a6d42e7dSPeter Dunlap * TASK_ABORTED so we can use the same code path. 1669a6d42e7dSPeter Dunlap */ 1670a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(&idt->idt_refcnt, 1671a6d42e7dSPeter Dunlap &idm_task_abort_unref_cb); 1672*61dfa509SRick McNeal return (s); 1673a6d42e7dSPeter Dunlap default: 1674a6d42e7dSPeter Dunlap ASSERT(0); 1675a6d42e7dSPeter Dunlap } 1676a6d42e7dSPeter Dunlap break; 1677a6d42e7dSPeter Dunlap case TASK_ABORTING: 1678a6d42e7dSPeter Dunlap case TASK_ABORTED: 1679a6d42e7dSPeter Dunlap switch (abort_type) { 1680a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND: 1681a6d42e7dSPeter Dunlap /* We're already past this point... */ 1682a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT: 1683a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT: 1684a6d42e7dSPeter Dunlap /* Already doing it */ 1685a6d42e7dSPeter Dunlap break; 1686a6d42e7dSPeter Dunlap default: 1687a6d42e7dSPeter Dunlap ASSERT(0); 1688a6d42e7dSPeter Dunlap } 1689a6d42e7dSPeter Dunlap break; 1690a6d42e7dSPeter Dunlap case TASK_COMPLETE: 1691*61dfa509SRick McNeal idm_refcnt_wait_ref(&idt->idt_refcnt); 1692*61dfa509SRick McNeal s = STMF_ABORT_SUCCESS; 1693a6d42e7dSPeter Dunlap break; 1694a6d42e7dSPeter Dunlap default: 1695a6d42e7dSPeter Dunlap ASSERT(0); 1696a6d42e7dSPeter Dunlap } 1697a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1698*61dfa509SRick McNeal 1699*61dfa509SRick McNeal return (s); 1700a6d42e7dSPeter Dunlap } 1701a6d42e7dSPeter Dunlap 1702a6d42e7dSPeter Dunlap static void 1703a6d42e7dSPeter Dunlap idm_task_aborted(idm_task_t *idt, idm_status_t status) 1704a6d42e7dSPeter Dunlap { 1705a6d42e7dSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_task_aborted)(idt, status); 1706a6d42e7dSPeter Dunlap } 1707a6d42e7dSPeter Dunlap 1708a6d42e7dSPeter Dunlap /* 1709a6d42e7dSPeter Dunlap * idm_pdu_tx 1710a6d42e7dSPeter Dunlap * 1711a6d42e7dSPeter Dunlap * This is IDM's implementation of the 'Send_Control' operational primitive. 1712a6d42e7dSPeter Dunlap * This function is invoked by an initiator iSCSI layer requesting the transfer 1713a6d42e7dSPeter Dunlap * of a iSCSI command PDU or a target iSCSI layer requesting the transfer of a 1714a6d42e7dSPeter Dunlap * iSCSI response PDU. The PDU will be transmitted as-is by the local Datamover 1715a6d42e7dSPeter Dunlap * layer to the peer iSCSI layer in the remote iSCSI node. The connection info 1716a6d42e7dSPeter Dunlap * and iSCSI PDU-specific qualifiers namely BHS, AHS, DataDescriptor and Size 1717a6d42e7dSPeter Dunlap * are provided as input. 1718a6d42e7dSPeter Dunlap * 1719a6d42e7dSPeter Dunlap */ 1720a6d42e7dSPeter Dunlap void 1721a6d42e7dSPeter Dunlap idm_pdu_tx(idm_pdu_t *pdu) 1722a6d42e7dSPeter Dunlap { 1723a6d42e7dSPeter Dunlap idm_conn_t *ic = pdu->isp_ic; 1724a6d42e7dSPeter Dunlap iscsi_async_evt_hdr_t *async_evt; 1725a6d42e7dSPeter Dunlap 1726a6d42e7dSPeter Dunlap /* 1727a6d42e7dSPeter Dunlap * If we are in full-featured mode then route SCSI-related 1728a6d42e7dSPeter Dunlap * commands to the appropriate function vector without checking 1729a6d42e7dSPeter Dunlap * the connection state. We will only be in full-feature mode 1730a6d42e7dSPeter Dunlap * when we are in an acceptable state for SCSI PDU's. 1731a6d42e7dSPeter Dunlap * 1732a6d42e7dSPeter Dunlap * We also need to ensure that there are no PDU events outstanding 1733a6d42e7dSPeter Dunlap * on the state machine. Any non-SCSI PDU's received in full-feature 1734a6d42e7dSPeter Dunlap * mode will result in PDU events and until these have been handled 1735a6d42e7dSPeter Dunlap * we need to route all PDU's through the state machine as PDU 1736a6d42e7dSPeter Dunlap * events to maintain ordering. 1737a6d42e7dSPeter Dunlap * 1738a6d42e7dSPeter Dunlap * Note that IDM cannot enter FFP mode until it processes in 1739a6d42e7dSPeter Dunlap * its state machine the last xmit of the login process. 1740a6d42e7dSPeter Dunlap * Hence, checking the IDM_PDU_LOGIN_TX flag here would be 1741a6d42e7dSPeter Dunlap * superfluous. 1742a6d42e7dSPeter Dunlap */ 1743a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 1744a6d42e7dSPeter Dunlap if (ic->ic_ffp && (ic->ic_pdu_events == 0)) { 1745a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 1746a6d42e7dSPeter Dunlap switch (IDM_PDU_OPCODE(pdu)) { 1747a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_RSP: 1748a6d42e7dSPeter Dunlap /* Target only */ 1749a668b114SPriya Krishnan DTRACE_ISCSI_2(scsi__response, idm_conn_t *, ic, 1750a668b114SPriya Krishnan iscsi_scsi_rsp_hdr_t *, 1751a668b114SPriya Krishnan (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr); 1752a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1753a6d42e7dSPeter Dunlap return; 1754a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_RSP: 1755a6d42e7dSPeter Dunlap /* Target only */ 1756a668b114SPriya Krishnan DTRACE_ISCSI_2(task__response, idm_conn_t *, ic, 1757a668b114SPriya Krishnan iscsi_text_rsp_hdr_t *, 1758a668b114SPriya Krishnan (iscsi_text_rsp_hdr_t *)pdu->isp_hdr); 1759a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1760a6d42e7dSPeter Dunlap return; 1761a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA_RSP: 1762a6d42e7dSPeter Dunlap /* Target only */ 1763a668b114SPriya Krishnan DTRACE_ISCSI_2(data__send, idm_conn_t *, ic, 1764a668b114SPriya Krishnan iscsi_data_rsp_hdr_t *, 1765a668b114SPriya Krishnan (iscsi_data_rsp_hdr_t *)pdu->isp_hdr); 1766a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1767a6d42e7dSPeter Dunlap return; 1768a6d42e7dSPeter Dunlap case ISCSI_OP_RTT_RSP: 1769a6d42e7dSPeter Dunlap /* Target only */ 1770a668b114SPriya Krishnan DTRACE_ISCSI_2(data__request, idm_conn_t *, ic, 1771a668b114SPriya Krishnan iscsi_rtt_hdr_t *, 1772a668b114SPriya Krishnan (iscsi_rtt_hdr_t *)pdu->isp_hdr); 1773a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1774a6d42e7dSPeter Dunlap return; 1775a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_IN: 1776a6d42e7dSPeter Dunlap /* Target only */ 1777a668b114SPriya Krishnan DTRACE_ISCSI_2(nop__send, idm_conn_t *, ic, 1778a668b114SPriya Krishnan iscsi_nop_in_hdr_t *, 1779a668b114SPriya Krishnan (iscsi_nop_in_hdr_t *)pdu->isp_hdr); 1780a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1781a6d42e7dSPeter Dunlap return; 1782a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_RSP: 1783a6d42e7dSPeter Dunlap /* Target only */ 1784a668b114SPriya Krishnan DTRACE_ISCSI_2(text__response, idm_conn_t *, ic, 1785a668b114SPriya Krishnan iscsi_text_rsp_hdr_t *, 1786a668b114SPriya Krishnan (iscsi_text_rsp_hdr_t *)pdu->isp_hdr); 1787a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1788a6d42e7dSPeter Dunlap return; 1789a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_CMD: 1790a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_OUT: 1791a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_CMD: 1792a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA: 1793a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_MSG: 1794a6d42e7dSPeter Dunlap /* Initiator only */ 1795a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1796a6d42e7dSPeter Dunlap return; 1797a6d42e7dSPeter Dunlap default: 1798a6d42e7dSPeter Dunlap break; 1799a6d42e7dSPeter Dunlap } 1800a6d42e7dSPeter Dunlap 1801a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 1802a6d42e7dSPeter Dunlap } 1803a6d42e7dSPeter Dunlap 1804a6d42e7dSPeter Dunlap /* 1805a6d42e7dSPeter Dunlap * Any PDU's processed outside of full-feature mode and non-SCSI 1806a6d42e7dSPeter Dunlap * PDU's in full-feature mode are handled by generating an 1807a6d42e7dSPeter Dunlap * event to the connection state machine. The state machine 1808a6d42e7dSPeter Dunlap * will validate the PDU against the current state and either 1809a6d42e7dSPeter Dunlap * transmit the PDU if the opcode is allowed or handle an 1810a6d42e7dSPeter Dunlap * error if the PDU is not allowed. 1811a6d42e7dSPeter Dunlap * 1812a6d42e7dSPeter Dunlap * This code-path will also generate any events that are implied 1813a6d42e7dSPeter Dunlap * by the PDU opcode. For example a "login response" with success 1814a6d42e7dSPeter Dunlap * status generates a CE_LOGOUT_SUCCESS_SND event. 1815a6d42e7dSPeter Dunlap */ 1816a6d42e7dSPeter Dunlap switch (IDM_PDU_OPCODE(pdu)) { 1817a6d42e7dSPeter Dunlap case ISCSI_OP_LOGIN_CMD: 1818a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_LOGIN_SND, (uintptr_t)pdu); 1819a6d42e7dSPeter Dunlap break; 1820a6d42e7dSPeter Dunlap case ISCSI_OP_LOGIN_RSP: 1821a668b114SPriya Krishnan DTRACE_ISCSI_2(login__response, idm_conn_t *, ic, 1822a668b114SPriya Krishnan iscsi_login_rsp_hdr_t *, 1823a668b114SPriya Krishnan (iscsi_login_rsp_hdr_t *)pdu->isp_hdr); 1824a6d42e7dSPeter Dunlap idm_parse_login_rsp(ic, pdu, /* Is RX */ B_FALSE); 1825a6d42e7dSPeter Dunlap break; 1826a6d42e7dSPeter Dunlap case ISCSI_OP_LOGOUT_CMD: 1827a6d42e7dSPeter Dunlap idm_parse_logout_req(ic, pdu, /* Is RX */ B_FALSE); 1828a6d42e7dSPeter Dunlap break; 1829a6d42e7dSPeter Dunlap case ISCSI_OP_LOGOUT_RSP: 1830a668b114SPriya Krishnan DTRACE_ISCSI_2(logout__response, idm_conn_t *, ic, 1831a668b114SPriya Krishnan iscsi_logout_rsp_hdr_t *, 1832a668b114SPriya Krishnan (iscsi_logout_rsp_hdr_t *)pdu->isp_hdr); 1833a6d42e7dSPeter Dunlap idm_parse_logout_rsp(ic, pdu, /* Is RX */ B_FALSE); 1834a6d42e7dSPeter Dunlap break; 1835a6d42e7dSPeter Dunlap case ISCSI_OP_ASYNC_EVENT: 1836a668b114SPriya Krishnan DTRACE_ISCSI_2(async__send, idm_conn_t *, ic, 1837a668b114SPriya Krishnan iscsi_async_evt_hdr_t *, 1838a668b114SPriya Krishnan (iscsi_async_evt_hdr_t *)pdu->isp_hdr); 1839a6d42e7dSPeter Dunlap async_evt = (iscsi_async_evt_hdr_t *)pdu->isp_hdr; 1840a6d42e7dSPeter Dunlap switch (async_evt->async_event) { 1841a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT: 1842a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_ASYNC_LOGOUT_SND, 1843a6d42e7dSPeter Dunlap (uintptr_t)pdu); 1844a6d42e7dSPeter Dunlap break; 1845a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION: 1846a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_ASYNC_DROP_CONN_SND, 1847a6d42e7dSPeter Dunlap (uintptr_t)pdu); 1848a6d42e7dSPeter Dunlap break; 1849a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS: 1850a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_ASYNC_DROP_ALL_CONN_SND, 1851a6d42e7dSPeter Dunlap (uintptr_t)pdu); 1852a6d42e7dSPeter Dunlap break; 1853a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_SCSI_EVENT: 1854a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION: 1855a6d42e7dSPeter Dunlap default: 1856a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, 1857a6d42e7dSPeter Dunlap (uintptr_t)pdu); 1858a6d42e7dSPeter Dunlap break; 1859a6d42e7dSPeter Dunlap } 1860a6d42e7dSPeter Dunlap break; 1861a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_RSP: 1862a6d42e7dSPeter Dunlap /* Target only */ 1863a668b114SPriya Krishnan DTRACE_ISCSI_2(scsi__response, idm_conn_t *, ic, 1864a668b114SPriya Krishnan iscsi_scsi_rsp_hdr_t *, 1865a668b114SPriya Krishnan (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr); 1866a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1867a6d42e7dSPeter Dunlap break; 1868a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_RSP: 1869a6d42e7dSPeter Dunlap /* Target only */ 1870a668b114SPriya Krishnan DTRACE_ISCSI_2(task__response, idm_conn_t *, ic, 1871a668b114SPriya Krishnan iscsi_scsi_task_mgt_rsp_hdr_t *, 1872a668b114SPriya Krishnan (iscsi_scsi_task_mgt_rsp_hdr_t *)pdu->isp_hdr); 1873a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1874a6d42e7dSPeter Dunlap break; 1875a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA_RSP: 1876a6d42e7dSPeter Dunlap /* Target only */ 1877a668b114SPriya Krishnan DTRACE_ISCSI_2(data__send, idm_conn_t *, ic, 1878a668b114SPriya Krishnan iscsi_data_rsp_hdr_t *, 1879a668b114SPriya Krishnan (iscsi_data_rsp_hdr_t *)pdu->isp_hdr); 1880a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1881a6d42e7dSPeter Dunlap break; 1882a6d42e7dSPeter Dunlap case ISCSI_OP_RTT_RSP: 1883a6d42e7dSPeter Dunlap /* Target only */ 1884a668b114SPriya Krishnan DTRACE_ISCSI_2(data__request, idm_conn_t *, ic, 1885a668b114SPriya Krishnan iscsi_rtt_hdr_t *, 1886a668b114SPriya Krishnan (iscsi_rtt_hdr_t *)pdu->isp_hdr); 1887a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1888a6d42e7dSPeter Dunlap break; 1889a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_IN: 1890a6d42e7dSPeter Dunlap /* Target only */ 1891a668b114SPriya Krishnan DTRACE_ISCSI_2(nop__send, idm_conn_t *, ic, 1892a668b114SPriya Krishnan iscsi_nop_in_hdr_t *, 1893a668b114SPriya Krishnan (iscsi_nop_in_hdr_t *)pdu->isp_hdr); 1894a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1895a6d42e7dSPeter Dunlap break; 1896a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_RSP: 1897a6d42e7dSPeter Dunlap /* Target only */ 1898a668b114SPriya Krishnan DTRACE_ISCSI_2(text__response, idm_conn_t *, ic, 1899a668b114SPriya Krishnan iscsi_text_rsp_hdr_t *, 1900a668b114SPriya Krishnan (iscsi_text_rsp_hdr_t *)pdu->isp_hdr); 1901a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1902a6d42e7dSPeter Dunlap break; 1903a6d42e7dSPeter Dunlap /* Initiator only */ 1904a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_CMD: 1905a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_MSG: 1906a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA: 1907a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_OUT: 1908a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_CMD: 1909a6d42e7dSPeter Dunlap case ISCSI_OP_SNACK_CMD: 1910a6d42e7dSPeter Dunlap case ISCSI_OP_REJECT_MSG: 1911a6d42e7dSPeter Dunlap default: 1912a6d42e7dSPeter Dunlap /* 1913a6d42e7dSPeter Dunlap * Connection state machine will validate these PDU's against 1914a6d42e7dSPeter Dunlap * the current state. A PDU not allowed in the current 1915a6d42e7dSPeter Dunlap * state will cause a protocol error. 1916a6d42e7dSPeter Dunlap */ 1917a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1918a6d42e7dSPeter Dunlap break; 1919a6d42e7dSPeter Dunlap } 1920a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 1921a6d42e7dSPeter Dunlap } 1922a6d42e7dSPeter Dunlap 1923a6d42e7dSPeter Dunlap /* 192430e7468fSPeter Dunlap * Common allocation of a PDU along with memory for header and data. 1925a6d42e7dSPeter Dunlap */ 192630e7468fSPeter Dunlap static idm_pdu_t * 192730e7468fSPeter Dunlap idm_pdu_alloc_common(uint_t hdrlen, uint_t datalen, int sleepflag) 1928a6d42e7dSPeter Dunlap { 1929a6d42e7dSPeter Dunlap idm_pdu_t *result; 1930a6d42e7dSPeter Dunlap 1931a6d42e7dSPeter Dunlap /* 1932a6d42e7dSPeter Dunlap * IDM clients should cache these structures for performance 1933a6d42e7dSPeter Dunlap * critical paths. We can't cache effectively in IDM because we 1934a6d42e7dSPeter Dunlap * don't know the correct header and data size. 1935a6d42e7dSPeter Dunlap * 1936a6d42e7dSPeter Dunlap * Valid header length is assumed to be hdrlen and valid data 1937a6d42e7dSPeter Dunlap * length is assumed to be datalen. isp_hdrlen and isp_datalen 1938a6d42e7dSPeter Dunlap * can be adjusted after the PDU is returned if necessary. 1939a6d42e7dSPeter Dunlap */ 194030e7468fSPeter Dunlap result = kmem_zalloc(sizeof (idm_pdu_t) + hdrlen + datalen, sleepflag); 194130e7468fSPeter Dunlap if (result != NULL) { 194230e7468fSPeter Dunlap /* For idm_pdu_free sanity check */ 194330e7468fSPeter Dunlap result->isp_flags |= IDM_PDU_ALLOC; 194430e7468fSPeter Dunlap /* pointer arithmetic */ 194530e7468fSPeter Dunlap result->isp_hdr = (iscsi_hdr_t *)(result + 1); 194630e7468fSPeter Dunlap result->isp_hdrlen = hdrlen; 194730e7468fSPeter Dunlap result->isp_hdrbuflen = hdrlen; 194830e7468fSPeter Dunlap result->isp_transport_hdrlen = 0; 19494142b486SJames Moore if (datalen != 0) 19504142b486SJames Moore result->isp_data = (uint8_t *)result->isp_hdr + hdrlen; 195130e7468fSPeter Dunlap result->isp_datalen = datalen; 195230e7468fSPeter Dunlap result->isp_databuflen = datalen; 195330e7468fSPeter Dunlap result->isp_magic = IDM_PDU_MAGIC; 195430e7468fSPeter Dunlap } 1955a6d42e7dSPeter Dunlap 1956a6d42e7dSPeter Dunlap return (result); 1957a6d42e7dSPeter Dunlap } 1958a6d42e7dSPeter Dunlap 195930e7468fSPeter Dunlap /* 196030e7468fSPeter Dunlap * Typical idm_pdu_alloc invocation, will block for resources. 196130e7468fSPeter Dunlap */ 196230e7468fSPeter Dunlap idm_pdu_t * 196330e7468fSPeter Dunlap idm_pdu_alloc(uint_t hdrlen, uint_t datalen) 196430e7468fSPeter Dunlap { 196530e7468fSPeter Dunlap return (idm_pdu_alloc_common(hdrlen, datalen, KM_SLEEP)); 196630e7468fSPeter Dunlap } 196730e7468fSPeter Dunlap 196830e7468fSPeter Dunlap /* 196930e7468fSPeter Dunlap * Non-blocking idm_pdu_alloc implementation, returns NULL if resources 197030e7468fSPeter Dunlap * are not available. Needed for transport-layer allocations which may 197130e7468fSPeter Dunlap * be invoking in interrupt context. 197230e7468fSPeter Dunlap */ 197330e7468fSPeter Dunlap idm_pdu_t * 197430e7468fSPeter Dunlap idm_pdu_alloc_nosleep(uint_t hdrlen, uint_t datalen) 197530e7468fSPeter Dunlap { 197630e7468fSPeter Dunlap return (idm_pdu_alloc_common(hdrlen, datalen, KM_NOSLEEP)); 197730e7468fSPeter Dunlap } 197830e7468fSPeter Dunlap 1979a6d42e7dSPeter Dunlap /* 1980a6d42e7dSPeter Dunlap * Free a PDU previously allocated with idm_pdu_alloc() including any 1981a6d42e7dSPeter Dunlap * header and data space allocated as part of the original request. 1982a6d42e7dSPeter Dunlap * Additional memory regions referenced by subsequent modification of 1983a6d42e7dSPeter Dunlap * the isp_hdr and/or isp_data fields will not be freed. 1984a6d42e7dSPeter Dunlap */ 1985a6d42e7dSPeter Dunlap void 1986a6d42e7dSPeter Dunlap idm_pdu_free(idm_pdu_t *pdu) 1987a6d42e7dSPeter Dunlap { 1988a6d42e7dSPeter Dunlap /* Make sure the structure was allocated using idm_pdu_alloc() */ 1989a6d42e7dSPeter Dunlap ASSERT(pdu->isp_flags & IDM_PDU_ALLOC); 1990a6d42e7dSPeter Dunlap kmem_free(pdu, 1991a6d42e7dSPeter Dunlap sizeof (idm_pdu_t) + pdu->isp_hdrbuflen + pdu->isp_databuflen); 1992a6d42e7dSPeter Dunlap } 1993a6d42e7dSPeter Dunlap 1994a6d42e7dSPeter Dunlap /* 1995a6d42e7dSPeter Dunlap * Initialize the connection, private and callback fields in a PDU. 1996a6d42e7dSPeter Dunlap */ 1997a6d42e7dSPeter Dunlap void 1998a6d42e7dSPeter Dunlap idm_pdu_init(idm_pdu_t *pdu, idm_conn_t *ic, void *private, idm_pdu_cb_t *cb) 1999a6d42e7dSPeter Dunlap { 2000a6d42e7dSPeter Dunlap /* 2001a6d42e7dSPeter Dunlap * idm_pdu_complete() will call idm_pdu_free if the callback is 2002a6d42e7dSPeter Dunlap * NULL. This will only work if the PDU was originally allocated 2003a6d42e7dSPeter Dunlap * with idm_pdu_alloc(). 2004a6d42e7dSPeter Dunlap */ 2005a6d42e7dSPeter Dunlap ASSERT((pdu->isp_flags & IDM_PDU_ALLOC) || 2006a6d42e7dSPeter Dunlap (cb != NULL)); 2007a6d42e7dSPeter Dunlap pdu->isp_magic = IDM_PDU_MAGIC; 2008a6d42e7dSPeter Dunlap pdu->isp_ic = ic; 2009a6d42e7dSPeter Dunlap pdu->isp_private = private; 2010a6d42e7dSPeter Dunlap pdu->isp_callback = cb; 2011a6d42e7dSPeter Dunlap } 2012a6d42e7dSPeter Dunlap 2013a6d42e7dSPeter Dunlap /* 2014a6d42e7dSPeter Dunlap * Initialize the header and header length field. This function should 2015a6d42e7dSPeter Dunlap * not be used to adjust the header length in a buffer allocated via 2016a6d42e7dSPeter Dunlap * pdu_pdu_alloc since it overwrites the existing header pointer. 2017a6d42e7dSPeter Dunlap */ 2018a6d42e7dSPeter Dunlap void 2019a6d42e7dSPeter Dunlap idm_pdu_init_hdr(idm_pdu_t *pdu, uint8_t *hdr, uint_t hdrlen) 2020a6d42e7dSPeter Dunlap { 2021a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)((void *)hdr); 2022a6d42e7dSPeter Dunlap pdu->isp_hdrlen = hdrlen; 2023a6d42e7dSPeter Dunlap } 2024a6d42e7dSPeter Dunlap 2025a6d42e7dSPeter Dunlap /* 2026a6d42e7dSPeter Dunlap * Initialize the data and data length fields. This function should 2027a6d42e7dSPeter Dunlap * not be used to adjust the data length of a buffer allocated via 2028a6d42e7dSPeter Dunlap * idm_pdu_alloc since it overwrites the existing data pointer. 2029a6d42e7dSPeter Dunlap */ 2030a6d42e7dSPeter Dunlap void 2031a6d42e7dSPeter Dunlap idm_pdu_init_data(idm_pdu_t *pdu, uint8_t *data, uint_t datalen) 2032a6d42e7dSPeter Dunlap { 2033a6d42e7dSPeter Dunlap pdu->isp_data = data; 2034a6d42e7dSPeter Dunlap pdu->isp_datalen = datalen; 2035a6d42e7dSPeter Dunlap } 2036a6d42e7dSPeter Dunlap 2037a6d42e7dSPeter Dunlap void 2038a6d42e7dSPeter Dunlap idm_pdu_complete(idm_pdu_t *pdu, idm_status_t status) 2039a6d42e7dSPeter Dunlap { 2040a6d42e7dSPeter Dunlap if (pdu->isp_callback) { 2041a6d42e7dSPeter Dunlap pdu->isp_status = status; 2042a6d42e7dSPeter Dunlap (*pdu->isp_callback)(pdu, status); 2043a6d42e7dSPeter Dunlap } else { 2044a6d42e7dSPeter Dunlap idm_pdu_free(pdu); 2045a6d42e7dSPeter Dunlap } 2046a6d42e7dSPeter Dunlap } 2047a6d42e7dSPeter Dunlap 2048a6d42e7dSPeter Dunlap /* 2049a6d42e7dSPeter Dunlap * State machine auditing 2050a6d42e7dSPeter Dunlap */ 2051a6d42e7dSPeter Dunlap 2052a6d42e7dSPeter Dunlap void 2053a6d42e7dSPeter Dunlap idm_sm_audit_init(sm_audit_buf_t *audit_buf) 2054a6d42e7dSPeter Dunlap { 2055a6d42e7dSPeter Dunlap bzero(audit_buf, sizeof (sm_audit_buf_t)); 2056a6d42e7dSPeter Dunlap audit_buf->sab_max_index = SM_AUDIT_BUF_MAX_REC - 1; 2057a6d42e7dSPeter Dunlap } 2058a6d42e7dSPeter Dunlap 2059a6d42e7dSPeter Dunlap static 2060a6d42e7dSPeter Dunlap sm_audit_record_t * 2061a6d42e7dSPeter Dunlap idm_sm_audit_common(sm_audit_buf_t *audit_buf, sm_audit_record_type_t r_type, 2062a6d42e7dSPeter Dunlap sm_audit_sm_type_t sm_type, 2063a6d42e7dSPeter Dunlap int current_state) 2064a6d42e7dSPeter Dunlap { 2065a6d42e7dSPeter Dunlap sm_audit_record_t *sar; 2066a6d42e7dSPeter Dunlap 2067a6d42e7dSPeter Dunlap sar = audit_buf->sab_records; 2068a6d42e7dSPeter Dunlap sar += audit_buf->sab_index; 2069a6d42e7dSPeter Dunlap audit_buf->sab_index++; 2070a6d42e7dSPeter Dunlap audit_buf->sab_index &= audit_buf->sab_max_index; 2071a6d42e7dSPeter Dunlap 2072a6d42e7dSPeter Dunlap sar->sar_type = r_type; 2073a6d42e7dSPeter Dunlap gethrestime(&sar->sar_timestamp); 2074a6d42e7dSPeter Dunlap sar->sar_sm_type = sm_type; 2075a6d42e7dSPeter Dunlap sar->sar_state = current_state; 2076a6d42e7dSPeter Dunlap 2077a6d42e7dSPeter Dunlap return (sar); 2078a6d42e7dSPeter Dunlap } 2079a6d42e7dSPeter Dunlap 2080a6d42e7dSPeter Dunlap void 2081a6d42e7dSPeter Dunlap idm_sm_audit_event(sm_audit_buf_t *audit_buf, 2082a6d42e7dSPeter Dunlap sm_audit_sm_type_t sm_type, int current_state, 2083a6d42e7dSPeter Dunlap int event, uintptr_t event_info) 2084a6d42e7dSPeter Dunlap { 2085a6d42e7dSPeter Dunlap sm_audit_record_t *sar; 2086a6d42e7dSPeter Dunlap 2087a6d42e7dSPeter Dunlap sar = idm_sm_audit_common(audit_buf, SAR_STATE_EVENT, 2088a6d42e7dSPeter Dunlap sm_type, current_state); 2089a6d42e7dSPeter Dunlap sar->sar_event = event; 2090a6d42e7dSPeter Dunlap sar->sar_event_info = event_info; 2091a6d42e7dSPeter Dunlap } 2092a6d42e7dSPeter Dunlap 2093a6d42e7dSPeter Dunlap void 2094a6d42e7dSPeter Dunlap idm_sm_audit_state_change(sm_audit_buf_t *audit_buf, 2095a6d42e7dSPeter Dunlap sm_audit_sm_type_t sm_type, int current_state, int new_state) 2096a6d42e7dSPeter Dunlap { 2097a6d42e7dSPeter Dunlap sm_audit_record_t *sar; 2098a6d42e7dSPeter Dunlap 2099a6d42e7dSPeter Dunlap sar = idm_sm_audit_common(audit_buf, SAR_STATE_CHANGE, 2100a6d42e7dSPeter Dunlap sm_type, current_state); 2101a6d42e7dSPeter Dunlap sar->sar_new_state = new_state; 2102a6d42e7dSPeter Dunlap } 2103a6d42e7dSPeter Dunlap 2104a6d42e7dSPeter Dunlap 2105a6d42e7dSPeter Dunlap /* 2106a6d42e7dSPeter Dunlap * Object reference tracking 2107a6d42e7dSPeter Dunlap */ 2108a6d42e7dSPeter Dunlap 2109a6d42e7dSPeter Dunlap void 2110a6d42e7dSPeter Dunlap idm_refcnt_init(idm_refcnt_t *refcnt, void *referenced_obj) 2111a6d42e7dSPeter Dunlap { 2112a6d42e7dSPeter Dunlap bzero(refcnt, sizeof (*refcnt)); 2113a6d42e7dSPeter Dunlap idm_refcnt_reset(refcnt); 2114a6d42e7dSPeter Dunlap refcnt->ir_referenced_obj = referenced_obj; 2115a6d42e7dSPeter Dunlap bzero(&refcnt->ir_audit_buf, sizeof (refcnt_audit_buf_t)); 2116a6d42e7dSPeter Dunlap refcnt->ir_audit_buf.anb_max_index = REFCNT_AUDIT_BUF_MAX_REC - 1; 2117a6d42e7dSPeter Dunlap mutex_init(&refcnt->ir_mutex, NULL, MUTEX_DEFAULT, NULL); 2118a6d42e7dSPeter Dunlap cv_init(&refcnt->ir_cv, NULL, CV_DEFAULT, NULL); 2119a6d42e7dSPeter Dunlap } 2120a6d42e7dSPeter Dunlap 2121a6d42e7dSPeter Dunlap void 2122a6d42e7dSPeter Dunlap idm_refcnt_destroy(idm_refcnt_t *refcnt) 2123a6d42e7dSPeter Dunlap { 212472cf3143Speter dunlap /* 212572cf3143Speter dunlap * Grab the mutex to there are no other lingering threads holding 212672cf3143Speter dunlap * the mutex before we destroy it (e.g. idm_refcnt_rele just after 212772cf3143Speter dunlap * the refcnt goes to zero if ir_waiting == REF_WAIT_ASYNC) 212872cf3143Speter dunlap */ 212972cf3143Speter dunlap mutex_enter(&refcnt->ir_mutex); 2130a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_refcnt == 0); 2131a6d42e7dSPeter Dunlap cv_destroy(&refcnt->ir_cv); 2132a6d42e7dSPeter Dunlap mutex_destroy(&refcnt->ir_mutex); 2133a6d42e7dSPeter Dunlap } 2134a6d42e7dSPeter Dunlap 2135a6d42e7dSPeter Dunlap void 2136a6d42e7dSPeter Dunlap idm_refcnt_reset(idm_refcnt_t *refcnt) 2137a6d42e7dSPeter Dunlap { 2138a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_NOWAIT; 2139a6d42e7dSPeter Dunlap refcnt->ir_refcnt = 0; 2140a6d42e7dSPeter Dunlap } 2141a6d42e7dSPeter Dunlap 2142a6d42e7dSPeter Dunlap void 2143a6d42e7dSPeter Dunlap idm_refcnt_hold(idm_refcnt_t *refcnt) 2144a6d42e7dSPeter Dunlap { 2145a6d42e7dSPeter Dunlap /* 2146a6d42e7dSPeter Dunlap * Nothing should take a hold on an object after a call to 2147a6d42e7dSPeter Dunlap * idm_refcnt_wait_ref or idm_refcnd_async_wait_ref 2148a6d42e7dSPeter Dunlap */ 2149a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_waiting == REF_NOWAIT); 2150a6d42e7dSPeter Dunlap 2151a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 2152a6d42e7dSPeter Dunlap refcnt->ir_refcnt++; 2153a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 2154a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2155a6d42e7dSPeter Dunlap } 2156a6d42e7dSPeter Dunlap 2157a6d42e7dSPeter Dunlap static void 2158a6d42e7dSPeter Dunlap idm_refcnt_unref_task(void *refcnt_void) 2159a6d42e7dSPeter Dunlap { 2160a6d42e7dSPeter Dunlap idm_refcnt_t *refcnt = refcnt_void; 2161a6d42e7dSPeter Dunlap 2162a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 2163a6d42e7dSPeter Dunlap (*refcnt->ir_cb)(refcnt->ir_referenced_obj); 2164a6d42e7dSPeter Dunlap } 2165a6d42e7dSPeter Dunlap 2166a6d42e7dSPeter Dunlap void 2167a6d42e7dSPeter Dunlap idm_refcnt_rele(idm_refcnt_t *refcnt) 2168a6d42e7dSPeter Dunlap { 2169a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 2170a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_refcnt > 0); 2171a6d42e7dSPeter Dunlap refcnt->ir_refcnt--; 2172a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 2173a6d42e7dSPeter Dunlap if (refcnt->ir_waiting == REF_NOWAIT) { 2174a6d42e7dSPeter Dunlap /* No one is waiting on this object */ 2175a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2176a6d42e7dSPeter Dunlap return; 2177a6d42e7dSPeter Dunlap } 2178a6d42e7dSPeter Dunlap 2179a6d42e7dSPeter Dunlap /* 2180a6d42e7dSPeter Dunlap * Someone is waiting for this object to go idle so check if 2181a6d42e7dSPeter Dunlap * refcnt is 0. Waiting on an object then later grabbing another 2182a6d42e7dSPeter Dunlap * reference is not allowed so we don't need to handle that case. 2183a6d42e7dSPeter Dunlap */ 2184a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) { 2185a6d42e7dSPeter Dunlap if (refcnt->ir_waiting == REF_WAIT_ASYNC) { 2186a6d42e7dSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq, 2187fc8ae2ecSToomas Soome &idm_refcnt_unref_task, refcnt, TQ_SLEEP) == 2188fc8ae2ecSToomas Soome TASKQID_INVALID) { 2189a6d42e7dSPeter Dunlap cmn_err(CE_WARN, 2190a6d42e7dSPeter Dunlap "idm_refcnt_rele: Couldn't dispatch task"); 2191a6d42e7dSPeter Dunlap } 2192a6d42e7dSPeter Dunlap } else if (refcnt->ir_waiting == REF_WAIT_SYNC) { 2193a6d42e7dSPeter Dunlap cv_signal(&refcnt->ir_cv); 2194a6d42e7dSPeter Dunlap } 2195a6d42e7dSPeter Dunlap } 2196a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2197a6d42e7dSPeter Dunlap } 2198a6d42e7dSPeter Dunlap 2199a6d42e7dSPeter Dunlap void 2200a6d42e7dSPeter Dunlap idm_refcnt_rele_and_destroy(idm_refcnt_t *refcnt, idm_refcnt_cb_t *cb_func) 2201a6d42e7dSPeter Dunlap { 2202a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 2203a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_refcnt > 0); 2204a6d42e7dSPeter Dunlap refcnt->ir_refcnt--; 2205a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 2206a6d42e7dSPeter Dunlap 2207a6d42e7dSPeter Dunlap /* 2208a6d42e7dSPeter Dunlap * Someone is waiting for this object to go idle so check if 2209a6d42e7dSPeter Dunlap * refcnt is 0. Waiting on an object then later grabbing another 2210a6d42e7dSPeter Dunlap * reference is not allowed so we don't need to handle that case. 2211a6d42e7dSPeter Dunlap */ 2212a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) { 2213a6d42e7dSPeter Dunlap refcnt->ir_cb = cb_func; 2214a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_WAIT_ASYNC; 2215a6d42e7dSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq, 22168e718be9SToomas Soome &idm_refcnt_unref_task, refcnt, TQ_SLEEP) == 22178e718be9SToomas Soome TASKQID_INVALID) { 2218a6d42e7dSPeter Dunlap cmn_err(CE_WARN, 2219a6d42e7dSPeter Dunlap "idm_refcnt_rele: Couldn't dispatch task"); 2220a6d42e7dSPeter Dunlap } 2221a6d42e7dSPeter Dunlap } 2222a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2223a6d42e7dSPeter Dunlap } 2224a6d42e7dSPeter Dunlap 2225a6d42e7dSPeter Dunlap void 2226a6d42e7dSPeter Dunlap idm_refcnt_wait_ref(idm_refcnt_t *refcnt) 2227a6d42e7dSPeter Dunlap { 2228a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 2229a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_WAIT_SYNC; 2230a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 2231a6d42e7dSPeter Dunlap while (refcnt->ir_refcnt != 0) 2232a6d42e7dSPeter Dunlap cv_wait(&refcnt->ir_cv, &refcnt->ir_mutex); 2233a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2234a6d42e7dSPeter Dunlap } 2235a6d42e7dSPeter Dunlap 2236a6d42e7dSPeter Dunlap void 2237a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(idm_refcnt_t *refcnt, idm_refcnt_cb_t *cb_func) 2238a6d42e7dSPeter Dunlap { 2239a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 2240a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_WAIT_ASYNC; 2241a6d42e7dSPeter Dunlap refcnt->ir_cb = cb_func; 2242a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 2243a6d42e7dSPeter Dunlap /* 2244a6d42e7dSPeter Dunlap * It's possible we don't have any references. To make things easier 2245a6d42e7dSPeter Dunlap * on the caller use a taskq to call the callback instead of 2246a6d42e7dSPeter Dunlap * calling it synchronously 2247a6d42e7dSPeter Dunlap */ 2248a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) { 2249a6d42e7dSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq, 2250fc8ae2ecSToomas Soome &idm_refcnt_unref_task, refcnt, TQ_SLEEP) == 2251fc8ae2ecSToomas Soome TASKQID_INVALID) { 2252a6d42e7dSPeter Dunlap cmn_err(CE_WARN, 2253a6d42e7dSPeter Dunlap "idm_refcnt_async_wait_ref: " 2254a6d42e7dSPeter Dunlap "Couldn't dispatch task"); 2255a6d42e7dSPeter Dunlap } 2256a6d42e7dSPeter Dunlap } 2257a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2258a6d42e7dSPeter Dunlap } 2259a6d42e7dSPeter Dunlap 2260a6d42e7dSPeter Dunlap void 2261a6d42e7dSPeter Dunlap idm_refcnt_destroy_unref_obj(idm_refcnt_t *refcnt, 2262a6d42e7dSPeter Dunlap idm_refcnt_cb_t *cb_func) 2263a6d42e7dSPeter Dunlap { 2264a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 2265a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) { 2266a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2267a6d42e7dSPeter Dunlap (*cb_func)(refcnt->ir_referenced_obj); 2268a6d42e7dSPeter Dunlap return; 2269a6d42e7dSPeter Dunlap } 2270a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2271a6d42e7dSPeter Dunlap } 2272a6d42e7dSPeter Dunlap 2273*61dfa509SRick McNeal /* 2274*61dfa509SRick McNeal * used to determine the status of the refcnt. 2275*61dfa509SRick McNeal * 2276*61dfa509SRick McNeal * if refcnt is 0 return is 0 2277*61dfa509SRick McNeal * if refcnt is negative return is -1 2278*61dfa509SRick McNeal * if refcnt > 0 and no waiters return is 1 2279*61dfa509SRick McNeal * if refcnt > 0 and waiters return is 2 2280*61dfa509SRick McNeal */ 2281*61dfa509SRick McNeal int 2282*61dfa509SRick McNeal idm_refcnt_is_held(idm_refcnt_t *refcnt) 2283*61dfa509SRick McNeal { 2284*61dfa509SRick McNeal if (refcnt->ir_refcnt < 0) 2285*61dfa509SRick McNeal return (-1); 2286*61dfa509SRick McNeal 2287*61dfa509SRick McNeal if (refcnt->ir_refcnt == 0) 2288*61dfa509SRick McNeal return (0); 2289*61dfa509SRick McNeal 2290*61dfa509SRick McNeal if (refcnt->ir_waiting == REF_NOWAIT && refcnt->ir_refcnt > 0) 2291*61dfa509SRick McNeal return (1); 2292*61dfa509SRick McNeal 2293*61dfa509SRick McNeal return (2); 2294*61dfa509SRick McNeal } 2295*61dfa509SRick McNeal 2296a6d42e7dSPeter Dunlap void 2297a6d42e7dSPeter Dunlap idm_conn_hold(idm_conn_t *ic) 2298a6d42e7dSPeter Dunlap { 2299a6d42e7dSPeter Dunlap idm_refcnt_hold(&ic->ic_refcnt); 2300a6d42e7dSPeter Dunlap } 2301a6d42e7dSPeter Dunlap 2302a6d42e7dSPeter Dunlap void 2303a6d42e7dSPeter Dunlap idm_conn_rele(idm_conn_t *ic) 2304a6d42e7dSPeter Dunlap { 2305a6d42e7dSPeter Dunlap idm_refcnt_rele(&ic->ic_refcnt); 2306a6d42e7dSPeter Dunlap } 2307a6d42e7dSPeter Dunlap 2308a668b114SPriya Krishnan void 2309a668b114SPriya Krishnan idm_conn_set_target_name(idm_conn_t *ic, char *target_name) 2310a668b114SPriya Krishnan { 2311a668b114SPriya Krishnan (void) strlcpy(ic->ic_target_name, target_name, ISCSI_MAX_NAME_LEN + 1); 2312a668b114SPriya Krishnan } 2313a668b114SPriya Krishnan 2314a668b114SPriya Krishnan void 2315a668b114SPriya Krishnan idm_conn_set_initiator_name(idm_conn_t *ic, char *initiator_name) 2316a668b114SPriya Krishnan { 2317a668b114SPriya Krishnan (void) strlcpy(ic->ic_initiator_name, initiator_name, 2318a668b114SPriya Krishnan ISCSI_MAX_NAME_LEN + 1); 2319a668b114SPriya Krishnan } 2320a668b114SPriya Krishnan 2321a668b114SPriya Krishnan void 2322a668b114SPriya Krishnan idm_conn_set_isid(idm_conn_t *ic, uint8_t isid[ISCSI_ISID_LEN]) 2323a668b114SPriya Krishnan { 2324a668b114SPriya Krishnan (void) snprintf(ic->ic_isid, ISCSI_MAX_ISID_LEN + 1, 2325a668b114SPriya Krishnan "%02x%02x%02x%02x%02x%02x", 2326a668b114SPriya Krishnan isid[0], isid[1], isid[2], isid[3], isid[4], isid[5]); 2327a668b114SPriya Krishnan } 2328a6d42e7dSPeter Dunlap 2329a6d42e7dSPeter Dunlap static int 2330a6d42e7dSPeter Dunlap _idm_init(void) 2331a6d42e7dSPeter Dunlap { 2332a6d42e7dSPeter Dunlap /* Initialize the rwlock for the taskid table */ 2333a6d42e7dSPeter Dunlap rw_init(&idm.idm_taskid_table_lock, NULL, RW_DRIVER, NULL); 2334a6d42e7dSPeter Dunlap 2335a6d42e7dSPeter Dunlap /* Initialize the global mutex and taskq */ 2336a6d42e7dSPeter Dunlap mutex_init(&idm.idm_global_mutex, NULL, MUTEX_DEFAULT, NULL); 2337a6d42e7dSPeter Dunlap 2338a6d42e7dSPeter Dunlap cv_init(&idm.idm_tgt_svc_cv, NULL, CV_DEFAULT, NULL); 2339a6d42e7dSPeter Dunlap cv_init(&idm.idm_wd_cv, NULL, CV_DEFAULT, NULL); 2340a6d42e7dSPeter Dunlap 234130e7468fSPeter Dunlap /* 234230e7468fSPeter Dunlap * The maximum allocation needs to be high here since there can be 234330e7468fSPeter Dunlap * many concurrent tasks using the global taskq. 234430e7468fSPeter Dunlap */ 2345a6d42e7dSPeter Dunlap idm.idm_global_taskq = taskq_create("idm_global_taskq", 1, minclsyspri, 234630e7468fSPeter Dunlap 128, 16384, TASKQ_PREPOPULATE); 2347a6d42e7dSPeter Dunlap if (idm.idm_global_taskq == NULL) { 2348a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_wd_cv); 2349a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_tgt_svc_cv); 2350a6d42e7dSPeter Dunlap mutex_destroy(&idm.idm_global_mutex); 2351a6d42e7dSPeter Dunlap rw_destroy(&idm.idm_taskid_table_lock); 2352a6d42e7dSPeter Dunlap return (ENOMEM); 2353a6d42e7dSPeter Dunlap } 2354a6d42e7dSPeter Dunlap 2355a41f9819SJames Moore /* Start watchdog thread */ 2356a6d42e7dSPeter Dunlap idm.idm_wd_thread = thread_create(NULL, 0, 2357a6d42e7dSPeter Dunlap idm_wd_thread, NULL, 0, &p0, TS_RUN, minclsyspri); 2358a6d42e7dSPeter Dunlap if (idm.idm_wd_thread == NULL) { 2359a6d42e7dSPeter Dunlap /* Couldn't create the watchdog thread */ 2360a6d42e7dSPeter Dunlap taskq_destroy(idm.idm_global_taskq); 2361a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_wd_cv); 2362a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_tgt_svc_cv); 2363a6d42e7dSPeter Dunlap mutex_destroy(&idm.idm_global_mutex); 2364a6d42e7dSPeter Dunlap rw_destroy(&idm.idm_taskid_table_lock); 2365a6d42e7dSPeter Dunlap return (ENOMEM); 2366a6d42e7dSPeter Dunlap } 2367a6d42e7dSPeter Dunlap 2368a41f9819SJames Moore /* Pause until the watchdog thread is running */ 2369a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 2370a6d42e7dSPeter Dunlap while (!idm.idm_wd_thread_running) 2371a6d42e7dSPeter Dunlap cv_wait(&idm.idm_wd_cv, &idm.idm_global_mutex); 2372a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 2373a6d42e7dSPeter Dunlap 2374a6d42e7dSPeter Dunlap /* 2375a6d42e7dSPeter Dunlap * Allocate the task ID table and set "next" to 0. 2376a6d42e7dSPeter Dunlap */ 2377a6d42e7dSPeter Dunlap 2378a6d42e7dSPeter Dunlap idm.idm_taskid_max = idm_max_taskids; 2379a6d42e7dSPeter Dunlap idm.idm_taskid_table = (idm_task_t **) 2380a6d42e7dSPeter Dunlap kmem_zalloc(idm.idm_taskid_max * sizeof (idm_task_t *), KM_SLEEP); 2381a6d42e7dSPeter Dunlap idm.idm_taskid_next = 0; 2382a6d42e7dSPeter Dunlap 2383a6d42e7dSPeter Dunlap /* Create the global buffer and task kmem caches */ 2384a6d42e7dSPeter Dunlap idm.idm_buf_cache = kmem_cache_create("idm_buf_cache", 2385a6d42e7dSPeter Dunlap sizeof (idm_buf_t), 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP); 2386a6d42e7dSPeter Dunlap 2387a6d42e7dSPeter Dunlap /* 2388a6d42e7dSPeter Dunlap * Note, we're explicitly allocating an additional iSER header- 2389a6d42e7dSPeter Dunlap * sized chunk for each of these elements. See idm_task_constructor(). 2390a6d42e7dSPeter Dunlap */ 2391a6d42e7dSPeter Dunlap idm.idm_task_cache = kmem_cache_create("idm_task_cache", 2392a6d42e7dSPeter Dunlap sizeof (idm_task_t) + IDM_TRANSPORT_HEADER_LENGTH, 8, 2393a6d42e7dSPeter Dunlap &idm_task_constructor, &idm_task_destructor, 2394a6d42e7dSPeter Dunlap NULL, NULL, NULL, KM_SLEEP); 2395a6d42e7dSPeter Dunlap 2396a6d42e7dSPeter Dunlap /* Create the service and connection context lists */ 2397a6d42e7dSPeter Dunlap list_create(&idm.idm_tgt_svc_list, sizeof (idm_svc_t), 2398a6d42e7dSPeter Dunlap offsetof(idm_svc_t, is_list_node)); 2399a6d42e7dSPeter Dunlap list_create(&idm.idm_tgt_conn_list, sizeof (idm_conn_t), 2400a6d42e7dSPeter Dunlap offsetof(idm_conn_t, ic_list_node)); 2401a6d42e7dSPeter Dunlap list_create(&idm.idm_ini_conn_list, sizeof (idm_conn_t), 2402a6d42e7dSPeter Dunlap offsetof(idm_conn_t, ic_list_node)); 2403a6d42e7dSPeter Dunlap 2404a6d42e7dSPeter Dunlap /* Initialize the native sockets transport */ 2405a6d42e7dSPeter Dunlap idm_so_init(&idm_transport_list[IDM_TRANSPORT_TYPE_SOCKETS]); 2406a6d42e7dSPeter Dunlap 2407a6d42e7dSPeter Dunlap /* Create connection ID pool */ 2408a6d42e7dSPeter Dunlap (void) idm_idpool_create(&idm.idm_conn_id_pool); 2409a6d42e7dSPeter Dunlap 2410a6d42e7dSPeter Dunlap return (DDI_SUCCESS); 2411a6d42e7dSPeter Dunlap } 2412a6d42e7dSPeter Dunlap 2413a6d42e7dSPeter Dunlap static int 2414a6d42e7dSPeter Dunlap _idm_fini(void) 2415a6d42e7dSPeter Dunlap { 2416a6d42e7dSPeter Dunlap if (!list_is_empty(&idm.idm_ini_conn_list) || 2417a6d42e7dSPeter Dunlap !list_is_empty(&idm.idm_tgt_conn_list) || 2418a6d42e7dSPeter Dunlap !list_is_empty(&idm.idm_tgt_svc_list)) { 2419a6d42e7dSPeter Dunlap return (EBUSY); 2420a6d42e7dSPeter Dunlap } 2421a6d42e7dSPeter Dunlap 2422a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 2423a6d42e7dSPeter Dunlap idm.idm_wd_thread_running = B_FALSE; 2424a6d42e7dSPeter Dunlap cv_signal(&idm.idm_wd_cv); 2425a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 2426a6d42e7dSPeter Dunlap 2427a6d42e7dSPeter Dunlap thread_join(idm.idm_wd_thread_did); 2428a6d42e7dSPeter Dunlap 2429a6d42e7dSPeter Dunlap idm_idpool_destroy(&idm.idm_conn_id_pool); 243030e7468fSPeter Dunlap 243130e7468fSPeter Dunlap /* Close any LDI handles we have open on transport drivers */ 243230e7468fSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 243330e7468fSPeter Dunlap idm_transport_teardown(); 243430e7468fSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 243530e7468fSPeter Dunlap 243630e7468fSPeter Dunlap /* Teardown the native sockets transport */ 2437a6d42e7dSPeter Dunlap idm_so_fini(); 243830e7468fSPeter Dunlap 2439a6d42e7dSPeter Dunlap list_destroy(&idm.idm_ini_conn_list); 2440a6d42e7dSPeter Dunlap list_destroy(&idm.idm_tgt_conn_list); 2441a6d42e7dSPeter Dunlap list_destroy(&idm.idm_tgt_svc_list); 2442a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_task_cache); 2443a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_buf_cache); 2444a6d42e7dSPeter Dunlap kmem_free(idm.idm_taskid_table, 2445a6d42e7dSPeter Dunlap idm.idm_taskid_max * sizeof (idm_task_t *)); 2446a6d42e7dSPeter Dunlap mutex_destroy(&idm.idm_global_mutex); 2447a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_wd_cv); 2448a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_tgt_svc_cv); 2449a6d42e7dSPeter Dunlap rw_destroy(&idm.idm_taskid_table_lock); 2450a6d42e7dSPeter Dunlap 2451a6d42e7dSPeter Dunlap return (0); 2452a6d42e7dSPeter Dunlap } 2453