1*a6d42e7dSPeter Dunlap /* 2*a6d42e7dSPeter Dunlap * CDDL HEADER START 3*a6d42e7dSPeter Dunlap * 4*a6d42e7dSPeter Dunlap * The contents of this file are subject to the terms of the 5*a6d42e7dSPeter Dunlap * Common Development and Distribution License (the "License"). 6*a6d42e7dSPeter Dunlap * You may not use this file except in compliance with the License. 7*a6d42e7dSPeter Dunlap * 8*a6d42e7dSPeter Dunlap * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*a6d42e7dSPeter Dunlap * or http://www.opensolaris.org/os/licensing. 10*a6d42e7dSPeter Dunlap * See the License for the specific language governing permissions 11*a6d42e7dSPeter Dunlap * and limitations under the License. 12*a6d42e7dSPeter Dunlap * 13*a6d42e7dSPeter Dunlap * When distributing Covered Code, include this CDDL HEADER in each 14*a6d42e7dSPeter Dunlap * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*a6d42e7dSPeter Dunlap * If applicable, add the following below this CDDL HEADER, with the 16*a6d42e7dSPeter Dunlap * fields enclosed by brackets "[]" replaced with your own identifying 17*a6d42e7dSPeter Dunlap * information: Portions Copyright [yyyy] [name of copyright owner] 18*a6d42e7dSPeter Dunlap * 19*a6d42e7dSPeter Dunlap * CDDL HEADER END 20*a6d42e7dSPeter Dunlap */ 21*a6d42e7dSPeter Dunlap /* 22*a6d42e7dSPeter Dunlap * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*a6d42e7dSPeter Dunlap * Use is subject to license terms. 24*a6d42e7dSPeter Dunlap */ 25*a6d42e7dSPeter Dunlap 26*a6d42e7dSPeter Dunlap #include <sys/cpuvar.h> 27*a6d42e7dSPeter Dunlap #include <sys/conf.h> 28*a6d42e7dSPeter Dunlap #include <sys/file.h> 29*a6d42e7dSPeter Dunlap #include <sys/ddi.h> 30*a6d42e7dSPeter Dunlap #include <sys/sunddi.h> 31*a6d42e7dSPeter Dunlap #include <sys/modctl.h> 32*a6d42e7dSPeter Dunlap 33*a6d42e7dSPeter Dunlap #include <sys/socket.h> 34*a6d42e7dSPeter Dunlap #include <sys/strsubr.h> 35*a6d42e7dSPeter Dunlap #include <sys/sysmacros.h> 36*a6d42e7dSPeter Dunlap 37*a6d42e7dSPeter Dunlap #include <sys/socketvar.h> 38*a6d42e7dSPeter Dunlap #include <netinet/in.h> 39*a6d42e7dSPeter Dunlap 40*a6d42e7dSPeter Dunlap #include <sys/idm/idm.h> 41*a6d42e7dSPeter Dunlap #include <sys/idm/idm_so.h> 42*a6d42e7dSPeter Dunlap 43*a6d42e7dSPeter Dunlap #define IDM_NAME_VERSION "iSCSI Data Mover" 44*a6d42e7dSPeter Dunlap 45*a6d42e7dSPeter Dunlap extern struct mod_ops mod_miscops; 46*a6d42e7dSPeter Dunlap extern struct mod_ops mod_miscops; 47*a6d42e7dSPeter Dunlap 48*a6d42e7dSPeter Dunlap static struct modlmisc modlmisc = { 49*a6d42e7dSPeter Dunlap &mod_miscops, /* Type of module */ 50*a6d42e7dSPeter Dunlap IDM_NAME_VERSION 51*a6d42e7dSPeter Dunlap }; 52*a6d42e7dSPeter Dunlap 53*a6d42e7dSPeter Dunlap static struct modlinkage modlinkage = { 54*a6d42e7dSPeter Dunlap MODREV_1, (void *)&modlmisc, NULL 55*a6d42e7dSPeter Dunlap }; 56*a6d42e7dSPeter Dunlap 57*a6d42e7dSPeter Dunlap extern int idm_task_compare(const void *t1, const void *t2); 58*a6d42e7dSPeter Dunlap extern void idm_wd_thread(void *arg); 59*a6d42e7dSPeter Dunlap 60*a6d42e7dSPeter Dunlap static int _idm_init(void); 61*a6d42e7dSPeter Dunlap static int _idm_fini(void); 62*a6d42e7dSPeter Dunlap static void idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf); 63*a6d42e7dSPeter Dunlap static void idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf); 64*a6d42e7dSPeter Dunlap static void idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf); 65*a6d42e7dSPeter Dunlap static void idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf); 66*a6d42e7dSPeter Dunlap static void idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt, 67*a6d42e7dSPeter Dunlap idm_abort_type_t abort_type); 68*a6d42e7dSPeter Dunlap static void idm_task_aborted(idm_task_t *idt, idm_status_t status); 69*a6d42e7dSPeter Dunlap 70*a6d42e7dSPeter Dunlap boolean_t idm_conn_logging = 0; 71*a6d42e7dSPeter Dunlap boolean_t idm_svc_logging = 0; 72*a6d42e7dSPeter Dunlap 73*a6d42e7dSPeter Dunlap /* 74*a6d42e7dSPeter Dunlap * Potential tuneable for the maximum number of tasks. Default to 75*a6d42e7dSPeter Dunlap * IDM_TASKIDS_MAX 76*a6d42e7dSPeter Dunlap */ 77*a6d42e7dSPeter Dunlap 78*a6d42e7dSPeter Dunlap uint32_t idm_max_taskids = IDM_TASKIDS_MAX; 79*a6d42e7dSPeter Dunlap 80*a6d42e7dSPeter Dunlap /* 81*a6d42e7dSPeter Dunlap * Global list of transport handles 82*a6d42e7dSPeter Dunlap * These are listed in preferential order, so we can simply take the 83*a6d42e7dSPeter Dunlap * first "it_conn_is_capable" hit. Note also that the order maps to 84*a6d42e7dSPeter Dunlap * the order of the idm_transport_type_t list. 85*a6d42e7dSPeter Dunlap */ 86*a6d42e7dSPeter Dunlap idm_transport_t idm_transport_list[] = { 87*a6d42e7dSPeter Dunlap 88*a6d42e7dSPeter Dunlap /* iSER on InfiniBand transport handle */ 89*a6d42e7dSPeter Dunlap {IDM_TRANSPORT_TYPE_ISER, /* type */ 90*a6d42e7dSPeter Dunlap "/devices/ib/iser@0:iser", /* device path */ 91*a6d42e7dSPeter Dunlap NULL, /* LDI handle */ 92*a6d42e7dSPeter Dunlap NULL, /* transport ops */ 93*a6d42e7dSPeter Dunlap NULL}, /* transport caps */ 94*a6d42e7dSPeter Dunlap 95*a6d42e7dSPeter Dunlap /* IDM native sockets transport handle */ 96*a6d42e7dSPeter Dunlap {IDM_TRANSPORT_TYPE_SOCKETS, /* type */ 97*a6d42e7dSPeter Dunlap NULL, /* device path */ 98*a6d42e7dSPeter Dunlap NULL, /* LDI handle */ 99*a6d42e7dSPeter Dunlap NULL, /* transport ops */ 100*a6d42e7dSPeter Dunlap NULL} /* transport caps */ 101*a6d42e7dSPeter Dunlap 102*a6d42e7dSPeter Dunlap }; 103*a6d42e7dSPeter Dunlap 104*a6d42e7dSPeter Dunlap int 105*a6d42e7dSPeter Dunlap _init(void) 106*a6d42e7dSPeter Dunlap { 107*a6d42e7dSPeter Dunlap int rc; 108*a6d42e7dSPeter Dunlap 109*a6d42e7dSPeter Dunlap if ((rc = _idm_init()) != 0) { 110*a6d42e7dSPeter Dunlap return (rc); 111*a6d42e7dSPeter Dunlap } 112*a6d42e7dSPeter Dunlap 113*a6d42e7dSPeter Dunlap return (mod_install(&modlinkage)); 114*a6d42e7dSPeter Dunlap } 115*a6d42e7dSPeter Dunlap 116*a6d42e7dSPeter Dunlap int 117*a6d42e7dSPeter Dunlap _fini(void) 118*a6d42e7dSPeter Dunlap { 119*a6d42e7dSPeter Dunlap int rc; 120*a6d42e7dSPeter Dunlap 121*a6d42e7dSPeter Dunlap if ((rc = _idm_fini()) != 0) { 122*a6d42e7dSPeter Dunlap return (rc); 123*a6d42e7dSPeter Dunlap } 124*a6d42e7dSPeter Dunlap 125*a6d42e7dSPeter Dunlap if ((rc = mod_remove(&modlinkage)) != 0) { 126*a6d42e7dSPeter Dunlap return (rc); 127*a6d42e7dSPeter Dunlap } 128*a6d42e7dSPeter Dunlap 129*a6d42e7dSPeter Dunlap return (rc); 130*a6d42e7dSPeter Dunlap } 131*a6d42e7dSPeter Dunlap 132*a6d42e7dSPeter Dunlap int 133*a6d42e7dSPeter Dunlap _info(struct modinfo *modinfop) 134*a6d42e7dSPeter Dunlap { 135*a6d42e7dSPeter Dunlap return (mod_info(&modlinkage, modinfop)); 136*a6d42e7dSPeter Dunlap } 137*a6d42e7dSPeter Dunlap 138*a6d42e7dSPeter Dunlap /* 139*a6d42e7dSPeter Dunlap * idm_transport_register() 140*a6d42e7dSPeter Dunlap * 141*a6d42e7dSPeter Dunlap * Provides a mechanism for an IDM transport driver to register its 142*a6d42e7dSPeter Dunlap * transport ops and caps with the IDM kernel module. Invoked during 143*a6d42e7dSPeter Dunlap * a transport driver's attach routine. 144*a6d42e7dSPeter Dunlap */ 145*a6d42e7dSPeter Dunlap idm_status_t 146*a6d42e7dSPeter Dunlap idm_transport_register(idm_transport_attr_t *attr) 147*a6d42e7dSPeter Dunlap { 148*a6d42e7dSPeter Dunlap ASSERT(attr->it_ops != NULL); 149*a6d42e7dSPeter Dunlap ASSERT(attr->it_caps != NULL); 150*a6d42e7dSPeter Dunlap 151*a6d42e7dSPeter Dunlap switch (attr->type) { 152*a6d42e7dSPeter Dunlap /* All known non-native transports here; for now, iSER */ 153*a6d42e7dSPeter Dunlap case IDM_TRANSPORT_TYPE_ISER: 154*a6d42e7dSPeter Dunlap idm_transport_list[attr->type].it_ops = attr->it_ops; 155*a6d42e7dSPeter Dunlap idm_transport_list[attr->type].it_caps = attr->it_caps; 156*a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 157*a6d42e7dSPeter Dunlap 158*a6d42e7dSPeter Dunlap default: 159*a6d42e7dSPeter Dunlap cmn_err(CE_NOTE, "idm: unknown transport type (0x%x) in " 160*a6d42e7dSPeter Dunlap "idm_transport_register", attr->type); 161*a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 162*a6d42e7dSPeter Dunlap } 163*a6d42e7dSPeter Dunlap } 164*a6d42e7dSPeter Dunlap 165*a6d42e7dSPeter Dunlap /* 166*a6d42e7dSPeter Dunlap * idm_ini_conn_create 167*a6d42e7dSPeter Dunlap * 168*a6d42e7dSPeter Dunlap * This function is invoked by the iSCSI layer to create a connection context. 169*a6d42e7dSPeter Dunlap * This does not actually establish the socket connection. 170*a6d42e7dSPeter Dunlap * 171*a6d42e7dSPeter Dunlap * cr - Connection request parameters 172*a6d42e7dSPeter Dunlap * new_con - Output parameter that contains the new request if successful 173*a6d42e7dSPeter Dunlap * 174*a6d42e7dSPeter Dunlap */ 175*a6d42e7dSPeter Dunlap idm_status_t 176*a6d42e7dSPeter Dunlap idm_ini_conn_create(idm_conn_req_t *cr, idm_conn_t **new_con) 177*a6d42e7dSPeter Dunlap { 178*a6d42e7dSPeter Dunlap idm_transport_t *it; 179*a6d42e7dSPeter Dunlap idm_conn_t *ic; 180*a6d42e7dSPeter Dunlap int rc; 181*a6d42e7dSPeter Dunlap 182*a6d42e7dSPeter Dunlap it = idm_transport_lookup(cr); 183*a6d42e7dSPeter Dunlap 184*a6d42e7dSPeter Dunlap retry: 185*a6d42e7dSPeter Dunlap ic = idm_conn_create_common(CONN_TYPE_INI, it->it_type, 186*a6d42e7dSPeter Dunlap &cr->icr_conn_ops); 187*a6d42e7dSPeter Dunlap 188*a6d42e7dSPeter Dunlap bcopy(&cr->cr_ini_dst_addr, &ic->ic_ini_dst_addr, 189*a6d42e7dSPeter Dunlap sizeof (cr->cr_ini_dst_addr)); 190*a6d42e7dSPeter Dunlap 191*a6d42e7dSPeter Dunlap /* create the transport-specific connection components */ 192*a6d42e7dSPeter Dunlap rc = it->it_ops->it_ini_conn_create(cr, ic); 193*a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) { 194*a6d42e7dSPeter Dunlap /* cleanup the failed connection */ 195*a6d42e7dSPeter Dunlap idm_conn_destroy_common(ic); 196*a6d42e7dSPeter Dunlap kmem_free(ic, sizeof (idm_conn_t)); 197*a6d42e7dSPeter Dunlap 198*a6d42e7dSPeter Dunlap /* 199*a6d42e7dSPeter Dunlap * It is possible for an IB client to connect to 200*a6d42e7dSPeter Dunlap * an ethernet-only client via an IB-eth gateway. 201*a6d42e7dSPeter Dunlap * Therefore, if we are attempting to use iSER and 202*a6d42e7dSPeter Dunlap * fail, retry with sockets before ultimately 203*a6d42e7dSPeter Dunlap * failing the connection. 204*a6d42e7dSPeter Dunlap */ 205*a6d42e7dSPeter Dunlap if (it->it_type == IDM_TRANSPORT_TYPE_ISER) { 206*a6d42e7dSPeter Dunlap it = &idm_transport_list[IDM_TRANSPORT_TYPE_SOCKETS]; 207*a6d42e7dSPeter Dunlap goto retry; 208*a6d42e7dSPeter Dunlap } 209*a6d42e7dSPeter Dunlap 210*a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 211*a6d42e7dSPeter Dunlap } 212*a6d42e7dSPeter Dunlap 213*a6d42e7dSPeter Dunlap *new_con = ic; 214*a6d42e7dSPeter Dunlap 215*a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 216*a6d42e7dSPeter Dunlap list_insert_tail(&idm.idm_ini_conn_list, ic); 217*a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 218*a6d42e7dSPeter Dunlap 219*a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 220*a6d42e7dSPeter Dunlap } 221*a6d42e7dSPeter Dunlap 222*a6d42e7dSPeter Dunlap /* 223*a6d42e7dSPeter Dunlap * idm_ini_conn_destroy 224*a6d42e7dSPeter Dunlap * 225*a6d42e7dSPeter Dunlap * Releases any resources associated with the connection. This is the 226*a6d42e7dSPeter Dunlap * complement to idm_ini_conn_create. 227*a6d42e7dSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection 228*a6d42e7dSPeter Dunlap * 229*a6d42e7dSPeter Dunlap */ 230*a6d42e7dSPeter Dunlap void 231*a6d42e7dSPeter Dunlap idm_ini_conn_destroy(idm_conn_t *ic) 232*a6d42e7dSPeter Dunlap { 233*a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 234*a6d42e7dSPeter Dunlap list_remove(&idm.idm_ini_conn_list, ic); 235*a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 236*a6d42e7dSPeter Dunlap 237*a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_ini_conn_destroy(ic); 238*a6d42e7dSPeter Dunlap idm_conn_destroy_common(ic); 239*a6d42e7dSPeter Dunlap } 240*a6d42e7dSPeter Dunlap 241*a6d42e7dSPeter Dunlap /* 242*a6d42e7dSPeter Dunlap * idm_ini_conn_connect 243*a6d42e7dSPeter Dunlap * 244*a6d42e7dSPeter Dunlap * Establish connection to the remote system identified in idm_conn_t. 245*a6d42e7dSPeter Dunlap * The connection parameters including the remote IP address were established 246*a6d42e7dSPeter Dunlap * in the call to idm_ini_conn_create. 247*a6d42e7dSPeter Dunlap * 248*a6d42e7dSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection 249*a6d42e7dSPeter Dunlap * 250*a6d42e7dSPeter Dunlap * Returns success if the connection was established, otherwise some kind 251*a6d42e7dSPeter Dunlap * of meaningful error code. 252*a6d42e7dSPeter Dunlap * 253*a6d42e7dSPeter Dunlap * Upon return the initiator can send a "login" request when it is ready. 254*a6d42e7dSPeter Dunlap */ 255*a6d42e7dSPeter Dunlap idm_status_t 256*a6d42e7dSPeter Dunlap idm_ini_conn_connect(idm_conn_t *ic) 257*a6d42e7dSPeter Dunlap { 258*a6d42e7dSPeter Dunlap idm_status_t rc; 259*a6d42e7dSPeter Dunlap 260*a6d42e7dSPeter Dunlap rc = idm_conn_sm_init(ic); 261*a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) { 262*a6d42e7dSPeter Dunlap return (ic->ic_conn_sm_status); 263*a6d42e7dSPeter Dunlap } 264*a6d42e7dSPeter Dunlap /* Kick state machine */ 265*a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_CONNECT_REQ, NULL); 266*a6d42e7dSPeter Dunlap 267*a6d42e7dSPeter Dunlap /* Wait for login flag */ 268*a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 269*a6d42e7dSPeter Dunlap while (!(ic->ic_state_flags & CF_LOGIN_READY) && 270*a6d42e7dSPeter Dunlap !(ic->ic_state_flags & CF_ERROR)) { 271*a6d42e7dSPeter Dunlap cv_wait(&ic->ic_state_cv, &ic->ic_state_mutex); 272*a6d42e7dSPeter Dunlap } 273*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 274*a6d42e7dSPeter Dunlap 275*a6d42e7dSPeter Dunlap if (ic->ic_state_flags & CF_ERROR) { 276*a6d42e7dSPeter Dunlap /* ic->ic_conn_sm_status will contains failure status */ 277*a6d42e7dSPeter Dunlap return (ic->ic_conn_sm_status); 278*a6d42e7dSPeter Dunlap } 279*a6d42e7dSPeter Dunlap 280*a6d42e7dSPeter Dunlap /* Ready to login */ 281*a6d42e7dSPeter Dunlap ASSERT(ic->ic_state_flags & CF_LOGIN_READY); 282*a6d42e7dSPeter Dunlap (void) idm_notify_client(ic, CN_READY_FOR_LOGIN, NULL); 283*a6d42e7dSPeter Dunlap 284*a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 285*a6d42e7dSPeter Dunlap } 286*a6d42e7dSPeter Dunlap 287*a6d42e7dSPeter Dunlap /* 288*a6d42e7dSPeter Dunlap * idm_ini_conn_sm_fini_task() 289*a6d42e7dSPeter Dunlap * 290*a6d42e7dSPeter Dunlap * Dispatch a thread on the global taskq to tear down an initiator connection's 291*a6d42e7dSPeter Dunlap * state machine. Note: We cannot do this from the disconnect thread as we will 292*a6d42e7dSPeter Dunlap * end up in a situation wherein the thread is running on a taskq that it then 293*a6d42e7dSPeter Dunlap * attempts to destroy. 294*a6d42e7dSPeter Dunlap */ 295*a6d42e7dSPeter Dunlap static void 296*a6d42e7dSPeter Dunlap idm_ini_conn_sm_fini_task(void *ic_void) 297*a6d42e7dSPeter Dunlap { 298*a6d42e7dSPeter Dunlap idm_conn_sm_fini((idm_conn_t *)ic_void); 299*a6d42e7dSPeter Dunlap } 300*a6d42e7dSPeter Dunlap 301*a6d42e7dSPeter Dunlap /* 302*a6d42e7dSPeter Dunlap * idm_ini_conn_disconnect 303*a6d42e7dSPeter Dunlap * 304*a6d42e7dSPeter Dunlap * Forces a connection (previously established using idm_ini_conn_connect) 305*a6d42e7dSPeter Dunlap * to perform a controlled shutdown, cleaning up any outstanding requests. 306*a6d42e7dSPeter Dunlap * 307*a6d42e7dSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection 308*a6d42e7dSPeter Dunlap * 309*a6d42e7dSPeter Dunlap * This is synchronous and it will return when the connection has been 310*a6d42e7dSPeter Dunlap * properly shutdown. 311*a6d42e7dSPeter Dunlap */ 312*a6d42e7dSPeter Dunlap /* ARGSUSED */ 313*a6d42e7dSPeter Dunlap void 314*a6d42e7dSPeter Dunlap idm_ini_conn_disconnect(idm_conn_t *ic) 315*a6d42e7dSPeter Dunlap { 316*a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 317*a6d42e7dSPeter Dunlap 318*a6d42e7dSPeter Dunlap if (ic->ic_state_flags == 0) { 319*a6d42e7dSPeter Dunlap /* already disconnected */ 320*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 321*a6d42e7dSPeter Dunlap return; 322*a6d42e7dSPeter Dunlap } 323*a6d42e7dSPeter Dunlap ic->ic_state_flags = 0; 324*a6d42e7dSPeter Dunlap ic->ic_conn_sm_status = 0; 325*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 326*a6d42e7dSPeter Dunlap 327*a6d42e7dSPeter Dunlap /* invoke the transport-specific conn_destroy */ 328*a6d42e7dSPeter Dunlap (void) ic->ic_transport_ops->it_ini_conn_disconnect(ic); 329*a6d42e7dSPeter Dunlap 330*a6d42e7dSPeter Dunlap /* teardown the connection sm */ 331*a6d42e7dSPeter Dunlap (void) taskq_dispatch(idm.idm_global_taskq, &idm_ini_conn_sm_fini_task, 332*a6d42e7dSPeter Dunlap (void *)ic, TQ_SLEEP); 333*a6d42e7dSPeter Dunlap } 334*a6d42e7dSPeter Dunlap 335*a6d42e7dSPeter Dunlap /* 336*a6d42e7dSPeter Dunlap * idm_tgt_svc_create 337*a6d42e7dSPeter Dunlap * 338*a6d42e7dSPeter Dunlap * The target calls this service to obtain a service context for each available 339*a6d42e7dSPeter Dunlap * transport, starting a service of each type related to the IP address and port 340*a6d42e7dSPeter Dunlap * passed. The idm_svc_req_t contains the service parameters. 341*a6d42e7dSPeter Dunlap */ 342*a6d42e7dSPeter Dunlap idm_status_t 343*a6d42e7dSPeter Dunlap idm_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t **new_svc) 344*a6d42e7dSPeter Dunlap { 345*a6d42e7dSPeter Dunlap idm_transport_type_t type; 346*a6d42e7dSPeter Dunlap idm_transport_t *it; 347*a6d42e7dSPeter Dunlap idm_svc_t *is; 348*a6d42e7dSPeter Dunlap int rc; 349*a6d42e7dSPeter Dunlap 350*a6d42e7dSPeter Dunlap *new_svc = NULL; 351*a6d42e7dSPeter Dunlap is = kmem_zalloc(sizeof (idm_svc_t), KM_SLEEP); 352*a6d42e7dSPeter Dunlap 353*a6d42e7dSPeter Dunlap /* Initialize transport-agnostic components of the service handle */ 354*a6d42e7dSPeter Dunlap is->is_svc_req = *sr; 355*a6d42e7dSPeter Dunlap mutex_init(&is->is_mutex, NULL, MUTEX_DEFAULT, NULL); 356*a6d42e7dSPeter Dunlap cv_init(&is->is_cv, NULL, CV_DEFAULT, NULL); 357*a6d42e7dSPeter Dunlap mutex_init(&is->is_count_mutex, NULL, MUTEX_DEFAULT, NULL); 358*a6d42e7dSPeter Dunlap cv_init(&is->is_count_cv, NULL, CV_DEFAULT, NULL); 359*a6d42e7dSPeter Dunlap idm_refcnt_init(&is->is_refcnt, is); 360*a6d42e7dSPeter Dunlap 361*a6d42e7dSPeter Dunlap /* 362*a6d42e7dSPeter Dunlap * Make sure all available transports are setup. We call this now 363*a6d42e7dSPeter Dunlap * instead of at initialization time in case IB has become available 364*a6d42e7dSPeter Dunlap * since we started (hotplug, etc). 365*a6d42e7dSPeter Dunlap */ 366*a6d42e7dSPeter Dunlap idm_transport_setup(sr->sr_li); 367*a6d42e7dSPeter Dunlap 368*a6d42e7dSPeter Dunlap /* 369*a6d42e7dSPeter Dunlap * Loop through the transports, configuring the transport-specific 370*a6d42e7dSPeter Dunlap * components of each one. 371*a6d42e7dSPeter Dunlap */ 372*a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 373*a6d42e7dSPeter Dunlap 374*a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 375*a6d42e7dSPeter Dunlap /* 376*a6d42e7dSPeter Dunlap * If it_ops is NULL then the transport is unconfigured 377*a6d42e7dSPeter Dunlap * and we shouldn't try to start the service. 378*a6d42e7dSPeter Dunlap */ 379*a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 380*a6d42e7dSPeter Dunlap continue; 381*a6d42e7dSPeter Dunlap } 382*a6d42e7dSPeter Dunlap 383*a6d42e7dSPeter Dunlap rc = it->it_ops->it_tgt_svc_create(sr, is); 384*a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) { 385*a6d42e7dSPeter Dunlap /* Teardown any configured services */ 386*a6d42e7dSPeter Dunlap while (type--) { 387*a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 388*a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 389*a6d42e7dSPeter Dunlap continue; 390*a6d42e7dSPeter Dunlap } 391*a6d42e7dSPeter Dunlap it->it_ops->it_tgt_svc_destroy(is); 392*a6d42e7dSPeter Dunlap } 393*a6d42e7dSPeter Dunlap /* Free the svc context and return */ 394*a6d42e7dSPeter Dunlap kmem_free(is, sizeof (idm_svc_t)); 395*a6d42e7dSPeter Dunlap return (rc); 396*a6d42e7dSPeter Dunlap } 397*a6d42e7dSPeter Dunlap } 398*a6d42e7dSPeter Dunlap 399*a6d42e7dSPeter Dunlap *new_svc = is; 400*a6d42e7dSPeter Dunlap 401*a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 402*a6d42e7dSPeter Dunlap list_insert_tail(&idm.idm_tgt_svc_list, is); 403*a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 404*a6d42e7dSPeter Dunlap 405*a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 406*a6d42e7dSPeter Dunlap } 407*a6d42e7dSPeter Dunlap 408*a6d42e7dSPeter Dunlap /* 409*a6d42e7dSPeter Dunlap * idm_tgt_svc_destroy 410*a6d42e7dSPeter Dunlap * 411*a6d42e7dSPeter Dunlap * is - idm_svc_t returned by the call to idm_tgt_svc_create 412*a6d42e7dSPeter Dunlap * 413*a6d42e7dSPeter Dunlap * Cleanup any resources associated with the idm_svc_t. 414*a6d42e7dSPeter Dunlap */ 415*a6d42e7dSPeter Dunlap void 416*a6d42e7dSPeter Dunlap idm_tgt_svc_destroy(idm_svc_t *is) 417*a6d42e7dSPeter Dunlap { 418*a6d42e7dSPeter Dunlap idm_transport_type_t type; 419*a6d42e7dSPeter Dunlap idm_transport_t *it; 420*a6d42e7dSPeter Dunlap 421*a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 422*a6d42e7dSPeter Dunlap /* remove this service from the global list */ 423*a6d42e7dSPeter Dunlap list_remove(&idm.idm_tgt_svc_list, is); 424*a6d42e7dSPeter Dunlap /* wakeup any waiters for service change */ 425*a6d42e7dSPeter Dunlap cv_broadcast(&idm.idm_tgt_svc_cv); 426*a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 427*a6d42e7dSPeter Dunlap 428*a6d42e7dSPeter Dunlap /* tear down the svc resources */ 429*a6d42e7dSPeter Dunlap idm_refcnt_destroy(&is->is_refcnt); 430*a6d42e7dSPeter Dunlap cv_destroy(&is->is_count_cv); 431*a6d42e7dSPeter Dunlap mutex_destroy(&is->is_count_mutex); 432*a6d42e7dSPeter Dunlap cv_destroy(&is->is_cv); 433*a6d42e7dSPeter Dunlap mutex_destroy(&is->is_mutex); 434*a6d42e7dSPeter Dunlap 435*a6d42e7dSPeter Dunlap /* teardown each transport-specific service */ 436*a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 437*a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 438*a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 439*a6d42e7dSPeter Dunlap continue; 440*a6d42e7dSPeter Dunlap } 441*a6d42e7dSPeter Dunlap 442*a6d42e7dSPeter Dunlap it->it_ops->it_tgt_svc_destroy(is); 443*a6d42e7dSPeter Dunlap } 444*a6d42e7dSPeter Dunlap 445*a6d42e7dSPeter Dunlap /* free the svc handle */ 446*a6d42e7dSPeter Dunlap kmem_free(is, sizeof (idm_svc_t)); 447*a6d42e7dSPeter Dunlap } 448*a6d42e7dSPeter Dunlap 449*a6d42e7dSPeter Dunlap void 450*a6d42e7dSPeter Dunlap idm_tgt_svc_hold(idm_svc_t *is) 451*a6d42e7dSPeter Dunlap { 452*a6d42e7dSPeter Dunlap idm_refcnt_hold(&is->is_refcnt); 453*a6d42e7dSPeter Dunlap } 454*a6d42e7dSPeter Dunlap 455*a6d42e7dSPeter Dunlap void 456*a6d42e7dSPeter Dunlap idm_tgt_svc_rele_and_destroy(idm_svc_t *is) 457*a6d42e7dSPeter Dunlap { 458*a6d42e7dSPeter Dunlap idm_refcnt_rele_and_destroy(&is->is_refcnt, 459*a6d42e7dSPeter Dunlap (idm_refcnt_cb_t *)&idm_tgt_svc_destroy); 460*a6d42e7dSPeter Dunlap } 461*a6d42e7dSPeter Dunlap 462*a6d42e7dSPeter Dunlap /* 463*a6d42e7dSPeter Dunlap * idm_tgt_svc_online 464*a6d42e7dSPeter Dunlap * 465*a6d42e7dSPeter Dunlap * is - idm_svc_t returned by the call to idm_tgt_svc_create 466*a6d42e7dSPeter Dunlap * 467*a6d42e7dSPeter Dunlap * Online each transport service, as we want this target to be accessible 468*a6d42e7dSPeter Dunlap * via any configured transport. 469*a6d42e7dSPeter Dunlap * 470*a6d42e7dSPeter Dunlap * When the initiator establishes a new connection to the target, IDM will 471*a6d42e7dSPeter Dunlap * call the "new connect" callback defined in the idm_svc_req_t structure 472*a6d42e7dSPeter Dunlap * and it will pass an idm_conn_t structure representing that new connection. 473*a6d42e7dSPeter Dunlap */ 474*a6d42e7dSPeter Dunlap idm_status_t 475*a6d42e7dSPeter Dunlap idm_tgt_svc_online(idm_svc_t *is) 476*a6d42e7dSPeter Dunlap { 477*a6d42e7dSPeter Dunlap 478*a6d42e7dSPeter Dunlap idm_transport_type_t type; 479*a6d42e7dSPeter Dunlap idm_transport_t *it; 480*a6d42e7dSPeter Dunlap int rc; 481*a6d42e7dSPeter Dunlap int svc_found; 482*a6d42e7dSPeter Dunlap 483*a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 484*a6d42e7dSPeter Dunlap /* Walk through each of the transports and online them */ 485*a6d42e7dSPeter Dunlap if (is->is_online == 0) { 486*a6d42e7dSPeter Dunlap svc_found = 0; 487*a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 488*a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 489*a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 490*a6d42e7dSPeter Dunlap /* transport is not registered */ 491*a6d42e7dSPeter Dunlap continue; 492*a6d42e7dSPeter Dunlap } 493*a6d42e7dSPeter Dunlap 494*a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 495*a6d42e7dSPeter Dunlap rc = it->it_ops->it_tgt_svc_online(is); 496*a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 497*a6d42e7dSPeter Dunlap if (rc == IDM_STATUS_SUCCESS) { 498*a6d42e7dSPeter Dunlap /* We have at least one service running. */ 499*a6d42e7dSPeter Dunlap svc_found = 1; 500*a6d42e7dSPeter Dunlap } 501*a6d42e7dSPeter Dunlap } 502*a6d42e7dSPeter Dunlap } else { 503*a6d42e7dSPeter Dunlap svc_found = 1; 504*a6d42e7dSPeter Dunlap } 505*a6d42e7dSPeter Dunlap if (svc_found) 506*a6d42e7dSPeter Dunlap is->is_online++; 507*a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 508*a6d42e7dSPeter Dunlap 509*a6d42e7dSPeter Dunlap return (svc_found ? IDM_STATUS_SUCCESS : IDM_STATUS_FAIL); 510*a6d42e7dSPeter Dunlap } 511*a6d42e7dSPeter Dunlap 512*a6d42e7dSPeter Dunlap /* 513*a6d42e7dSPeter Dunlap * idm_tgt_svc_offline 514*a6d42e7dSPeter Dunlap * 515*a6d42e7dSPeter Dunlap * is - idm_svc_t returned by the call to idm_tgt_svc_create 516*a6d42e7dSPeter Dunlap * 517*a6d42e7dSPeter Dunlap * Shutdown any online target services. 518*a6d42e7dSPeter Dunlap */ 519*a6d42e7dSPeter Dunlap void 520*a6d42e7dSPeter Dunlap idm_tgt_svc_offline(idm_svc_t *is) 521*a6d42e7dSPeter Dunlap { 522*a6d42e7dSPeter Dunlap idm_transport_type_t type; 523*a6d42e7dSPeter Dunlap idm_transport_t *it; 524*a6d42e7dSPeter Dunlap 525*a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 526*a6d42e7dSPeter Dunlap is->is_online--; 527*a6d42e7dSPeter Dunlap if (is->is_online == 0) { 528*a6d42e7dSPeter Dunlap /* Walk through each of the transports and offline them */ 529*a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) { 530*a6d42e7dSPeter Dunlap it = &idm_transport_list[type]; 531*a6d42e7dSPeter Dunlap if (it->it_ops == NULL) { 532*a6d42e7dSPeter Dunlap /* transport is not registered */ 533*a6d42e7dSPeter Dunlap continue; 534*a6d42e7dSPeter Dunlap } 535*a6d42e7dSPeter Dunlap 536*a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 537*a6d42e7dSPeter Dunlap it->it_ops->it_tgt_svc_offline(is); 538*a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 539*a6d42e7dSPeter Dunlap } 540*a6d42e7dSPeter Dunlap } 541*a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 542*a6d42e7dSPeter Dunlap } 543*a6d42e7dSPeter Dunlap 544*a6d42e7dSPeter Dunlap /* 545*a6d42e7dSPeter Dunlap * idm_tgt_svc_lookup 546*a6d42e7dSPeter Dunlap * 547*a6d42e7dSPeter Dunlap * Lookup a service instance listening on the specified port 548*a6d42e7dSPeter Dunlap */ 549*a6d42e7dSPeter Dunlap 550*a6d42e7dSPeter Dunlap idm_svc_t * 551*a6d42e7dSPeter Dunlap idm_tgt_svc_lookup(uint16_t port) 552*a6d42e7dSPeter Dunlap { 553*a6d42e7dSPeter Dunlap idm_svc_t *result; 554*a6d42e7dSPeter Dunlap 555*a6d42e7dSPeter Dunlap retry: 556*a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 557*a6d42e7dSPeter Dunlap for (result = list_head(&idm.idm_tgt_svc_list); 558*a6d42e7dSPeter Dunlap result != NULL; 559*a6d42e7dSPeter Dunlap result = list_next(&idm.idm_tgt_svc_list, result)) { 560*a6d42e7dSPeter Dunlap if (result->is_svc_req.sr_port == port) { 561*a6d42e7dSPeter Dunlap if (result->is_online == 0) { 562*a6d42e7dSPeter Dunlap /* 563*a6d42e7dSPeter Dunlap * A service exists on this port, but it 564*a6d42e7dSPeter Dunlap * is going away, wait for it to cleanup. 565*a6d42e7dSPeter Dunlap */ 566*a6d42e7dSPeter Dunlap cv_wait(&idm.idm_tgt_svc_cv, 567*a6d42e7dSPeter Dunlap &idm.idm_global_mutex); 568*a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 569*a6d42e7dSPeter Dunlap goto retry; 570*a6d42e7dSPeter Dunlap } 571*a6d42e7dSPeter Dunlap idm_tgt_svc_hold(result); 572*a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 573*a6d42e7dSPeter Dunlap return (result); 574*a6d42e7dSPeter Dunlap } 575*a6d42e7dSPeter Dunlap } 576*a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 577*a6d42e7dSPeter Dunlap 578*a6d42e7dSPeter Dunlap return (NULL); 579*a6d42e7dSPeter Dunlap } 580*a6d42e7dSPeter Dunlap 581*a6d42e7dSPeter Dunlap /* 582*a6d42e7dSPeter Dunlap * idm_negotiate_key_values() 583*a6d42e7dSPeter Dunlap * Give IDM level a chance to negotiate any login parameters it should own. 584*a6d42e7dSPeter Dunlap * -- leave unhandled parameters alone on request_nvl 585*a6d42e7dSPeter Dunlap * -- move all handled parameters to response_nvl with an appropriate response 586*a6d42e7dSPeter Dunlap * -- also add an entry to negotiated_nvl for any accepted parameters 587*a6d42e7dSPeter Dunlap */ 588*a6d42e7dSPeter Dunlap kv_status_t 589*a6d42e7dSPeter Dunlap idm_negotiate_key_values(idm_conn_t *ic, nvlist_t *request_nvl, 590*a6d42e7dSPeter Dunlap nvlist_t *response_nvl, nvlist_t *negotiated_nvl) 591*a6d42e7dSPeter Dunlap { 592*a6d42e7dSPeter Dunlap ASSERT(ic->ic_transport_ops != NULL); 593*a6d42e7dSPeter Dunlap return (ic->ic_transport_ops->it_negotiate_key_values(ic, 594*a6d42e7dSPeter Dunlap request_nvl, response_nvl, negotiated_nvl)); 595*a6d42e7dSPeter Dunlap } 596*a6d42e7dSPeter Dunlap 597*a6d42e7dSPeter Dunlap /* 598*a6d42e7dSPeter Dunlap * idm_notice_key_values() 599*a6d42e7dSPeter Dunlap * Activate at the IDM level any parameters that have been negotiated. 600*a6d42e7dSPeter Dunlap * Passes the set of key value pairs to the transport for activation. 601*a6d42e7dSPeter Dunlap * This will be invoked as the connection is entering full-feature mode. 602*a6d42e7dSPeter Dunlap */ 603*a6d42e7dSPeter Dunlap idm_status_t 604*a6d42e7dSPeter Dunlap idm_notice_key_values(idm_conn_t *ic, nvlist_t *negotiated_nvl) 605*a6d42e7dSPeter Dunlap { 606*a6d42e7dSPeter Dunlap ASSERT(ic->ic_transport_ops != NULL); 607*a6d42e7dSPeter Dunlap return (ic->ic_transport_ops->it_notice_key_values(ic, 608*a6d42e7dSPeter Dunlap negotiated_nvl)); 609*a6d42e7dSPeter Dunlap } 610*a6d42e7dSPeter Dunlap 611*a6d42e7dSPeter Dunlap /* 612*a6d42e7dSPeter Dunlap * idm_buf_tx_to_ini 613*a6d42e7dSPeter Dunlap * 614*a6d42e7dSPeter Dunlap * This is IDM's implementation of the 'Put_Data' operational primitive. 615*a6d42e7dSPeter Dunlap * 616*a6d42e7dSPeter Dunlap * This function is invoked by a target iSCSI layer to request its local 617*a6d42e7dSPeter Dunlap * Datamover layer to transmit the Data-In PDU to the peer iSCSI layer 618*a6d42e7dSPeter Dunlap * on the remote iSCSI node. The I/O buffer represented by 'idb' is 619*a6d42e7dSPeter Dunlap * transferred to the initiator associated with task 'idt'. The connection 620*a6d42e7dSPeter Dunlap * info, contents of the Data-In PDU header, the DataDescriptorIn, BHS, 621*a6d42e7dSPeter Dunlap * and the callback (idb->idb_buf_cb) at transfer completion are 622*a6d42e7dSPeter Dunlap * provided as input. 623*a6d42e7dSPeter Dunlap * 624*a6d42e7dSPeter Dunlap * This data transfer takes place transparently to the remote iSCSI layer, 625*a6d42e7dSPeter Dunlap * i.e. without its participation. 626*a6d42e7dSPeter Dunlap * 627*a6d42e7dSPeter Dunlap * Using sockets, IDM implements the data transfer by segmenting the data 628*a6d42e7dSPeter Dunlap * buffer into appropriately sized iSCSI PDUs and transmitting them to the 629*a6d42e7dSPeter Dunlap * initiator. iSER performs the transfer using RDMA write. 630*a6d42e7dSPeter Dunlap * 631*a6d42e7dSPeter Dunlap */ 632*a6d42e7dSPeter Dunlap idm_status_t 633*a6d42e7dSPeter Dunlap idm_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb, 634*a6d42e7dSPeter Dunlap uint32_t offset, uint32_t xfer_len, 635*a6d42e7dSPeter Dunlap idm_buf_cb_t idb_buf_cb, void *cb_arg) 636*a6d42e7dSPeter Dunlap { 637*a6d42e7dSPeter Dunlap idm_status_t rc; 638*a6d42e7dSPeter Dunlap 639*a6d42e7dSPeter Dunlap idb->idb_bufoffset = offset; 640*a6d42e7dSPeter Dunlap idb->idb_xfer_len = xfer_len; 641*a6d42e7dSPeter Dunlap idb->idb_buf_cb = idb_buf_cb; 642*a6d42e7dSPeter Dunlap idb->idb_cb_arg = cb_arg; 643*a6d42e7dSPeter Dunlap 644*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 645*a6d42e7dSPeter Dunlap switch (idt->idt_state) { 646*a6d42e7dSPeter Dunlap case TASK_ACTIVE: 647*a6d42e7dSPeter Dunlap idt->idt_tx_to_ini_start++; 648*a6d42e7dSPeter Dunlap idm_task_hold(idt); 649*a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idt, idb); 650*a6d42e7dSPeter Dunlap idb->idb_in_transport = B_TRUE; 651*a6d42e7dSPeter Dunlap rc = (*idt->idt_ic->ic_transport_ops->it_buf_tx_to_ini) 652*a6d42e7dSPeter Dunlap (idt, idb); 653*a6d42e7dSPeter Dunlap return (rc); 654*a6d42e7dSPeter Dunlap 655*a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 656*a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 657*a6d42e7dSPeter Dunlap /* 658*a6d42e7dSPeter Dunlap * Bind buffer but don't start a transfer since the task 659*a6d42e7dSPeter Dunlap * is suspended 660*a6d42e7dSPeter Dunlap */ 661*a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idt, idb); 662*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 663*a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 664*a6d42e7dSPeter Dunlap 665*a6d42e7dSPeter Dunlap case TASK_ABORTING: 666*a6d42e7dSPeter Dunlap case TASK_ABORTED: 667*a6d42e7dSPeter Dunlap /* 668*a6d42e7dSPeter Dunlap * Once the task is aborted, any buffers added to the 669*a6d42e7dSPeter Dunlap * idt_inbufv will never get cleaned up, so just return 670*a6d42e7dSPeter Dunlap * SUCCESS. The buffer should get cleaned up by the 671*a6d42e7dSPeter Dunlap * client or framework once task_aborted has completed. 672*a6d42e7dSPeter Dunlap */ 673*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 674*a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 675*a6d42e7dSPeter Dunlap 676*a6d42e7dSPeter Dunlap default: 677*a6d42e7dSPeter Dunlap ASSERT(0); 678*a6d42e7dSPeter Dunlap break; 679*a6d42e7dSPeter Dunlap } 680*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 681*a6d42e7dSPeter Dunlap 682*a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 683*a6d42e7dSPeter Dunlap } 684*a6d42e7dSPeter Dunlap 685*a6d42e7dSPeter Dunlap /* 686*a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini 687*a6d42e7dSPeter Dunlap * 688*a6d42e7dSPeter Dunlap * This is IDM's implementation of the 'Get_Data' operational primitive. 689*a6d42e7dSPeter Dunlap * 690*a6d42e7dSPeter Dunlap * This function is invoked by a target iSCSI layer to request its local 691*a6d42e7dSPeter Dunlap * Datamover layer to retrieve certain data identified by the R2T PDU from the 692*a6d42e7dSPeter Dunlap * peer iSCSI layer on the remote node. The retrieved Data-Out PDU will be 693*a6d42e7dSPeter Dunlap * mapped to the respective buffer by the task tags (ITT & TTT). 694*a6d42e7dSPeter Dunlap * The connection information, contents of an R2T PDU, DataDescriptor, BHS, and 695*a6d42e7dSPeter Dunlap * the callback (idb->idb_buf_cb) notification for data transfer completion are 696*a6d42e7dSPeter Dunlap * are provided as input. 697*a6d42e7dSPeter Dunlap * 698*a6d42e7dSPeter Dunlap * When an iSCSI node sends an R2T PDU to its local Datamover layer, the local 699*a6d42e7dSPeter Dunlap * Datamover layer, the local and remote Datamover layers transparently bring 700*a6d42e7dSPeter Dunlap * about the data transfer requested by the R2T PDU, without the participation 701*a6d42e7dSPeter Dunlap * of the iSCSI layers. 702*a6d42e7dSPeter Dunlap * 703*a6d42e7dSPeter Dunlap * Using sockets, IDM transmits an R2T PDU for each buffer and the rx_data_out() 704*a6d42e7dSPeter Dunlap * assembles the Data-Out PDUs into the buffer. iSER uses RDMA read. 705*a6d42e7dSPeter Dunlap * 706*a6d42e7dSPeter Dunlap */ 707*a6d42e7dSPeter Dunlap idm_status_t 708*a6d42e7dSPeter Dunlap idm_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb, 709*a6d42e7dSPeter Dunlap uint32_t offset, uint32_t xfer_len, 710*a6d42e7dSPeter Dunlap idm_buf_cb_t idb_buf_cb, void *cb_arg) 711*a6d42e7dSPeter Dunlap { 712*a6d42e7dSPeter Dunlap idm_status_t rc; 713*a6d42e7dSPeter Dunlap 714*a6d42e7dSPeter Dunlap idb->idb_bufoffset = offset; 715*a6d42e7dSPeter Dunlap idb->idb_xfer_len = xfer_len; 716*a6d42e7dSPeter Dunlap idb->idb_buf_cb = idb_buf_cb; 717*a6d42e7dSPeter Dunlap idb->idb_cb_arg = cb_arg; 718*a6d42e7dSPeter Dunlap 719*a6d42e7dSPeter Dunlap /* 720*a6d42e7dSPeter Dunlap * "In" buf list is for "Data In" PDU's, "Out" buf list is for 721*a6d42e7dSPeter Dunlap * "Data Out" PDU's 722*a6d42e7dSPeter Dunlap */ 723*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 724*a6d42e7dSPeter Dunlap switch (idt->idt_state) { 725*a6d42e7dSPeter Dunlap case TASK_ACTIVE: 726*a6d42e7dSPeter Dunlap idt->idt_rx_from_ini_start++; 727*a6d42e7dSPeter Dunlap idm_task_hold(idt); 728*a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idt, idb); 729*a6d42e7dSPeter Dunlap idb->idb_in_transport = B_TRUE; 730*a6d42e7dSPeter Dunlap rc = (*idt->idt_ic->ic_transport_ops->it_buf_rx_from_ini) 731*a6d42e7dSPeter Dunlap (idt, idb); 732*a6d42e7dSPeter Dunlap return (rc); 733*a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 734*a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 735*a6d42e7dSPeter Dunlap case TASK_ABORTING: 736*a6d42e7dSPeter Dunlap case TASK_ABORTED: 737*a6d42e7dSPeter Dunlap /* 738*a6d42e7dSPeter Dunlap * Bind buffer but don't start a transfer since the task 739*a6d42e7dSPeter Dunlap * is suspended 740*a6d42e7dSPeter Dunlap */ 741*a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idt, idb); 742*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 743*a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 744*a6d42e7dSPeter Dunlap default: 745*a6d42e7dSPeter Dunlap ASSERT(0); 746*a6d42e7dSPeter Dunlap break; 747*a6d42e7dSPeter Dunlap } 748*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 749*a6d42e7dSPeter Dunlap 750*a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 751*a6d42e7dSPeter Dunlap } 752*a6d42e7dSPeter Dunlap 753*a6d42e7dSPeter Dunlap /* 754*a6d42e7dSPeter Dunlap * idm_buf_tx_to_ini_done 755*a6d42e7dSPeter Dunlap * 756*a6d42e7dSPeter Dunlap * The transport calls this after it has completed a transfer requested by 757*a6d42e7dSPeter Dunlap * a call to transport_buf_tx_to_ini 758*a6d42e7dSPeter Dunlap * 759*a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex, idt->idt_mutex is released before returning. 760*a6d42e7dSPeter Dunlap * idt may be freed after the call to idb->idb_buf_cb. 761*a6d42e7dSPeter Dunlap */ 762*a6d42e7dSPeter Dunlap void 763*a6d42e7dSPeter Dunlap idm_buf_tx_to_ini_done(idm_task_t *idt, idm_buf_t *idb, idm_status_t status) 764*a6d42e7dSPeter Dunlap { 765*a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 766*a6d42e7dSPeter Dunlap idb->idb_in_transport = B_FALSE; 767*a6d42e7dSPeter Dunlap idb->idb_tx_thread = B_FALSE; 768*a6d42e7dSPeter Dunlap idt->idt_tx_to_ini_done++; 769*a6d42e7dSPeter Dunlap 770*a6d42e7dSPeter Dunlap /* 771*a6d42e7dSPeter Dunlap * idm_refcnt_rele may cause TASK_SUSPENDING --> TASK_SUSPENDED or 772*a6d42e7dSPeter Dunlap * TASK_ABORTING --> TASK_ABORTED transistion if the refcount goes 773*a6d42e7dSPeter Dunlap * to 0. 774*a6d42e7dSPeter Dunlap */ 775*a6d42e7dSPeter Dunlap idm_task_rele(idt); 776*a6d42e7dSPeter Dunlap idb->idb_status = status; 777*a6d42e7dSPeter Dunlap 778*a6d42e7dSPeter Dunlap switch (idt->idt_state) { 779*a6d42e7dSPeter Dunlap case TASK_ACTIVE: 780*a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idt, idb); 781*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 782*a6d42e7dSPeter Dunlap (*idb->idb_buf_cb)(idb, status); 783*a6d42e7dSPeter Dunlap return; 784*a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 785*a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 786*a6d42e7dSPeter Dunlap case TASK_ABORTING: 787*a6d42e7dSPeter Dunlap case TASK_ABORTED: 788*a6d42e7dSPeter Dunlap /* 789*a6d42e7dSPeter Dunlap * To keep things simple we will ignore the case where the 790*a6d42e7dSPeter Dunlap * transfer was successful and leave all buffers bound to the 791*a6d42e7dSPeter Dunlap * task. This allows us to also ignore the case where we've 792*a6d42e7dSPeter Dunlap * been asked to abort a task but the last transfer of the 793*a6d42e7dSPeter Dunlap * task has completed. IDM has no idea whether this was, in 794*a6d42e7dSPeter Dunlap * fact, the last transfer of the task so it would be difficult 795*a6d42e7dSPeter Dunlap * to handle this case. Everything should get sorted out again 796*a6d42e7dSPeter Dunlap * after task reassignment is complete. 797*a6d42e7dSPeter Dunlap * 798*a6d42e7dSPeter Dunlap * In the case of TASK_ABORTING we could conceivably call the 799*a6d42e7dSPeter Dunlap * buffer callback here but the timing of when the client's 800*a6d42e7dSPeter Dunlap * client_task_aborted callback is invoked vs. when the client's 801*a6d42e7dSPeter Dunlap * buffer callback gets invoked gets sticky. We don't want 802*a6d42e7dSPeter Dunlap * the client to here from us again after the call to 803*a6d42e7dSPeter Dunlap * client_task_aborted() but we don't want to give it a bunch 804*a6d42e7dSPeter Dunlap * of failed buffer transfers until we've called 805*a6d42e7dSPeter Dunlap * client_task_aborted(). Instead we'll just leave all the 806*a6d42e7dSPeter Dunlap * buffers bound and allow the client to cleanup. 807*a6d42e7dSPeter Dunlap */ 808*a6d42e7dSPeter Dunlap break; 809*a6d42e7dSPeter Dunlap default: 810*a6d42e7dSPeter Dunlap ASSERT(0); 811*a6d42e7dSPeter Dunlap } 812*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 813*a6d42e7dSPeter Dunlap } 814*a6d42e7dSPeter Dunlap 815*a6d42e7dSPeter Dunlap /* 816*a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done 817*a6d42e7dSPeter Dunlap * 818*a6d42e7dSPeter Dunlap * The transport calls this after it has completed a transfer requested by 819*a6d42e7dSPeter Dunlap * a call totransport_buf_tx_to_ini 820*a6d42e7dSPeter Dunlap * 821*a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex, idt->idt_mutex is released before returning. 822*a6d42e7dSPeter Dunlap * idt may be freed after the call to idb->idb_buf_cb. 823*a6d42e7dSPeter Dunlap */ 824*a6d42e7dSPeter Dunlap void 825*a6d42e7dSPeter Dunlap idm_buf_rx_from_ini_done(idm_task_t *idt, idm_buf_t *idb, idm_status_t status) 826*a6d42e7dSPeter Dunlap { 827*a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 828*a6d42e7dSPeter Dunlap idb->idb_in_transport = B_FALSE; 829*a6d42e7dSPeter Dunlap idt->idt_rx_from_ini_done++; 830*a6d42e7dSPeter Dunlap 831*a6d42e7dSPeter Dunlap /* 832*a6d42e7dSPeter Dunlap * idm_refcnt_rele may cause TASK_SUSPENDING --> TASK_SUSPENDED or 833*a6d42e7dSPeter Dunlap * TASK_ABORTING --> TASK_ABORTED transistion if the refcount goes 834*a6d42e7dSPeter Dunlap * to 0. 835*a6d42e7dSPeter Dunlap */ 836*a6d42e7dSPeter Dunlap idm_task_rele(idt); 837*a6d42e7dSPeter Dunlap idb->idb_status = status; 838*a6d42e7dSPeter Dunlap 839*a6d42e7dSPeter Dunlap switch (idt->idt_state) { 840*a6d42e7dSPeter Dunlap case TASK_ACTIVE: 841*a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idt, idb); 842*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 843*a6d42e7dSPeter Dunlap (*idb->idb_buf_cb)(idb, status); 844*a6d42e7dSPeter Dunlap return; 845*a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 846*a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 847*a6d42e7dSPeter Dunlap case TASK_ABORTING: 848*a6d42e7dSPeter Dunlap case TASK_ABORTED: 849*a6d42e7dSPeter Dunlap /* 850*a6d42e7dSPeter Dunlap * To keep things simple we will ignore the case where the 851*a6d42e7dSPeter Dunlap * transfer was successful and leave all buffers bound to the 852*a6d42e7dSPeter Dunlap * task. This allows us to also ignore the case where we've 853*a6d42e7dSPeter Dunlap * been asked to abort a task but the last transfer of the 854*a6d42e7dSPeter Dunlap * task has completed. IDM has no idea whether this was, in 855*a6d42e7dSPeter Dunlap * fact, the last transfer of the task so it would be difficult 856*a6d42e7dSPeter Dunlap * to handle this case. Everything should get sorted out again 857*a6d42e7dSPeter Dunlap * after task reassignment is complete. 858*a6d42e7dSPeter Dunlap * 859*a6d42e7dSPeter Dunlap * In the case of TASK_ABORTING we could conceivably call the 860*a6d42e7dSPeter Dunlap * buffer callback here but the timing of when the client's 861*a6d42e7dSPeter Dunlap * client_task_aborted callback is invoked vs. when the client's 862*a6d42e7dSPeter Dunlap * buffer callback gets invoked gets sticky. We don't want 863*a6d42e7dSPeter Dunlap * the client to here from us again after the call to 864*a6d42e7dSPeter Dunlap * client_task_aborted() but we don't want to give it a bunch 865*a6d42e7dSPeter Dunlap * of failed buffer transfers until we've called 866*a6d42e7dSPeter Dunlap * client_task_aborted(). Instead we'll just leave all the 867*a6d42e7dSPeter Dunlap * buffers bound and allow the client to cleanup. 868*a6d42e7dSPeter Dunlap */ 869*a6d42e7dSPeter Dunlap break; 870*a6d42e7dSPeter Dunlap default: 871*a6d42e7dSPeter Dunlap ASSERT(0); 872*a6d42e7dSPeter Dunlap } 873*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 874*a6d42e7dSPeter Dunlap } 875*a6d42e7dSPeter Dunlap 876*a6d42e7dSPeter Dunlap /* 877*a6d42e7dSPeter Dunlap * idm_buf_alloc 878*a6d42e7dSPeter Dunlap * 879*a6d42e7dSPeter Dunlap * Allocates a buffer handle and registers it for use with the transport 880*a6d42e7dSPeter Dunlap * layer. If a buffer is not passed on bufptr, the buffer will be allocated 881*a6d42e7dSPeter Dunlap * as well as the handle. 882*a6d42e7dSPeter Dunlap * 883*a6d42e7dSPeter Dunlap * ic - connection on which the buffer will be transferred 884*a6d42e7dSPeter Dunlap * bufptr - allocate memory for buffer if NULL, else assign to buffer 885*a6d42e7dSPeter Dunlap * buflen - length of buffer 886*a6d42e7dSPeter Dunlap * 887*a6d42e7dSPeter Dunlap * Returns idm_buf_t handle if successful, otherwise NULL 888*a6d42e7dSPeter Dunlap */ 889*a6d42e7dSPeter Dunlap idm_buf_t * 890*a6d42e7dSPeter Dunlap idm_buf_alloc(idm_conn_t *ic, void *bufptr, uint64_t buflen) 891*a6d42e7dSPeter Dunlap { 892*a6d42e7dSPeter Dunlap idm_buf_t *buf = NULL; 893*a6d42e7dSPeter Dunlap int rc; 894*a6d42e7dSPeter Dunlap 895*a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 896*a6d42e7dSPeter Dunlap ASSERT(idm.idm_buf_cache != NULL); 897*a6d42e7dSPeter Dunlap ASSERT(buflen > 0); 898*a6d42e7dSPeter Dunlap 899*a6d42e7dSPeter Dunlap /* Don't allocate new buffers if we are not in FFP */ 900*a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 901*a6d42e7dSPeter Dunlap if (!ic->ic_ffp) { 902*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 903*a6d42e7dSPeter Dunlap return (NULL); 904*a6d42e7dSPeter Dunlap } 905*a6d42e7dSPeter Dunlap 906*a6d42e7dSPeter Dunlap 907*a6d42e7dSPeter Dunlap idm_conn_hold(ic); 908*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 909*a6d42e7dSPeter Dunlap 910*a6d42e7dSPeter Dunlap buf = kmem_cache_alloc(idm.idm_buf_cache, KM_NOSLEEP); 911*a6d42e7dSPeter Dunlap if (buf == NULL) { 912*a6d42e7dSPeter Dunlap idm_conn_rele(ic); 913*a6d42e7dSPeter Dunlap return (NULL); 914*a6d42e7dSPeter Dunlap } 915*a6d42e7dSPeter Dunlap 916*a6d42e7dSPeter Dunlap buf->idb_ic = ic; 917*a6d42e7dSPeter Dunlap buf->idb_buflen = buflen; 918*a6d42e7dSPeter Dunlap buf->idb_exp_offset = 0; 919*a6d42e7dSPeter Dunlap buf->idb_bufoffset = 0; 920*a6d42e7dSPeter Dunlap buf->idb_xfer_len = 0; 921*a6d42e7dSPeter Dunlap buf->idb_magic = IDM_BUF_MAGIC; 922*a6d42e7dSPeter Dunlap 923*a6d42e7dSPeter Dunlap /* 924*a6d42e7dSPeter Dunlap * If bufptr is NULL, we have an implicit request to allocate 925*a6d42e7dSPeter Dunlap * memory for this IDM buffer handle and register it for use 926*a6d42e7dSPeter Dunlap * with the transport. To simplify this, and to give more freedom 927*a6d42e7dSPeter Dunlap * to the transport layer for it's own buffer management, both of 928*a6d42e7dSPeter Dunlap * these actions will take place in the transport layer. 929*a6d42e7dSPeter Dunlap * If bufptr is set, then the caller has allocated memory (or more 930*a6d42e7dSPeter Dunlap * likely it's been passed from an upper layer), and we need only 931*a6d42e7dSPeter Dunlap * register the buffer for use with the transport layer. 932*a6d42e7dSPeter Dunlap */ 933*a6d42e7dSPeter Dunlap if (bufptr == NULL) { 934*a6d42e7dSPeter Dunlap /* 935*a6d42e7dSPeter Dunlap * Allocate a buffer from the transport layer (which 936*a6d42e7dSPeter Dunlap * will also register the buffer for use). 937*a6d42e7dSPeter Dunlap */ 938*a6d42e7dSPeter Dunlap rc = ic->ic_transport_ops->it_buf_alloc(buf, buflen); 939*a6d42e7dSPeter Dunlap if (rc != 0) { 940*a6d42e7dSPeter Dunlap idm_conn_rele(ic); 941*a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_buf_cache, buf); 942*a6d42e7dSPeter Dunlap return (NULL); 943*a6d42e7dSPeter Dunlap } 944*a6d42e7dSPeter Dunlap /* Set the bufalloc'd flag */ 945*a6d42e7dSPeter Dunlap buf->idb_bufalloc = B_TRUE; 946*a6d42e7dSPeter Dunlap } else { 947*a6d42e7dSPeter Dunlap /* 948*a6d42e7dSPeter Dunlap * Set the passed bufptr into the buf handle, and 949*a6d42e7dSPeter Dunlap * register the handle with the transport layer. 950*a6d42e7dSPeter Dunlap */ 951*a6d42e7dSPeter Dunlap buf->idb_buf = bufptr; 952*a6d42e7dSPeter Dunlap 953*a6d42e7dSPeter Dunlap rc = ic->ic_transport_ops->it_buf_setup(buf); 954*a6d42e7dSPeter Dunlap if (rc != 0) { 955*a6d42e7dSPeter Dunlap idm_conn_rele(ic); 956*a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_buf_cache, buf); 957*a6d42e7dSPeter Dunlap return (NULL); 958*a6d42e7dSPeter Dunlap } 959*a6d42e7dSPeter Dunlap /* Ensure bufalloc'd flag is unset */ 960*a6d42e7dSPeter Dunlap buf->idb_bufalloc = B_FALSE; 961*a6d42e7dSPeter Dunlap } 962*a6d42e7dSPeter Dunlap 963*a6d42e7dSPeter Dunlap return (buf); 964*a6d42e7dSPeter Dunlap 965*a6d42e7dSPeter Dunlap } 966*a6d42e7dSPeter Dunlap 967*a6d42e7dSPeter Dunlap /* 968*a6d42e7dSPeter Dunlap * idm_buf_free 969*a6d42e7dSPeter Dunlap * 970*a6d42e7dSPeter Dunlap * Release a buffer handle along with the associated buffer that was allocated 971*a6d42e7dSPeter Dunlap * or assigned with idm_buf_alloc 972*a6d42e7dSPeter Dunlap */ 973*a6d42e7dSPeter Dunlap void 974*a6d42e7dSPeter Dunlap idm_buf_free(idm_buf_t *buf) 975*a6d42e7dSPeter Dunlap { 976*a6d42e7dSPeter Dunlap idm_conn_t *ic = buf->idb_ic; 977*a6d42e7dSPeter Dunlap 978*a6d42e7dSPeter Dunlap 979*a6d42e7dSPeter Dunlap buf->idb_task_binding = NULL; 980*a6d42e7dSPeter Dunlap 981*a6d42e7dSPeter Dunlap if (buf->idb_bufalloc) { 982*a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_buf_free(buf); 983*a6d42e7dSPeter Dunlap } else { 984*a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_buf_teardown(buf); 985*a6d42e7dSPeter Dunlap } 986*a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_buf_cache, buf); 987*a6d42e7dSPeter Dunlap idm_conn_rele(ic); 988*a6d42e7dSPeter Dunlap } 989*a6d42e7dSPeter Dunlap 990*a6d42e7dSPeter Dunlap /* 991*a6d42e7dSPeter Dunlap * idm_buf_bind_in 992*a6d42e7dSPeter Dunlap * 993*a6d42e7dSPeter Dunlap * This function associates a buffer with a task. This is only for use by the 994*a6d42e7dSPeter Dunlap * iSCSI initiator that will have only one buffer per transfer direction 995*a6d42e7dSPeter Dunlap * 996*a6d42e7dSPeter Dunlap */ 997*a6d42e7dSPeter Dunlap void 998*a6d42e7dSPeter Dunlap idm_buf_bind_in(idm_task_t *idt, idm_buf_t *buf) 999*a6d42e7dSPeter Dunlap { 1000*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1001*a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idt, buf); 1002*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1003*a6d42e7dSPeter Dunlap } 1004*a6d42e7dSPeter Dunlap 1005*a6d42e7dSPeter Dunlap static void 1006*a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf) 1007*a6d42e7dSPeter Dunlap { 1008*a6d42e7dSPeter Dunlap buf->idb_task_binding = idt; 1009*a6d42e7dSPeter Dunlap buf->idb_ic = idt->idt_ic; 1010*a6d42e7dSPeter Dunlap idm_listbuf_insert(&idt->idt_inbufv, buf); 1011*a6d42e7dSPeter Dunlap } 1012*a6d42e7dSPeter Dunlap 1013*a6d42e7dSPeter Dunlap void 1014*a6d42e7dSPeter Dunlap idm_buf_bind_out(idm_task_t *idt, idm_buf_t *buf) 1015*a6d42e7dSPeter Dunlap { 1016*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1017*a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idt, buf); 1018*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1019*a6d42e7dSPeter Dunlap } 1020*a6d42e7dSPeter Dunlap 1021*a6d42e7dSPeter Dunlap static void 1022*a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf) 1023*a6d42e7dSPeter Dunlap { 1024*a6d42e7dSPeter Dunlap buf->idb_task_binding = idt; 1025*a6d42e7dSPeter Dunlap buf->idb_ic = idt->idt_ic; 1026*a6d42e7dSPeter Dunlap idm_listbuf_insert(&idt->idt_outbufv, buf); 1027*a6d42e7dSPeter Dunlap } 1028*a6d42e7dSPeter Dunlap 1029*a6d42e7dSPeter Dunlap void 1030*a6d42e7dSPeter Dunlap idm_buf_unbind_in(idm_task_t *idt, idm_buf_t *buf) 1031*a6d42e7dSPeter Dunlap { 1032*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1033*a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idt, buf); 1034*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1035*a6d42e7dSPeter Dunlap } 1036*a6d42e7dSPeter Dunlap 1037*a6d42e7dSPeter Dunlap static void 1038*a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf) 1039*a6d42e7dSPeter Dunlap { 1040*a6d42e7dSPeter Dunlap list_remove(&idt->idt_inbufv, buf); 1041*a6d42e7dSPeter Dunlap } 1042*a6d42e7dSPeter Dunlap 1043*a6d42e7dSPeter Dunlap void 1044*a6d42e7dSPeter Dunlap idm_buf_unbind_out(idm_task_t *idt, idm_buf_t *buf) 1045*a6d42e7dSPeter Dunlap { 1046*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1047*a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idt, buf); 1048*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1049*a6d42e7dSPeter Dunlap } 1050*a6d42e7dSPeter Dunlap 1051*a6d42e7dSPeter Dunlap static void 1052*a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf) 1053*a6d42e7dSPeter Dunlap { 1054*a6d42e7dSPeter Dunlap list_remove(&idt->idt_outbufv, buf); 1055*a6d42e7dSPeter Dunlap } 1056*a6d42e7dSPeter Dunlap 1057*a6d42e7dSPeter Dunlap /* 1058*a6d42e7dSPeter Dunlap * idm_buf_find() will lookup the idm_buf_t based on the relative offset in the 1059*a6d42e7dSPeter Dunlap * iSCSI PDU 1060*a6d42e7dSPeter Dunlap */ 1061*a6d42e7dSPeter Dunlap idm_buf_t * 1062*a6d42e7dSPeter Dunlap idm_buf_find(void *lbuf, size_t data_offset) 1063*a6d42e7dSPeter Dunlap { 1064*a6d42e7dSPeter Dunlap idm_buf_t *idb; 1065*a6d42e7dSPeter Dunlap list_t *lst = (list_t *)lbuf; 1066*a6d42e7dSPeter Dunlap 1067*a6d42e7dSPeter Dunlap /* iterate through the list to find the buffer */ 1068*a6d42e7dSPeter Dunlap for (idb = list_head(lst); idb != NULL; idb = list_next(lst, idb)) { 1069*a6d42e7dSPeter Dunlap 1070*a6d42e7dSPeter Dunlap ASSERT((idb->idb_ic->ic_conn_type == CONN_TYPE_TGT) || 1071*a6d42e7dSPeter Dunlap (idb->idb_bufoffset == 0)); 1072*a6d42e7dSPeter Dunlap 1073*a6d42e7dSPeter Dunlap if ((data_offset >= idb->idb_bufoffset) && 1074*a6d42e7dSPeter Dunlap (data_offset < (idb->idb_bufoffset + idb->idb_buflen))) { 1075*a6d42e7dSPeter Dunlap 1076*a6d42e7dSPeter Dunlap return (idb); 1077*a6d42e7dSPeter Dunlap } 1078*a6d42e7dSPeter Dunlap } 1079*a6d42e7dSPeter Dunlap 1080*a6d42e7dSPeter Dunlap return (NULL); 1081*a6d42e7dSPeter Dunlap } 1082*a6d42e7dSPeter Dunlap 1083*a6d42e7dSPeter Dunlap /* 1084*a6d42e7dSPeter Dunlap * idm_task_alloc 1085*a6d42e7dSPeter Dunlap * 1086*a6d42e7dSPeter Dunlap * This function will allocate a idm_task_t structure. A task tag is also 1087*a6d42e7dSPeter Dunlap * generated and saved in idt_tt. The task is not active. 1088*a6d42e7dSPeter Dunlap */ 1089*a6d42e7dSPeter Dunlap idm_task_t * 1090*a6d42e7dSPeter Dunlap idm_task_alloc(idm_conn_t *ic) 1091*a6d42e7dSPeter Dunlap { 1092*a6d42e7dSPeter Dunlap idm_task_t *idt; 1093*a6d42e7dSPeter Dunlap 1094*a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1095*a6d42e7dSPeter Dunlap 1096*a6d42e7dSPeter Dunlap /* Don't allocate new tasks if we are not in FFP */ 1097*a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 1098*a6d42e7dSPeter Dunlap if (!ic->ic_ffp) { 1099*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 1100*a6d42e7dSPeter Dunlap return (NULL); 1101*a6d42e7dSPeter Dunlap } 1102*a6d42e7dSPeter Dunlap idt = kmem_cache_alloc(idm.idm_task_cache, KM_NOSLEEP); 1103*a6d42e7dSPeter Dunlap if (idt == NULL) { 1104*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 1105*a6d42e7dSPeter Dunlap return (NULL); 1106*a6d42e7dSPeter Dunlap } 1107*a6d42e7dSPeter Dunlap 1108*a6d42e7dSPeter Dunlap ASSERT(list_is_empty(&idt->idt_inbufv)); 1109*a6d42e7dSPeter Dunlap ASSERT(list_is_empty(&idt->idt_outbufv)); 1110*a6d42e7dSPeter Dunlap 1111*a6d42e7dSPeter Dunlap idm_conn_hold(ic); 1112*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 1113*a6d42e7dSPeter Dunlap 1114*a6d42e7dSPeter Dunlap idt->idt_state = TASK_IDLE; 1115*a6d42e7dSPeter Dunlap idt->idt_ic = ic; 1116*a6d42e7dSPeter Dunlap idt->idt_private = NULL; 1117*a6d42e7dSPeter Dunlap idt->idt_exp_datasn = 0; 1118*a6d42e7dSPeter Dunlap idt->idt_exp_rttsn = 0; 1119*a6d42e7dSPeter Dunlap 1120*a6d42e7dSPeter Dunlap return (idt); 1121*a6d42e7dSPeter Dunlap } 1122*a6d42e7dSPeter Dunlap 1123*a6d42e7dSPeter Dunlap /* 1124*a6d42e7dSPeter Dunlap * idm_task_start 1125*a6d42e7dSPeter Dunlap * 1126*a6d42e7dSPeter Dunlap * Add the task to an AVL tree to notify IDM about a new task. The caller 1127*a6d42e7dSPeter Dunlap * sets up the idm_task_t structure with a prior call to idm_task_alloc(). 1128*a6d42e7dSPeter Dunlap * The task service does not function as a task/work engine, it is the 1129*a6d42e7dSPeter Dunlap * responsibility of the initiator to start the data transfer and free the 1130*a6d42e7dSPeter Dunlap * resources. 1131*a6d42e7dSPeter Dunlap */ 1132*a6d42e7dSPeter Dunlap void 1133*a6d42e7dSPeter Dunlap idm_task_start(idm_task_t *idt, uintptr_t handle) 1134*a6d42e7dSPeter Dunlap { 1135*a6d42e7dSPeter Dunlap ASSERT(idt != NULL); 1136*a6d42e7dSPeter Dunlap 1137*a6d42e7dSPeter Dunlap /* mark the task as ACTIVE */ 1138*a6d42e7dSPeter Dunlap idt->idt_state = TASK_ACTIVE; 1139*a6d42e7dSPeter Dunlap idt->idt_client_handle = handle; 1140*a6d42e7dSPeter Dunlap idt->idt_tx_to_ini_start = idt->idt_tx_to_ini_done = 1141*a6d42e7dSPeter Dunlap idt->idt_rx_from_ini_start = idt->idt_rx_from_ini_done = 0; 1142*a6d42e7dSPeter Dunlap } 1143*a6d42e7dSPeter Dunlap 1144*a6d42e7dSPeter Dunlap /* 1145*a6d42e7dSPeter Dunlap * idm_task_done 1146*a6d42e7dSPeter Dunlap * 1147*a6d42e7dSPeter Dunlap * This function will remove the task from the AVL tree indicating that the 1148*a6d42e7dSPeter Dunlap * task is no longer active. 1149*a6d42e7dSPeter Dunlap */ 1150*a6d42e7dSPeter Dunlap void 1151*a6d42e7dSPeter Dunlap idm_task_done(idm_task_t *idt) 1152*a6d42e7dSPeter Dunlap { 1153*a6d42e7dSPeter Dunlap ASSERT(idt != NULL); 1154*a6d42e7dSPeter Dunlap ASSERT(idt->idt_refcnt.ir_refcnt == 0); 1155*a6d42e7dSPeter Dunlap 1156*a6d42e7dSPeter Dunlap idt->idt_state = TASK_IDLE; 1157*a6d42e7dSPeter Dunlap idm_refcnt_reset(&idt->idt_refcnt); 1158*a6d42e7dSPeter Dunlap } 1159*a6d42e7dSPeter Dunlap 1160*a6d42e7dSPeter Dunlap /* 1161*a6d42e7dSPeter Dunlap * idm_task_free 1162*a6d42e7dSPeter Dunlap * 1163*a6d42e7dSPeter Dunlap * This function will free the Task Tag and the memory allocated for the task 1164*a6d42e7dSPeter Dunlap * idm_task_done should be called prior to this call 1165*a6d42e7dSPeter Dunlap */ 1166*a6d42e7dSPeter Dunlap void 1167*a6d42e7dSPeter Dunlap idm_task_free(idm_task_t *idt) 1168*a6d42e7dSPeter Dunlap { 1169*a6d42e7dSPeter Dunlap idm_conn_t *ic = idt->idt_ic; 1170*a6d42e7dSPeter Dunlap 1171*a6d42e7dSPeter Dunlap ASSERT(idt != NULL); 1172*a6d42e7dSPeter Dunlap ASSERT(idt->idt_state == TASK_IDLE); 1173*a6d42e7dSPeter Dunlap 1174*a6d42e7dSPeter Dunlap /* 1175*a6d42e7dSPeter Dunlap * It's possible for items to still be in the idt_inbufv list if 1176*a6d42e7dSPeter Dunlap * they were added after idm_task_cleanup was called. We rely on 1177*a6d42e7dSPeter Dunlap * STMF to free all buffers associated with the task however STMF 1178*a6d42e7dSPeter Dunlap * doesn't know that we have this reference to the buffers. 1179*a6d42e7dSPeter Dunlap * Use list_create so that we don't end up with stale references 1180*a6d42e7dSPeter Dunlap * to these buffers. 1181*a6d42e7dSPeter Dunlap */ 1182*a6d42e7dSPeter Dunlap list_create(&idt->idt_inbufv, sizeof (idm_buf_t), 1183*a6d42e7dSPeter Dunlap offsetof(idm_buf_t, idb_buflink)); 1184*a6d42e7dSPeter Dunlap list_create(&idt->idt_outbufv, sizeof (idm_buf_t), 1185*a6d42e7dSPeter Dunlap offsetof(idm_buf_t, idb_buflink)); 1186*a6d42e7dSPeter Dunlap 1187*a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_task_cache, idt); 1188*a6d42e7dSPeter Dunlap 1189*a6d42e7dSPeter Dunlap idm_conn_rele(ic); 1190*a6d42e7dSPeter Dunlap } 1191*a6d42e7dSPeter Dunlap 1192*a6d42e7dSPeter Dunlap /* 1193*a6d42e7dSPeter Dunlap * idm_task_find 1194*a6d42e7dSPeter Dunlap * 1195*a6d42e7dSPeter Dunlap * This function looks up a task by task tag 1196*a6d42e7dSPeter Dunlap */ 1197*a6d42e7dSPeter Dunlap /*ARGSUSED*/ 1198*a6d42e7dSPeter Dunlap idm_task_t * 1199*a6d42e7dSPeter Dunlap idm_task_find(idm_conn_t *ic, uint32_t itt, uint32_t ttt) 1200*a6d42e7dSPeter Dunlap { 1201*a6d42e7dSPeter Dunlap uint32_t tt, client_handle; 1202*a6d42e7dSPeter Dunlap idm_task_t *idt; 1203*a6d42e7dSPeter Dunlap 1204*a6d42e7dSPeter Dunlap /* 1205*a6d42e7dSPeter Dunlap * Must match both itt and ttt. The table is indexed by itt 1206*a6d42e7dSPeter Dunlap * for initiator connections and ttt for target connections. 1207*a6d42e7dSPeter Dunlap */ 1208*a6d42e7dSPeter Dunlap if (IDM_CONN_ISTGT(ic)) { 1209*a6d42e7dSPeter Dunlap tt = ttt; 1210*a6d42e7dSPeter Dunlap client_handle = itt; 1211*a6d42e7dSPeter Dunlap } else { 1212*a6d42e7dSPeter Dunlap tt = itt; 1213*a6d42e7dSPeter Dunlap client_handle = ttt; 1214*a6d42e7dSPeter Dunlap } 1215*a6d42e7dSPeter Dunlap 1216*a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER); 1217*a6d42e7dSPeter Dunlap if (tt >= idm.idm_taskid_max) { 1218*a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1219*a6d42e7dSPeter Dunlap return (NULL); 1220*a6d42e7dSPeter Dunlap } 1221*a6d42e7dSPeter Dunlap 1222*a6d42e7dSPeter Dunlap idt = idm.idm_taskid_table[tt]; 1223*a6d42e7dSPeter Dunlap 1224*a6d42e7dSPeter Dunlap if (idt != NULL) { 1225*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1226*a6d42e7dSPeter Dunlap if ((idt->idt_state != TASK_ACTIVE) || 1227*a6d42e7dSPeter Dunlap (IDM_CONN_ISTGT(ic) && 1228*a6d42e7dSPeter Dunlap (idt->idt_client_handle != client_handle))) { 1229*a6d42e7dSPeter Dunlap /* 1230*a6d42e7dSPeter Dunlap * Task is aborting, we don't want any more references. 1231*a6d42e7dSPeter Dunlap */ 1232*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1233*a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1234*a6d42e7dSPeter Dunlap return (NULL); 1235*a6d42e7dSPeter Dunlap } 1236*a6d42e7dSPeter Dunlap idm_task_hold(idt); 1237*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1238*a6d42e7dSPeter Dunlap } 1239*a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1240*a6d42e7dSPeter Dunlap 1241*a6d42e7dSPeter Dunlap return (idt); 1242*a6d42e7dSPeter Dunlap } 1243*a6d42e7dSPeter Dunlap 1244*a6d42e7dSPeter Dunlap /* 1245*a6d42e7dSPeter Dunlap * idm_task_find_by_handle 1246*a6d42e7dSPeter Dunlap * 1247*a6d42e7dSPeter Dunlap * This function looks up a task by the client-private idt_client_handle. 1248*a6d42e7dSPeter Dunlap * 1249*a6d42e7dSPeter Dunlap * This function should NEVER be called in the performance path. It is 1250*a6d42e7dSPeter Dunlap * intended strictly for error recovery/task management. 1251*a6d42e7dSPeter Dunlap */ 1252*a6d42e7dSPeter Dunlap /*ARGSUSED*/ 1253*a6d42e7dSPeter Dunlap void * 1254*a6d42e7dSPeter Dunlap idm_task_find_by_handle(idm_conn_t *ic, uintptr_t handle) 1255*a6d42e7dSPeter Dunlap { 1256*a6d42e7dSPeter Dunlap idm_task_t *idt = NULL; 1257*a6d42e7dSPeter Dunlap int idx = 0; 1258*a6d42e7dSPeter Dunlap 1259*a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER); 1260*a6d42e7dSPeter Dunlap 1261*a6d42e7dSPeter Dunlap for (idx = 0; idx < idm.idm_taskid_max; idx++) { 1262*a6d42e7dSPeter Dunlap idt = idm.idm_taskid_table[idx]; 1263*a6d42e7dSPeter Dunlap 1264*a6d42e7dSPeter Dunlap if (idt == NULL) 1265*a6d42e7dSPeter Dunlap continue; 1266*a6d42e7dSPeter Dunlap 1267*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1268*a6d42e7dSPeter Dunlap 1269*a6d42e7dSPeter Dunlap if (idt->idt_state != TASK_ACTIVE) { 1270*a6d42e7dSPeter Dunlap /* 1271*a6d42e7dSPeter Dunlap * Task is either in suspend, abort, or already 1272*a6d42e7dSPeter Dunlap * complete. 1273*a6d42e7dSPeter Dunlap */ 1274*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1275*a6d42e7dSPeter Dunlap continue; 1276*a6d42e7dSPeter Dunlap } 1277*a6d42e7dSPeter Dunlap 1278*a6d42e7dSPeter Dunlap if (idt->idt_client_handle == handle) { 1279*a6d42e7dSPeter Dunlap idm_task_hold(idt); 1280*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1281*a6d42e7dSPeter Dunlap break; 1282*a6d42e7dSPeter Dunlap } 1283*a6d42e7dSPeter Dunlap 1284*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1285*a6d42e7dSPeter Dunlap } 1286*a6d42e7dSPeter Dunlap 1287*a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1288*a6d42e7dSPeter Dunlap 1289*a6d42e7dSPeter Dunlap if ((idt == NULL) || (idx == idm.idm_taskid_max)) 1290*a6d42e7dSPeter Dunlap return (NULL); 1291*a6d42e7dSPeter Dunlap 1292*a6d42e7dSPeter Dunlap return (idt->idt_private); 1293*a6d42e7dSPeter Dunlap } 1294*a6d42e7dSPeter Dunlap 1295*a6d42e7dSPeter Dunlap void 1296*a6d42e7dSPeter Dunlap idm_task_hold(idm_task_t *idt) 1297*a6d42e7dSPeter Dunlap { 1298*a6d42e7dSPeter Dunlap idm_refcnt_hold(&idt->idt_refcnt); 1299*a6d42e7dSPeter Dunlap } 1300*a6d42e7dSPeter Dunlap 1301*a6d42e7dSPeter Dunlap void 1302*a6d42e7dSPeter Dunlap idm_task_rele(idm_task_t *idt) 1303*a6d42e7dSPeter Dunlap { 1304*a6d42e7dSPeter Dunlap idm_refcnt_rele(&idt->idt_refcnt); 1305*a6d42e7dSPeter Dunlap } 1306*a6d42e7dSPeter Dunlap 1307*a6d42e7dSPeter Dunlap void 1308*a6d42e7dSPeter Dunlap idm_task_abort(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type) 1309*a6d42e7dSPeter Dunlap { 1310*a6d42e7dSPeter Dunlap idm_task_t *task; 1311*a6d42e7dSPeter Dunlap int idx; 1312*a6d42e7dSPeter Dunlap 1313*a6d42e7dSPeter Dunlap /* 1314*a6d42e7dSPeter Dunlap * Passing NULL as the task indicates that all tasks 1315*a6d42e7dSPeter Dunlap * for this connection should be aborted. 1316*a6d42e7dSPeter Dunlap */ 1317*a6d42e7dSPeter Dunlap if (idt == NULL) { 1318*a6d42e7dSPeter Dunlap /* 1319*a6d42e7dSPeter Dunlap * Only the connection state machine should ask for 1320*a6d42e7dSPeter Dunlap * all tasks to abort and this should never happen in FFP. 1321*a6d42e7dSPeter Dunlap */ 1322*a6d42e7dSPeter Dunlap ASSERT(!ic->ic_ffp); 1323*a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER); 1324*a6d42e7dSPeter Dunlap for (idx = 0; idx < idm.idm_taskid_max; idx++) { 1325*a6d42e7dSPeter Dunlap task = idm.idm_taskid_table[idx]; 1326*a6d42e7dSPeter Dunlap if (task && (task->idt_state != TASK_IDLE) && 1327*a6d42e7dSPeter Dunlap (task->idt_ic == ic)) { 1328*a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1329*a6d42e7dSPeter Dunlap idm_task_abort_one(ic, task, abort_type); 1330*a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER); 1331*a6d42e7dSPeter Dunlap } 1332*a6d42e7dSPeter Dunlap } 1333*a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock); 1334*a6d42e7dSPeter Dunlap } else { 1335*a6d42e7dSPeter Dunlap idm_task_abort_one(ic, idt, abort_type); 1336*a6d42e7dSPeter Dunlap } 1337*a6d42e7dSPeter Dunlap } 1338*a6d42e7dSPeter Dunlap 1339*a6d42e7dSPeter Dunlap static void 1340*a6d42e7dSPeter Dunlap idm_task_abort_unref_cb(void *ref) 1341*a6d42e7dSPeter Dunlap { 1342*a6d42e7dSPeter Dunlap idm_task_t *idt = ref; 1343*a6d42e7dSPeter Dunlap 1344*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1345*a6d42e7dSPeter Dunlap switch (idt->idt_state) { 1346*a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 1347*a6d42e7dSPeter Dunlap idt->idt_state = TASK_SUSPENDED; 1348*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1349*a6d42e7dSPeter Dunlap idm_task_aborted(idt, IDM_STATUS_SUSPENDED); 1350*a6d42e7dSPeter Dunlap return; 1351*a6d42e7dSPeter Dunlap case TASK_ABORTING: 1352*a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTED; 1353*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1354*a6d42e7dSPeter Dunlap idm_task_aborted(idt, IDM_STATUS_ABORTED); 1355*a6d42e7dSPeter Dunlap return; 1356*a6d42e7dSPeter Dunlap default: 1357*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1358*a6d42e7dSPeter Dunlap ASSERT(0); 1359*a6d42e7dSPeter Dunlap break; 1360*a6d42e7dSPeter Dunlap } 1361*a6d42e7dSPeter Dunlap } 1362*a6d42e7dSPeter Dunlap 1363*a6d42e7dSPeter Dunlap static void 1364*a6d42e7dSPeter Dunlap idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type) 1365*a6d42e7dSPeter Dunlap { 1366*a6d42e7dSPeter Dunlap /* Caller must hold connection mutex */ 1367*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1368*a6d42e7dSPeter Dunlap switch (idt->idt_state) { 1369*a6d42e7dSPeter Dunlap case TASK_ACTIVE: 1370*a6d42e7dSPeter Dunlap switch (abort_type) { 1371*a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND: 1372*a6d42e7dSPeter Dunlap /* Call transport to release any resources */ 1373*a6d42e7dSPeter Dunlap idt->idt_state = TASK_SUSPENDING; 1374*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1375*a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_free_task_rsrc(idt); 1376*a6d42e7dSPeter Dunlap 1377*a6d42e7dSPeter Dunlap /* 1378*a6d42e7dSPeter Dunlap * Wait for outstanding references. When all 1379*a6d42e7dSPeter Dunlap * references are released the callback will call 1380*a6d42e7dSPeter Dunlap * idm_task_aborted(). 1381*a6d42e7dSPeter Dunlap */ 1382*a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(&idt->idt_refcnt, 1383*a6d42e7dSPeter Dunlap &idm_task_abort_unref_cb); 1384*a6d42e7dSPeter Dunlap return; 1385*a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT: 1386*a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT: 1387*a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTING; 1388*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1389*a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_free_task_rsrc(idt); 1390*a6d42e7dSPeter Dunlap 1391*a6d42e7dSPeter Dunlap /* 1392*a6d42e7dSPeter Dunlap * Wait for outstanding references. When all 1393*a6d42e7dSPeter Dunlap * references are released the callback will call 1394*a6d42e7dSPeter Dunlap * idm_task_aborted(). 1395*a6d42e7dSPeter Dunlap */ 1396*a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(&idt->idt_refcnt, 1397*a6d42e7dSPeter Dunlap &idm_task_abort_unref_cb); 1398*a6d42e7dSPeter Dunlap return; 1399*a6d42e7dSPeter Dunlap default: 1400*a6d42e7dSPeter Dunlap ASSERT(0); 1401*a6d42e7dSPeter Dunlap } 1402*a6d42e7dSPeter Dunlap break; 1403*a6d42e7dSPeter Dunlap case TASK_SUSPENDING: 1404*a6d42e7dSPeter Dunlap /* Already called transport_free_task_rsrc(); */ 1405*a6d42e7dSPeter Dunlap switch (abort_type) { 1406*a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND: 1407*a6d42e7dSPeter Dunlap /* Already doing it */ 1408*a6d42e7dSPeter Dunlap break; 1409*a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT: 1410*a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT: 1411*a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTING; 1412*a6d42e7dSPeter Dunlap break; 1413*a6d42e7dSPeter Dunlap default: 1414*a6d42e7dSPeter Dunlap ASSERT(0); 1415*a6d42e7dSPeter Dunlap } 1416*a6d42e7dSPeter Dunlap break; 1417*a6d42e7dSPeter Dunlap case TASK_SUSPENDED: 1418*a6d42e7dSPeter Dunlap /* Already called transport_free_task_rsrc(); */ 1419*a6d42e7dSPeter Dunlap switch (abort_type) { 1420*a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND: 1421*a6d42e7dSPeter Dunlap /* Already doing it */ 1422*a6d42e7dSPeter Dunlap break; 1423*a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT: 1424*a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT: 1425*a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTING; 1426*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1427*a6d42e7dSPeter Dunlap 1428*a6d42e7dSPeter Dunlap /* 1429*a6d42e7dSPeter Dunlap * We could probably call idm_task_aborted directly 1430*a6d42e7dSPeter Dunlap * here but we may be holding the conn lock. It's 1431*a6d42e7dSPeter Dunlap * easier to just switch contexts. Even though 1432*a6d42e7dSPeter Dunlap * we shouldn't really have any references we'll 1433*a6d42e7dSPeter Dunlap * set the state to TASK_ABORTING instead of 1434*a6d42e7dSPeter Dunlap * TASK_ABORTED so we can use the same code path. 1435*a6d42e7dSPeter Dunlap */ 1436*a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(&idt->idt_refcnt, 1437*a6d42e7dSPeter Dunlap &idm_task_abort_unref_cb); 1438*a6d42e7dSPeter Dunlap return; 1439*a6d42e7dSPeter Dunlap default: 1440*a6d42e7dSPeter Dunlap ASSERT(0); 1441*a6d42e7dSPeter Dunlap } 1442*a6d42e7dSPeter Dunlap break; 1443*a6d42e7dSPeter Dunlap case TASK_ABORTING: 1444*a6d42e7dSPeter Dunlap case TASK_ABORTED: 1445*a6d42e7dSPeter Dunlap switch (abort_type) { 1446*a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND: 1447*a6d42e7dSPeter Dunlap /* We're already past this point... */ 1448*a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT: 1449*a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT: 1450*a6d42e7dSPeter Dunlap /* Already doing it */ 1451*a6d42e7dSPeter Dunlap break; 1452*a6d42e7dSPeter Dunlap default: 1453*a6d42e7dSPeter Dunlap ASSERT(0); 1454*a6d42e7dSPeter Dunlap } 1455*a6d42e7dSPeter Dunlap break; 1456*a6d42e7dSPeter Dunlap case TASK_COMPLETE: 1457*a6d42e7dSPeter Dunlap /* 1458*a6d42e7dSPeter Dunlap * In this case, let it go. The status has already been 1459*a6d42e7dSPeter Dunlap * sent (which may or may not get successfully transmitted) 1460*a6d42e7dSPeter Dunlap * and we don't want to end up in a race between completing 1461*a6d42e7dSPeter Dunlap * the status PDU and marking the task suspended. 1462*a6d42e7dSPeter Dunlap */ 1463*a6d42e7dSPeter Dunlap break; 1464*a6d42e7dSPeter Dunlap default: 1465*a6d42e7dSPeter Dunlap ASSERT(0); 1466*a6d42e7dSPeter Dunlap } 1467*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1468*a6d42e7dSPeter Dunlap } 1469*a6d42e7dSPeter Dunlap 1470*a6d42e7dSPeter Dunlap static void 1471*a6d42e7dSPeter Dunlap idm_task_aborted(idm_task_t *idt, idm_status_t status) 1472*a6d42e7dSPeter Dunlap { 1473*a6d42e7dSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_task_aborted)(idt, status); 1474*a6d42e7dSPeter Dunlap } 1475*a6d42e7dSPeter Dunlap 1476*a6d42e7dSPeter Dunlap void 1477*a6d42e7dSPeter Dunlap idm_task_cleanup(idm_task_t *idt) 1478*a6d42e7dSPeter Dunlap { 1479*a6d42e7dSPeter Dunlap idm_buf_t *idb, *next_idb; 1480*a6d42e7dSPeter Dunlap list_t tmp_buflist; 1481*a6d42e7dSPeter Dunlap ASSERT((idt->idt_state == TASK_SUSPENDED) || 1482*a6d42e7dSPeter Dunlap (idt->idt_state == TASK_ABORTED)); 1483*a6d42e7dSPeter Dunlap 1484*a6d42e7dSPeter Dunlap list_create(&tmp_buflist, sizeof (idm_buf_t), 1485*a6d42e7dSPeter Dunlap offsetof(idm_buf_t, idb_buflink)); 1486*a6d42e7dSPeter Dunlap 1487*a6d42e7dSPeter Dunlap /* 1488*a6d42e7dSPeter Dunlap * Remove all the buffers from the task and add them to a 1489*a6d42e7dSPeter Dunlap * temporary local list -- we do this so that we can hold 1490*a6d42e7dSPeter Dunlap * the task lock and prevent the task from going away if 1491*a6d42e7dSPeter Dunlap * the client decides to call idm_task_done/idm_task_free. 1492*a6d42e7dSPeter Dunlap * This could happen during abort in iscsit. 1493*a6d42e7dSPeter Dunlap */ 1494*a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1495*a6d42e7dSPeter Dunlap for (idb = list_head(&idt->idt_inbufv); 1496*a6d42e7dSPeter Dunlap idb != NULL; 1497*a6d42e7dSPeter Dunlap idb = next_idb) { 1498*a6d42e7dSPeter Dunlap next_idb = list_next(&idt->idt_inbufv, idb); 1499*a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idt, idb); 1500*a6d42e7dSPeter Dunlap list_insert_tail(&tmp_buflist, idb); 1501*a6d42e7dSPeter Dunlap } 1502*a6d42e7dSPeter Dunlap 1503*a6d42e7dSPeter Dunlap for (idb = list_head(&idt->idt_outbufv); 1504*a6d42e7dSPeter Dunlap idb != NULL; 1505*a6d42e7dSPeter Dunlap idb = next_idb) { 1506*a6d42e7dSPeter Dunlap next_idb = list_next(&idt->idt_outbufv, idb); 1507*a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idt, idb); 1508*a6d42e7dSPeter Dunlap list_insert_tail(&tmp_buflist, idb); 1509*a6d42e7dSPeter Dunlap } 1510*a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1511*a6d42e7dSPeter Dunlap 1512*a6d42e7dSPeter Dunlap for (idb = list_head(&tmp_buflist); idb != NULL; idb = next_idb) { 1513*a6d42e7dSPeter Dunlap next_idb = list_next(&tmp_buflist, idb); 1514*a6d42e7dSPeter Dunlap list_remove(&tmp_buflist, idb); 1515*a6d42e7dSPeter Dunlap (*idb->idb_buf_cb)(idb, IDM_STATUS_ABORTED); 1516*a6d42e7dSPeter Dunlap } 1517*a6d42e7dSPeter Dunlap list_destroy(&tmp_buflist); 1518*a6d42e7dSPeter Dunlap } 1519*a6d42e7dSPeter Dunlap 1520*a6d42e7dSPeter Dunlap 1521*a6d42e7dSPeter Dunlap /* 1522*a6d42e7dSPeter Dunlap * idm_pdu_tx 1523*a6d42e7dSPeter Dunlap * 1524*a6d42e7dSPeter Dunlap * This is IDM's implementation of the 'Send_Control' operational primitive. 1525*a6d42e7dSPeter Dunlap * This function is invoked by an initiator iSCSI layer requesting the transfer 1526*a6d42e7dSPeter Dunlap * of a iSCSI command PDU or a target iSCSI layer requesting the transfer of a 1527*a6d42e7dSPeter Dunlap * iSCSI response PDU. The PDU will be transmitted as-is by the local Datamover 1528*a6d42e7dSPeter Dunlap * layer to the peer iSCSI layer in the remote iSCSI node. The connection info 1529*a6d42e7dSPeter Dunlap * and iSCSI PDU-specific qualifiers namely BHS, AHS, DataDescriptor and Size 1530*a6d42e7dSPeter Dunlap * are provided as input. 1531*a6d42e7dSPeter Dunlap * 1532*a6d42e7dSPeter Dunlap */ 1533*a6d42e7dSPeter Dunlap void 1534*a6d42e7dSPeter Dunlap idm_pdu_tx(idm_pdu_t *pdu) 1535*a6d42e7dSPeter Dunlap { 1536*a6d42e7dSPeter Dunlap idm_conn_t *ic = pdu->isp_ic; 1537*a6d42e7dSPeter Dunlap iscsi_async_evt_hdr_t *async_evt; 1538*a6d42e7dSPeter Dunlap 1539*a6d42e7dSPeter Dunlap /* 1540*a6d42e7dSPeter Dunlap * If we are in full-featured mode then route SCSI-related 1541*a6d42e7dSPeter Dunlap * commands to the appropriate function vector without checking 1542*a6d42e7dSPeter Dunlap * the connection state. We will only be in full-feature mode 1543*a6d42e7dSPeter Dunlap * when we are in an acceptable state for SCSI PDU's. 1544*a6d42e7dSPeter Dunlap * 1545*a6d42e7dSPeter Dunlap * We also need to ensure that there are no PDU events outstanding 1546*a6d42e7dSPeter Dunlap * on the state machine. Any non-SCSI PDU's received in full-feature 1547*a6d42e7dSPeter Dunlap * mode will result in PDU events and until these have been handled 1548*a6d42e7dSPeter Dunlap * we need to route all PDU's through the state machine as PDU 1549*a6d42e7dSPeter Dunlap * events to maintain ordering. 1550*a6d42e7dSPeter Dunlap * 1551*a6d42e7dSPeter Dunlap * Note that IDM cannot enter FFP mode until it processes in 1552*a6d42e7dSPeter Dunlap * its state machine the last xmit of the login process. 1553*a6d42e7dSPeter Dunlap * Hence, checking the IDM_PDU_LOGIN_TX flag here would be 1554*a6d42e7dSPeter Dunlap * superfluous. 1555*a6d42e7dSPeter Dunlap */ 1556*a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 1557*a6d42e7dSPeter Dunlap if (ic->ic_ffp && (ic->ic_pdu_events == 0)) { 1558*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 1559*a6d42e7dSPeter Dunlap switch (IDM_PDU_OPCODE(pdu)) { 1560*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_RSP: 1561*a6d42e7dSPeter Dunlap /* Target only */ 1562*a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1563*a6d42e7dSPeter Dunlap return; 1564*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_RSP: 1565*a6d42e7dSPeter Dunlap /* Target only */ 1566*a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1567*a6d42e7dSPeter Dunlap return; 1568*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA_RSP: 1569*a6d42e7dSPeter Dunlap /* Target only */ 1570*a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1571*a6d42e7dSPeter Dunlap return; 1572*a6d42e7dSPeter Dunlap case ISCSI_OP_RTT_RSP: 1573*a6d42e7dSPeter Dunlap /* Target only */ 1574*a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1575*a6d42e7dSPeter Dunlap return; 1576*a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_IN: 1577*a6d42e7dSPeter Dunlap /* Target only */ 1578*a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1579*a6d42e7dSPeter Dunlap return; 1580*a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_RSP: 1581*a6d42e7dSPeter Dunlap /* Target only */ 1582*a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1583*a6d42e7dSPeter Dunlap return; 1584*a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_CMD: 1585*a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_OUT: 1586*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_CMD: 1587*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA: 1588*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_MSG: 1589*a6d42e7dSPeter Dunlap /* Initiator only */ 1590*a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu); 1591*a6d42e7dSPeter Dunlap return; 1592*a6d42e7dSPeter Dunlap default: 1593*a6d42e7dSPeter Dunlap break; 1594*a6d42e7dSPeter Dunlap } 1595*a6d42e7dSPeter Dunlap 1596*a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 1597*a6d42e7dSPeter Dunlap } 1598*a6d42e7dSPeter Dunlap 1599*a6d42e7dSPeter Dunlap /* 1600*a6d42e7dSPeter Dunlap * Any PDU's processed outside of full-feature mode and non-SCSI 1601*a6d42e7dSPeter Dunlap * PDU's in full-feature mode are handled by generating an 1602*a6d42e7dSPeter Dunlap * event to the connection state machine. The state machine 1603*a6d42e7dSPeter Dunlap * will validate the PDU against the current state and either 1604*a6d42e7dSPeter Dunlap * transmit the PDU if the opcode is allowed or handle an 1605*a6d42e7dSPeter Dunlap * error if the PDU is not allowed. 1606*a6d42e7dSPeter Dunlap * 1607*a6d42e7dSPeter Dunlap * This code-path will also generate any events that are implied 1608*a6d42e7dSPeter Dunlap * by the PDU opcode. For example a "login response" with success 1609*a6d42e7dSPeter Dunlap * status generates a CE_LOGOUT_SUCCESS_SND event. 1610*a6d42e7dSPeter Dunlap */ 1611*a6d42e7dSPeter Dunlap switch (IDM_PDU_OPCODE(pdu)) { 1612*a6d42e7dSPeter Dunlap case ISCSI_OP_LOGIN_CMD: 1613*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_LOGIN_SND, (uintptr_t)pdu); 1614*a6d42e7dSPeter Dunlap break; 1615*a6d42e7dSPeter Dunlap case ISCSI_OP_LOGIN_RSP: 1616*a6d42e7dSPeter Dunlap idm_parse_login_rsp(ic, pdu, /* Is RX */ B_FALSE); 1617*a6d42e7dSPeter Dunlap break; 1618*a6d42e7dSPeter Dunlap case ISCSI_OP_LOGOUT_CMD: 1619*a6d42e7dSPeter Dunlap idm_parse_logout_req(ic, pdu, /* Is RX */ B_FALSE); 1620*a6d42e7dSPeter Dunlap break; 1621*a6d42e7dSPeter Dunlap case ISCSI_OP_LOGOUT_RSP: 1622*a6d42e7dSPeter Dunlap idm_parse_logout_rsp(ic, pdu, /* Is RX */ B_FALSE); 1623*a6d42e7dSPeter Dunlap break; 1624*a6d42e7dSPeter Dunlap case ISCSI_OP_ASYNC_EVENT: 1625*a6d42e7dSPeter Dunlap async_evt = (iscsi_async_evt_hdr_t *)pdu->isp_hdr; 1626*a6d42e7dSPeter Dunlap switch (async_evt->async_event) { 1627*a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT: 1628*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_ASYNC_LOGOUT_SND, 1629*a6d42e7dSPeter Dunlap (uintptr_t)pdu); 1630*a6d42e7dSPeter Dunlap break; 1631*a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION: 1632*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_ASYNC_DROP_CONN_SND, 1633*a6d42e7dSPeter Dunlap (uintptr_t)pdu); 1634*a6d42e7dSPeter Dunlap break; 1635*a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS: 1636*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_ASYNC_DROP_ALL_CONN_SND, 1637*a6d42e7dSPeter Dunlap (uintptr_t)pdu); 1638*a6d42e7dSPeter Dunlap break; 1639*a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_SCSI_EVENT: 1640*a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION: 1641*a6d42e7dSPeter Dunlap default: 1642*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, 1643*a6d42e7dSPeter Dunlap (uintptr_t)pdu); 1644*a6d42e7dSPeter Dunlap break; 1645*a6d42e7dSPeter Dunlap } 1646*a6d42e7dSPeter Dunlap break; 1647*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_RSP: 1648*a6d42e7dSPeter Dunlap /* Target only */ 1649*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1650*a6d42e7dSPeter Dunlap break; 1651*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_RSP: 1652*a6d42e7dSPeter Dunlap /* Target only */ 1653*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1654*a6d42e7dSPeter Dunlap break; 1655*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA_RSP: 1656*a6d42e7dSPeter Dunlap /* Target only */ 1657*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1658*a6d42e7dSPeter Dunlap break; 1659*a6d42e7dSPeter Dunlap case ISCSI_OP_RTT_RSP: 1660*a6d42e7dSPeter Dunlap /* Target only */ 1661*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1662*a6d42e7dSPeter Dunlap break; 1663*a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_IN: 1664*a6d42e7dSPeter Dunlap /* Target only */ 1665*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1666*a6d42e7dSPeter Dunlap break; 1667*a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_RSP: 1668*a6d42e7dSPeter Dunlap /* Target only */ 1669*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1670*a6d42e7dSPeter Dunlap break; 1671*a6d42e7dSPeter Dunlap /* Initiator only */ 1672*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_CMD: 1673*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_MSG: 1674*a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA: 1675*a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_OUT: 1676*a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_CMD: 1677*a6d42e7dSPeter Dunlap case ISCSI_OP_SNACK_CMD: 1678*a6d42e7dSPeter Dunlap case ISCSI_OP_REJECT_MSG: 1679*a6d42e7dSPeter Dunlap default: 1680*a6d42e7dSPeter Dunlap /* 1681*a6d42e7dSPeter Dunlap * Connection state machine will validate these PDU's against 1682*a6d42e7dSPeter Dunlap * the current state. A PDU not allowed in the current 1683*a6d42e7dSPeter Dunlap * state will cause a protocol error. 1684*a6d42e7dSPeter Dunlap */ 1685*a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu); 1686*a6d42e7dSPeter Dunlap break; 1687*a6d42e7dSPeter Dunlap } 1688*a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 1689*a6d42e7dSPeter Dunlap } 1690*a6d42e7dSPeter Dunlap 1691*a6d42e7dSPeter Dunlap /* 1692*a6d42e7dSPeter Dunlap * Allocates a PDU along with memory for header and data. 1693*a6d42e7dSPeter Dunlap */ 1694*a6d42e7dSPeter Dunlap 1695*a6d42e7dSPeter Dunlap idm_pdu_t * 1696*a6d42e7dSPeter Dunlap idm_pdu_alloc(uint_t hdrlen, uint_t datalen) 1697*a6d42e7dSPeter Dunlap { 1698*a6d42e7dSPeter Dunlap idm_pdu_t *result; 1699*a6d42e7dSPeter Dunlap 1700*a6d42e7dSPeter Dunlap /* 1701*a6d42e7dSPeter Dunlap * IDM clients should cache these structures for performance 1702*a6d42e7dSPeter Dunlap * critical paths. We can't cache effectively in IDM because we 1703*a6d42e7dSPeter Dunlap * don't know the correct header and data size. 1704*a6d42e7dSPeter Dunlap * 1705*a6d42e7dSPeter Dunlap * Valid header length is assumed to be hdrlen and valid data 1706*a6d42e7dSPeter Dunlap * length is assumed to be datalen. isp_hdrlen and isp_datalen 1707*a6d42e7dSPeter Dunlap * can be adjusted after the PDU is returned if necessary. 1708*a6d42e7dSPeter Dunlap */ 1709*a6d42e7dSPeter Dunlap result = kmem_zalloc(sizeof (idm_pdu_t) + hdrlen + datalen, KM_SLEEP); 1710*a6d42e7dSPeter Dunlap result->isp_flags |= IDM_PDU_ALLOC; /* For idm_pdu_free sanity check */ 1711*a6d42e7dSPeter Dunlap result->isp_hdr = (iscsi_hdr_t *)(result + 1); /* Ptr. Arithmetic */ 1712*a6d42e7dSPeter Dunlap result->isp_hdrlen = hdrlen; 1713*a6d42e7dSPeter Dunlap result->isp_hdrbuflen = hdrlen; 1714*a6d42e7dSPeter Dunlap result->isp_transport_hdrlen = 0; 1715*a6d42e7dSPeter Dunlap result->isp_data = (uint8_t *)result->isp_hdr + hdrlen; 1716*a6d42e7dSPeter Dunlap result->isp_datalen = datalen; 1717*a6d42e7dSPeter Dunlap result->isp_databuflen = datalen; 1718*a6d42e7dSPeter Dunlap result->isp_magic = IDM_PDU_MAGIC; 1719*a6d42e7dSPeter Dunlap 1720*a6d42e7dSPeter Dunlap return (result); 1721*a6d42e7dSPeter Dunlap } 1722*a6d42e7dSPeter Dunlap 1723*a6d42e7dSPeter Dunlap /* 1724*a6d42e7dSPeter Dunlap * Free a PDU previously allocated with idm_pdu_alloc() including any 1725*a6d42e7dSPeter Dunlap * header and data space allocated as part of the original request. 1726*a6d42e7dSPeter Dunlap * Additional memory regions referenced by subsequent modification of 1727*a6d42e7dSPeter Dunlap * the isp_hdr and/or isp_data fields will not be freed. 1728*a6d42e7dSPeter Dunlap */ 1729*a6d42e7dSPeter Dunlap void 1730*a6d42e7dSPeter Dunlap idm_pdu_free(idm_pdu_t *pdu) 1731*a6d42e7dSPeter Dunlap { 1732*a6d42e7dSPeter Dunlap /* Make sure the structure was allocated using idm_pdu_alloc() */ 1733*a6d42e7dSPeter Dunlap ASSERT(pdu->isp_flags & IDM_PDU_ALLOC); 1734*a6d42e7dSPeter Dunlap kmem_free(pdu, 1735*a6d42e7dSPeter Dunlap sizeof (idm_pdu_t) + pdu->isp_hdrbuflen + pdu->isp_databuflen); 1736*a6d42e7dSPeter Dunlap } 1737*a6d42e7dSPeter Dunlap 1738*a6d42e7dSPeter Dunlap /* 1739*a6d42e7dSPeter Dunlap * Initialize the connection, private and callback fields in a PDU. 1740*a6d42e7dSPeter Dunlap */ 1741*a6d42e7dSPeter Dunlap void 1742*a6d42e7dSPeter Dunlap idm_pdu_init(idm_pdu_t *pdu, idm_conn_t *ic, void *private, idm_pdu_cb_t *cb) 1743*a6d42e7dSPeter Dunlap { 1744*a6d42e7dSPeter Dunlap /* 1745*a6d42e7dSPeter Dunlap * idm_pdu_complete() will call idm_pdu_free if the callback is 1746*a6d42e7dSPeter Dunlap * NULL. This will only work if the PDU was originally allocated 1747*a6d42e7dSPeter Dunlap * with idm_pdu_alloc(). 1748*a6d42e7dSPeter Dunlap */ 1749*a6d42e7dSPeter Dunlap ASSERT((pdu->isp_flags & IDM_PDU_ALLOC) || 1750*a6d42e7dSPeter Dunlap (cb != NULL)); 1751*a6d42e7dSPeter Dunlap pdu->isp_magic = IDM_PDU_MAGIC; 1752*a6d42e7dSPeter Dunlap pdu->isp_ic = ic; 1753*a6d42e7dSPeter Dunlap pdu->isp_private = private; 1754*a6d42e7dSPeter Dunlap pdu->isp_callback = cb; 1755*a6d42e7dSPeter Dunlap } 1756*a6d42e7dSPeter Dunlap 1757*a6d42e7dSPeter Dunlap /* 1758*a6d42e7dSPeter Dunlap * Initialize the header and header length field. This function should 1759*a6d42e7dSPeter Dunlap * not be used to adjust the header length in a buffer allocated via 1760*a6d42e7dSPeter Dunlap * pdu_pdu_alloc since it overwrites the existing header pointer. 1761*a6d42e7dSPeter Dunlap */ 1762*a6d42e7dSPeter Dunlap void 1763*a6d42e7dSPeter Dunlap idm_pdu_init_hdr(idm_pdu_t *pdu, uint8_t *hdr, uint_t hdrlen) 1764*a6d42e7dSPeter Dunlap { 1765*a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)((void *)hdr); 1766*a6d42e7dSPeter Dunlap pdu->isp_hdrlen = hdrlen; 1767*a6d42e7dSPeter Dunlap } 1768*a6d42e7dSPeter Dunlap 1769*a6d42e7dSPeter Dunlap /* 1770*a6d42e7dSPeter Dunlap * Initialize the data and data length fields. This function should 1771*a6d42e7dSPeter Dunlap * not be used to adjust the data length of a buffer allocated via 1772*a6d42e7dSPeter Dunlap * idm_pdu_alloc since it overwrites the existing data pointer. 1773*a6d42e7dSPeter Dunlap */ 1774*a6d42e7dSPeter Dunlap void 1775*a6d42e7dSPeter Dunlap idm_pdu_init_data(idm_pdu_t *pdu, uint8_t *data, uint_t datalen) 1776*a6d42e7dSPeter Dunlap { 1777*a6d42e7dSPeter Dunlap pdu->isp_data = data; 1778*a6d42e7dSPeter Dunlap pdu->isp_datalen = datalen; 1779*a6d42e7dSPeter Dunlap } 1780*a6d42e7dSPeter Dunlap 1781*a6d42e7dSPeter Dunlap void 1782*a6d42e7dSPeter Dunlap idm_pdu_complete(idm_pdu_t *pdu, idm_status_t status) 1783*a6d42e7dSPeter Dunlap { 1784*a6d42e7dSPeter Dunlap if (pdu->isp_callback) { 1785*a6d42e7dSPeter Dunlap pdu->isp_status = status; 1786*a6d42e7dSPeter Dunlap (*pdu->isp_callback)(pdu, status); 1787*a6d42e7dSPeter Dunlap } else { 1788*a6d42e7dSPeter Dunlap idm_pdu_free(pdu); 1789*a6d42e7dSPeter Dunlap } 1790*a6d42e7dSPeter Dunlap } 1791*a6d42e7dSPeter Dunlap 1792*a6d42e7dSPeter Dunlap /* 1793*a6d42e7dSPeter Dunlap * State machine auditing 1794*a6d42e7dSPeter Dunlap */ 1795*a6d42e7dSPeter Dunlap 1796*a6d42e7dSPeter Dunlap void 1797*a6d42e7dSPeter Dunlap idm_sm_audit_init(sm_audit_buf_t *audit_buf) 1798*a6d42e7dSPeter Dunlap { 1799*a6d42e7dSPeter Dunlap bzero(audit_buf, sizeof (sm_audit_buf_t)); 1800*a6d42e7dSPeter Dunlap audit_buf->sab_max_index = SM_AUDIT_BUF_MAX_REC - 1; 1801*a6d42e7dSPeter Dunlap } 1802*a6d42e7dSPeter Dunlap 1803*a6d42e7dSPeter Dunlap static 1804*a6d42e7dSPeter Dunlap sm_audit_record_t * 1805*a6d42e7dSPeter Dunlap idm_sm_audit_common(sm_audit_buf_t *audit_buf, sm_audit_record_type_t r_type, 1806*a6d42e7dSPeter Dunlap sm_audit_sm_type_t sm_type, 1807*a6d42e7dSPeter Dunlap int current_state) 1808*a6d42e7dSPeter Dunlap { 1809*a6d42e7dSPeter Dunlap sm_audit_record_t *sar; 1810*a6d42e7dSPeter Dunlap 1811*a6d42e7dSPeter Dunlap sar = audit_buf->sab_records; 1812*a6d42e7dSPeter Dunlap sar += audit_buf->sab_index; 1813*a6d42e7dSPeter Dunlap audit_buf->sab_index++; 1814*a6d42e7dSPeter Dunlap audit_buf->sab_index &= audit_buf->sab_max_index; 1815*a6d42e7dSPeter Dunlap 1816*a6d42e7dSPeter Dunlap sar->sar_type = r_type; 1817*a6d42e7dSPeter Dunlap gethrestime(&sar->sar_timestamp); 1818*a6d42e7dSPeter Dunlap sar->sar_sm_type = sm_type; 1819*a6d42e7dSPeter Dunlap sar->sar_state = current_state; 1820*a6d42e7dSPeter Dunlap 1821*a6d42e7dSPeter Dunlap return (sar); 1822*a6d42e7dSPeter Dunlap } 1823*a6d42e7dSPeter Dunlap 1824*a6d42e7dSPeter Dunlap void 1825*a6d42e7dSPeter Dunlap idm_sm_audit_event(sm_audit_buf_t *audit_buf, 1826*a6d42e7dSPeter Dunlap sm_audit_sm_type_t sm_type, int current_state, 1827*a6d42e7dSPeter Dunlap int event, uintptr_t event_info) 1828*a6d42e7dSPeter Dunlap { 1829*a6d42e7dSPeter Dunlap sm_audit_record_t *sar; 1830*a6d42e7dSPeter Dunlap 1831*a6d42e7dSPeter Dunlap sar = idm_sm_audit_common(audit_buf, SAR_STATE_EVENT, 1832*a6d42e7dSPeter Dunlap sm_type, current_state); 1833*a6d42e7dSPeter Dunlap sar->sar_event = event; 1834*a6d42e7dSPeter Dunlap sar->sar_event_info = event_info; 1835*a6d42e7dSPeter Dunlap } 1836*a6d42e7dSPeter Dunlap 1837*a6d42e7dSPeter Dunlap void 1838*a6d42e7dSPeter Dunlap idm_sm_audit_state_change(sm_audit_buf_t *audit_buf, 1839*a6d42e7dSPeter Dunlap sm_audit_sm_type_t sm_type, int current_state, int new_state) 1840*a6d42e7dSPeter Dunlap { 1841*a6d42e7dSPeter Dunlap sm_audit_record_t *sar; 1842*a6d42e7dSPeter Dunlap 1843*a6d42e7dSPeter Dunlap sar = idm_sm_audit_common(audit_buf, SAR_STATE_CHANGE, 1844*a6d42e7dSPeter Dunlap sm_type, current_state); 1845*a6d42e7dSPeter Dunlap sar->sar_new_state = new_state; 1846*a6d42e7dSPeter Dunlap } 1847*a6d42e7dSPeter Dunlap 1848*a6d42e7dSPeter Dunlap 1849*a6d42e7dSPeter Dunlap /* 1850*a6d42e7dSPeter Dunlap * Object reference tracking 1851*a6d42e7dSPeter Dunlap */ 1852*a6d42e7dSPeter Dunlap 1853*a6d42e7dSPeter Dunlap void 1854*a6d42e7dSPeter Dunlap idm_refcnt_init(idm_refcnt_t *refcnt, void *referenced_obj) 1855*a6d42e7dSPeter Dunlap { 1856*a6d42e7dSPeter Dunlap bzero(refcnt, sizeof (*refcnt)); 1857*a6d42e7dSPeter Dunlap idm_refcnt_reset(refcnt); 1858*a6d42e7dSPeter Dunlap refcnt->ir_referenced_obj = referenced_obj; 1859*a6d42e7dSPeter Dunlap bzero(&refcnt->ir_audit_buf, sizeof (refcnt_audit_buf_t)); 1860*a6d42e7dSPeter Dunlap refcnt->ir_audit_buf.anb_max_index = REFCNT_AUDIT_BUF_MAX_REC - 1; 1861*a6d42e7dSPeter Dunlap mutex_init(&refcnt->ir_mutex, NULL, MUTEX_DEFAULT, NULL); 1862*a6d42e7dSPeter Dunlap cv_init(&refcnt->ir_cv, NULL, CV_DEFAULT, NULL); 1863*a6d42e7dSPeter Dunlap } 1864*a6d42e7dSPeter Dunlap 1865*a6d42e7dSPeter Dunlap void 1866*a6d42e7dSPeter Dunlap idm_refcnt_destroy(idm_refcnt_t *refcnt) 1867*a6d42e7dSPeter Dunlap { 1868*a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_refcnt == 0); 1869*a6d42e7dSPeter Dunlap cv_destroy(&refcnt->ir_cv); 1870*a6d42e7dSPeter Dunlap mutex_destroy(&refcnt->ir_mutex); 1871*a6d42e7dSPeter Dunlap } 1872*a6d42e7dSPeter Dunlap 1873*a6d42e7dSPeter Dunlap void 1874*a6d42e7dSPeter Dunlap idm_refcnt_reset(idm_refcnt_t *refcnt) 1875*a6d42e7dSPeter Dunlap { 1876*a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_NOWAIT; 1877*a6d42e7dSPeter Dunlap refcnt->ir_refcnt = 0; 1878*a6d42e7dSPeter Dunlap } 1879*a6d42e7dSPeter Dunlap 1880*a6d42e7dSPeter Dunlap void 1881*a6d42e7dSPeter Dunlap idm_refcnt_hold(idm_refcnt_t *refcnt) 1882*a6d42e7dSPeter Dunlap { 1883*a6d42e7dSPeter Dunlap /* 1884*a6d42e7dSPeter Dunlap * Nothing should take a hold on an object after a call to 1885*a6d42e7dSPeter Dunlap * idm_refcnt_wait_ref or idm_refcnd_async_wait_ref 1886*a6d42e7dSPeter Dunlap */ 1887*a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_waiting == REF_NOWAIT); 1888*a6d42e7dSPeter Dunlap 1889*a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 1890*a6d42e7dSPeter Dunlap refcnt->ir_refcnt++; 1891*a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 1892*a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 1893*a6d42e7dSPeter Dunlap } 1894*a6d42e7dSPeter Dunlap 1895*a6d42e7dSPeter Dunlap static void 1896*a6d42e7dSPeter Dunlap idm_refcnt_unref_task(void *refcnt_void) 1897*a6d42e7dSPeter Dunlap { 1898*a6d42e7dSPeter Dunlap idm_refcnt_t *refcnt = refcnt_void; 1899*a6d42e7dSPeter Dunlap 1900*a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 1901*a6d42e7dSPeter Dunlap (*refcnt->ir_cb)(refcnt->ir_referenced_obj); 1902*a6d42e7dSPeter Dunlap } 1903*a6d42e7dSPeter Dunlap 1904*a6d42e7dSPeter Dunlap void 1905*a6d42e7dSPeter Dunlap idm_refcnt_rele(idm_refcnt_t *refcnt) 1906*a6d42e7dSPeter Dunlap { 1907*a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 1908*a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_refcnt > 0); 1909*a6d42e7dSPeter Dunlap refcnt->ir_refcnt--; 1910*a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 1911*a6d42e7dSPeter Dunlap if (refcnt->ir_waiting == REF_NOWAIT) { 1912*a6d42e7dSPeter Dunlap /* No one is waiting on this object */ 1913*a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 1914*a6d42e7dSPeter Dunlap return; 1915*a6d42e7dSPeter Dunlap } 1916*a6d42e7dSPeter Dunlap 1917*a6d42e7dSPeter Dunlap /* 1918*a6d42e7dSPeter Dunlap * Someone is waiting for this object to go idle so check if 1919*a6d42e7dSPeter Dunlap * refcnt is 0. Waiting on an object then later grabbing another 1920*a6d42e7dSPeter Dunlap * reference is not allowed so we don't need to handle that case. 1921*a6d42e7dSPeter Dunlap */ 1922*a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) { 1923*a6d42e7dSPeter Dunlap if (refcnt->ir_waiting == REF_WAIT_ASYNC) { 1924*a6d42e7dSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq, 1925*a6d42e7dSPeter Dunlap &idm_refcnt_unref_task, refcnt, TQ_SLEEP) == NULL) { 1926*a6d42e7dSPeter Dunlap cmn_err(CE_WARN, 1927*a6d42e7dSPeter Dunlap "idm_refcnt_rele: Couldn't dispatch task"); 1928*a6d42e7dSPeter Dunlap } 1929*a6d42e7dSPeter Dunlap } else if (refcnt->ir_waiting == REF_WAIT_SYNC) { 1930*a6d42e7dSPeter Dunlap cv_signal(&refcnt->ir_cv); 1931*a6d42e7dSPeter Dunlap } 1932*a6d42e7dSPeter Dunlap } 1933*a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 1934*a6d42e7dSPeter Dunlap } 1935*a6d42e7dSPeter Dunlap 1936*a6d42e7dSPeter Dunlap void 1937*a6d42e7dSPeter Dunlap idm_refcnt_rele_and_destroy(idm_refcnt_t *refcnt, idm_refcnt_cb_t *cb_func) 1938*a6d42e7dSPeter Dunlap { 1939*a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 1940*a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_refcnt > 0); 1941*a6d42e7dSPeter Dunlap refcnt->ir_refcnt--; 1942*a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 1943*a6d42e7dSPeter Dunlap 1944*a6d42e7dSPeter Dunlap /* 1945*a6d42e7dSPeter Dunlap * Someone is waiting for this object to go idle so check if 1946*a6d42e7dSPeter Dunlap * refcnt is 0. Waiting on an object then later grabbing another 1947*a6d42e7dSPeter Dunlap * reference is not allowed so we don't need to handle that case. 1948*a6d42e7dSPeter Dunlap */ 1949*a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) { 1950*a6d42e7dSPeter Dunlap refcnt->ir_cb = cb_func; 1951*a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_WAIT_ASYNC; 1952*a6d42e7dSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq, 1953*a6d42e7dSPeter Dunlap &idm_refcnt_unref_task, refcnt, TQ_SLEEP) == NULL) { 1954*a6d42e7dSPeter Dunlap cmn_err(CE_WARN, 1955*a6d42e7dSPeter Dunlap "idm_refcnt_rele: Couldn't dispatch task"); 1956*a6d42e7dSPeter Dunlap } 1957*a6d42e7dSPeter Dunlap } 1958*a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 1959*a6d42e7dSPeter Dunlap } 1960*a6d42e7dSPeter Dunlap 1961*a6d42e7dSPeter Dunlap void 1962*a6d42e7dSPeter Dunlap idm_refcnt_wait_ref(idm_refcnt_t *refcnt) 1963*a6d42e7dSPeter Dunlap { 1964*a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 1965*a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_WAIT_SYNC; 1966*a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 1967*a6d42e7dSPeter Dunlap while (refcnt->ir_refcnt != 0) 1968*a6d42e7dSPeter Dunlap cv_wait(&refcnt->ir_cv, &refcnt->ir_mutex); 1969*a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 1970*a6d42e7dSPeter Dunlap } 1971*a6d42e7dSPeter Dunlap 1972*a6d42e7dSPeter Dunlap void 1973*a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(idm_refcnt_t *refcnt, idm_refcnt_cb_t *cb_func) 1974*a6d42e7dSPeter Dunlap { 1975*a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 1976*a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_WAIT_ASYNC; 1977*a6d42e7dSPeter Dunlap refcnt->ir_cb = cb_func; 1978*a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt); 1979*a6d42e7dSPeter Dunlap /* 1980*a6d42e7dSPeter Dunlap * It's possible we don't have any references. To make things easier 1981*a6d42e7dSPeter Dunlap * on the caller use a taskq to call the callback instead of 1982*a6d42e7dSPeter Dunlap * calling it synchronously 1983*a6d42e7dSPeter Dunlap */ 1984*a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) { 1985*a6d42e7dSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq, 1986*a6d42e7dSPeter Dunlap &idm_refcnt_unref_task, refcnt, TQ_SLEEP) == NULL) { 1987*a6d42e7dSPeter Dunlap cmn_err(CE_WARN, 1988*a6d42e7dSPeter Dunlap "idm_refcnt_async_wait_ref: " 1989*a6d42e7dSPeter Dunlap "Couldn't dispatch task"); 1990*a6d42e7dSPeter Dunlap } 1991*a6d42e7dSPeter Dunlap } 1992*a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 1993*a6d42e7dSPeter Dunlap } 1994*a6d42e7dSPeter Dunlap 1995*a6d42e7dSPeter Dunlap void 1996*a6d42e7dSPeter Dunlap idm_refcnt_destroy_unref_obj(idm_refcnt_t *refcnt, 1997*a6d42e7dSPeter Dunlap idm_refcnt_cb_t *cb_func) 1998*a6d42e7dSPeter Dunlap { 1999*a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex); 2000*a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) { 2001*a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2002*a6d42e7dSPeter Dunlap (*cb_func)(refcnt->ir_referenced_obj); 2003*a6d42e7dSPeter Dunlap return; 2004*a6d42e7dSPeter Dunlap } 2005*a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex); 2006*a6d42e7dSPeter Dunlap } 2007*a6d42e7dSPeter Dunlap 2008*a6d42e7dSPeter Dunlap void 2009*a6d42e7dSPeter Dunlap idm_conn_hold(idm_conn_t *ic) 2010*a6d42e7dSPeter Dunlap { 2011*a6d42e7dSPeter Dunlap idm_refcnt_hold(&ic->ic_refcnt); 2012*a6d42e7dSPeter Dunlap } 2013*a6d42e7dSPeter Dunlap 2014*a6d42e7dSPeter Dunlap void 2015*a6d42e7dSPeter Dunlap idm_conn_rele(idm_conn_t *ic) 2016*a6d42e7dSPeter Dunlap { 2017*a6d42e7dSPeter Dunlap idm_refcnt_rele(&ic->ic_refcnt); 2018*a6d42e7dSPeter Dunlap } 2019*a6d42e7dSPeter Dunlap 2020*a6d42e7dSPeter Dunlap 2021*a6d42e7dSPeter Dunlap static int 2022*a6d42e7dSPeter Dunlap _idm_init(void) 2023*a6d42e7dSPeter Dunlap { 2024*a6d42e7dSPeter Dunlap /* Initialize the rwlock for the taskid table */ 2025*a6d42e7dSPeter Dunlap rw_init(&idm.idm_taskid_table_lock, NULL, RW_DRIVER, NULL); 2026*a6d42e7dSPeter Dunlap 2027*a6d42e7dSPeter Dunlap /* Initialize the global mutex and taskq */ 2028*a6d42e7dSPeter Dunlap mutex_init(&idm.idm_global_mutex, NULL, MUTEX_DEFAULT, NULL); 2029*a6d42e7dSPeter Dunlap 2030*a6d42e7dSPeter Dunlap cv_init(&idm.idm_tgt_svc_cv, NULL, CV_DEFAULT, NULL); 2031*a6d42e7dSPeter Dunlap cv_init(&idm.idm_wd_cv, NULL, CV_DEFAULT, NULL); 2032*a6d42e7dSPeter Dunlap 2033*a6d42e7dSPeter Dunlap idm.idm_global_taskq = taskq_create("idm_global_taskq", 1, minclsyspri, 2034*a6d42e7dSPeter Dunlap 4, 4, TASKQ_PREPOPULATE); 2035*a6d42e7dSPeter Dunlap if (idm.idm_global_taskq == NULL) { 2036*a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_wd_cv); 2037*a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_tgt_svc_cv); 2038*a6d42e7dSPeter Dunlap mutex_destroy(&idm.idm_global_mutex); 2039*a6d42e7dSPeter Dunlap rw_destroy(&idm.idm_taskid_table_lock); 2040*a6d42e7dSPeter Dunlap return (ENOMEM); 2041*a6d42e7dSPeter Dunlap } 2042*a6d42e7dSPeter Dunlap 2043*a6d42e7dSPeter Dunlap /* start watchdog thread */ 2044*a6d42e7dSPeter Dunlap idm.idm_wd_thread = thread_create(NULL, 0, 2045*a6d42e7dSPeter Dunlap idm_wd_thread, NULL, 0, &p0, TS_RUN, minclsyspri); 2046*a6d42e7dSPeter Dunlap if (idm.idm_wd_thread == NULL) { 2047*a6d42e7dSPeter Dunlap /* Couldn't create the watchdog thread */ 2048*a6d42e7dSPeter Dunlap taskq_destroy(idm.idm_global_taskq); 2049*a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_wd_cv); 2050*a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_tgt_svc_cv); 2051*a6d42e7dSPeter Dunlap mutex_destroy(&idm.idm_global_mutex); 2052*a6d42e7dSPeter Dunlap rw_destroy(&idm.idm_taskid_table_lock); 2053*a6d42e7dSPeter Dunlap return (ENOMEM); 2054*a6d42e7dSPeter Dunlap } 2055*a6d42e7dSPeter Dunlap 2056*a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 2057*a6d42e7dSPeter Dunlap while (!idm.idm_wd_thread_running) 2058*a6d42e7dSPeter Dunlap cv_wait(&idm.idm_wd_cv, &idm.idm_global_mutex); 2059*a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 2060*a6d42e7dSPeter Dunlap 2061*a6d42e7dSPeter Dunlap /* 2062*a6d42e7dSPeter Dunlap * Allocate the task ID table and set "next" to 0. 2063*a6d42e7dSPeter Dunlap */ 2064*a6d42e7dSPeter Dunlap 2065*a6d42e7dSPeter Dunlap idm.idm_taskid_max = idm_max_taskids; 2066*a6d42e7dSPeter Dunlap idm.idm_taskid_table = (idm_task_t **) 2067*a6d42e7dSPeter Dunlap kmem_zalloc(idm.idm_taskid_max * sizeof (idm_task_t *), KM_SLEEP); 2068*a6d42e7dSPeter Dunlap idm.idm_taskid_next = 0; 2069*a6d42e7dSPeter Dunlap 2070*a6d42e7dSPeter Dunlap /* Create the global buffer and task kmem caches */ 2071*a6d42e7dSPeter Dunlap idm.idm_buf_cache = kmem_cache_create("idm_buf_cache", 2072*a6d42e7dSPeter Dunlap sizeof (idm_buf_t), 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP); 2073*a6d42e7dSPeter Dunlap 2074*a6d42e7dSPeter Dunlap /* 2075*a6d42e7dSPeter Dunlap * Note, we're explicitly allocating an additional iSER header- 2076*a6d42e7dSPeter Dunlap * sized chunk for each of these elements. See idm_task_constructor(). 2077*a6d42e7dSPeter Dunlap */ 2078*a6d42e7dSPeter Dunlap idm.idm_task_cache = kmem_cache_create("idm_task_cache", 2079*a6d42e7dSPeter Dunlap sizeof (idm_task_t) + IDM_TRANSPORT_HEADER_LENGTH, 8, 2080*a6d42e7dSPeter Dunlap &idm_task_constructor, &idm_task_destructor, 2081*a6d42e7dSPeter Dunlap NULL, NULL, NULL, KM_SLEEP); 2082*a6d42e7dSPeter Dunlap 2083*a6d42e7dSPeter Dunlap /* Create the service and connection context lists */ 2084*a6d42e7dSPeter Dunlap list_create(&idm.idm_tgt_svc_list, sizeof (idm_svc_t), 2085*a6d42e7dSPeter Dunlap offsetof(idm_svc_t, is_list_node)); 2086*a6d42e7dSPeter Dunlap list_create(&idm.idm_tgt_conn_list, sizeof (idm_conn_t), 2087*a6d42e7dSPeter Dunlap offsetof(idm_conn_t, ic_list_node)); 2088*a6d42e7dSPeter Dunlap list_create(&idm.idm_ini_conn_list, sizeof (idm_conn_t), 2089*a6d42e7dSPeter Dunlap offsetof(idm_conn_t, ic_list_node)); 2090*a6d42e7dSPeter Dunlap 2091*a6d42e7dSPeter Dunlap /* Initialize the native sockets transport */ 2092*a6d42e7dSPeter Dunlap idm_so_init(&idm_transport_list[IDM_TRANSPORT_TYPE_SOCKETS]); 2093*a6d42e7dSPeter Dunlap 2094*a6d42e7dSPeter Dunlap /* Create connection ID pool */ 2095*a6d42e7dSPeter Dunlap (void) idm_idpool_create(&idm.idm_conn_id_pool); 2096*a6d42e7dSPeter Dunlap 2097*a6d42e7dSPeter Dunlap return (DDI_SUCCESS); 2098*a6d42e7dSPeter Dunlap } 2099*a6d42e7dSPeter Dunlap 2100*a6d42e7dSPeter Dunlap static int 2101*a6d42e7dSPeter Dunlap _idm_fini(void) 2102*a6d42e7dSPeter Dunlap { 2103*a6d42e7dSPeter Dunlap if (!list_is_empty(&idm.idm_ini_conn_list) || 2104*a6d42e7dSPeter Dunlap !list_is_empty(&idm.idm_tgt_conn_list) || 2105*a6d42e7dSPeter Dunlap !list_is_empty(&idm.idm_tgt_svc_list)) { 2106*a6d42e7dSPeter Dunlap return (EBUSY); 2107*a6d42e7dSPeter Dunlap } 2108*a6d42e7dSPeter Dunlap 2109*a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex); 2110*a6d42e7dSPeter Dunlap idm.idm_wd_thread_running = B_FALSE; 2111*a6d42e7dSPeter Dunlap cv_signal(&idm.idm_wd_cv); 2112*a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex); 2113*a6d42e7dSPeter Dunlap 2114*a6d42e7dSPeter Dunlap thread_join(idm.idm_wd_thread_did); 2115*a6d42e7dSPeter Dunlap 2116*a6d42e7dSPeter Dunlap idm_idpool_destroy(&idm.idm_conn_id_pool); 2117*a6d42e7dSPeter Dunlap idm_so_fini(); 2118*a6d42e7dSPeter Dunlap list_destroy(&idm.idm_ini_conn_list); 2119*a6d42e7dSPeter Dunlap list_destroy(&idm.idm_tgt_conn_list); 2120*a6d42e7dSPeter Dunlap list_destroy(&idm.idm_tgt_svc_list); 2121*a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_task_cache); 2122*a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_buf_cache); 2123*a6d42e7dSPeter Dunlap kmem_free(idm.idm_taskid_table, 2124*a6d42e7dSPeter Dunlap idm.idm_taskid_max * sizeof (idm_task_t *)); 2125*a6d42e7dSPeter Dunlap mutex_destroy(&idm.idm_global_mutex); 2126*a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_wd_cv); 2127*a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_tgt_svc_cv); 2128*a6d42e7dSPeter Dunlap rw_destroy(&idm.idm_taskid_table_lock); 2129*a6d42e7dSPeter Dunlap 2130*a6d42e7dSPeter Dunlap return (0); 2131*a6d42e7dSPeter Dunlap } 2132