1*45039663SJohn Forte /* 2*45039663SJohn Forte * CDDL HEADER START 3*45039663SJohn Forte * 4*45039663SJohn Forte * The contents of this file are subject to the terms of the 5*45039663SJohn Forte * Common Development and Distribution License (the "License"). 6*45039663SJohn Forte * You may not use this file except in compliance with the License. 7*45039663SJohn Forte * 8*45039663SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*45039663SJohn Forte * or http://www.opensolaris.org/os/licensing. 10*45039663SJohn Forte * See the License for the specific language governing permissions 11*45039663SJohn Forte * and limitations under the License. 12*45039663SJohn Forte * 13*45039663SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14*45039663SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*45039663SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16*45039663SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17*45039663SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18*45039663SJohn Forte * 19*45039663SJohn Forte * CDDL HEADER END 20*45039663SJohn Forte */ 21*45039663SJohn Forte /* 22*45039663SJohn Forte * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*45039663SJohn Forte * Use is subject to license terms. 24*45039663SJohn Forte */ 25*45039663SJohn Forte 26*45039663SJohn Forte #include <sys/cpuvar.h> 27*45039663SJohn Forte #include <sys/types.h> 28*45039663SJohn Forte #include <sys/conf.h> 29*45039663SJohn Forte #include <sys/stat.h> 30*45039663SJohn Forte #include <sys/file.h> 31*45039663SJohn Forte #include <sys/ddi.h> 32*45039663SJohn Forte #include <sys/sunddi.h> 33*45039663SJohn Forte #include <sys/modctl.h> 34*45039663SJohn Forte #include <sys/sysmacros.h> 35*45039663SJohn Forte #include <sys/nvpair.h> 36*45039663SJohn Forte #include <sys/door.h> 37*45039663SJohn Forte 38*45039663SJohn Forte #include <sys/stmf.h> 39*45039663SJohn Forte #include <sys/stmf_ioctl.h> 40*45039663SJohn Forte #include <sys/pppt_ioctl.h> 41*45039663SJohn Forte #include <sys/portif.h> 42*45039663SJohn Forte #include <pppt.h> 43*45039663SJohn Forte 44*45039663SJohn Forte #define PPPT_VERSION BUILD_DATE "-1.18dev" 45*45039663SJohn Forte #define PPPT_NAME_VERSION "COMSTAR PPPT v" PPPT_VERSION 46*45039663SJohn Forte 47*45039663SJohn Forte /* 48*45039663SJohn Forte * DDI entry points. 49*45039663SJohn Forte */ 50*45039663SJohn Forte static int pppt_drv_attach(dev_info_t *, ddi_attach_cmd_t); 51*45039663SJohn Forte static int pppt_drv_detach(dev_info_t *, ddi_detach_cmd_t); 52*45039663SJohn Forte static int pppt_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 53*45039663SJohn Forte static int pppt_drv_open(dev_t *, int, int, cred_t *); 54*45039663SJohn Forte static int pppt_drv_close(dev_t, int, int, cred_t *); 55*45039663SJohn Forte static boolean_t pppt_drv_busy(void); 56*45039663SJohn Forte static int pppt_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 57*45039663SJohn Forte 58*45039663SJohn Forte extern pppt_status_t pppt_ic_so_enable(boolean_t); 59*45039663SJohn Forte extern void pppt_ic_so_disable(); 60*45039663SJohn Forte extern void stmf_ic_rx_msg(char *, size_t); 61*45039663SJohn Forte 62*45039663SJohn Forte extern struct mod_ops mod_miscops; 63*45039663SJohn Forte 64*45039663SJohn Forte static struct cb_ops pppt_cb_ops = { 65*45039663SJohn Forte pppt_drv_open, /* cb_open */ 66*45039663SJohn Forte pppt_drv_close, /* cb_close */ 67*45039663SJohn Forte nodev, /* cb_strategy */ 68*45039663SJohn Forte nodev, /* cb_print */ 69*45039663SJohn Forte nodev, /* cb_dump */ 70*45039663SJohn Forte nodev, /* cb_read */ 71*45039663SJohn Forte nodev, /* cb_write */ 72*45039663SJohn Forte pppt_drv_ioctl, /* cb_ioctl */ 73*45039663SJohn Forte nodev, /* cb_devmap */ 74*45039663SJohn Forte nodev, /* cb_mmap */ 75*45039663SJohn Forte nodev, /* cb_segmap */ 76*45039663SJohn Forte nochpoll, /* cb_chpoll */ 77*45039663SJohn Forte ddi_prop_op, /* cb_prop_op */ 78*45039663SJohn Forte NULL, /* cb_streamtab */ 79*45039663SJohn Forte D_MP, /* cb_flag */ 80*45039663SJohn Forte CB_REV, /* cb_rev */ 81*45039663SJohn Forte nodev, /* cb_aread */ 82*45039663SJohn Forte nodev, /* cb_awrite */ 83*45039663SJohn Forte }; 84*45039663SJohn Forte 85*45039663SJohn Forte static struct dev_ops pppt_dev_ops = { 86*45039663SJohn Forte DEVO_REV, /* devo_rev */ 87*45039663SJohn Forte 0, /* devo_refcnt */ 88*45039663SJohn Forte pppt_drv_getinfo, /* devo_getinfo */ 89*45039663SJohn Forte nulldev, /* devo_identify */ 90*45039663SJohn Forte nulldev, /* devo_probe */ 91*45039663SJohn Forte pppt_drv_attach, /* devo_attach */ 92*45039663SJohn Forte pppt_drv_detach, /* devo_detach */ 93*45039663SJohn Forte nodev, /* devo_reset */ 94*45039663SJohn Forte &pppt_cb_ops, /* devo_cb_ops */ 95*45039663SJohn Forte NULL, /* devo_bus_ops */ 96*45039663SJohn Forte NULL, /* devo_power */ 97*45039663SJohn Forte ddi_quiesce_not_needed, /* quiesce */ 98*45039663SJohn Forte }; 99*45039663SJohn Forte 100*45039663SJohn Forte static struct modldrv modldrv = { 101*45039663SJohn Forte &mod_driverops, 102*45039663SJohn Forte "Proxy Port Provider", 103*45039663SJohn Forte &pppt_dev_ops, 104*45039663SJohn Forte }; 105*45039663SJohn Forte 106*45039663SJohn Forte static struct modlinkage modlinkage = { 107*45039663SJohn Forte MODREV_1, 108*45039663SJohn Forte &modldrv, 109*45039663SJohn Forte NULL, 110*45039663SJohn Forte }; 111*45039663SJohn Forte 112*45039663SJohn Forte pppt_global_t pppt_global; 113*45039663SJohn Forte 114*45039663SJohn Forte int pppt_logging = 0; 115*45039663SJohn Forte 116*45039663SJohn Forte static int pppt_enable_svc(void); 117*45039663SJohn Forte 118*45039663SJohn Forte static void pppt_disable_svc(void); 119*45039663SJohn Forte 120*45039663SJohn Forte static int pppt_task_avl_compare(const void *tgt1, const void *tgt2); 121*45039663SJohn Forte 122*45039663SJohn Forte static stmf_data_buf_t *pppt_dbuf_alloc(scsi_task_t *task, 123*45039663SJohn Forte uint32_t size, uint32_t *pminsize, uint32_t flags); 124*45039663SJohn Forte 125*45039663SJohn Forte static void pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf); 126*45039663SJohn Forte 127*45039663SJohn Forte static void pppt_sess_destroy_task(void *ps_void); 128*45039663SJohn Forte 129*45039663SJohn Forte static void pppt_task_sent_status(pppt_task_t *ptask); 130*45039663SJohn Forte 131*45039663SJohn Forte static pppt_status_t pppt_task_try_abort(pppt_task_t *ptask); 132*45039663SJohn Forte 133*45039663SJohn Forte static pppt_status_t pppt_task_hold(pppt_task_t *ptask); 134*45039663SJohn Forte 135*45039663SJohn Forte static void pppt_task_rele(pppt_task_t *ptask); 136*45039663SJohn Forte 137*45039663SJohn Forte static void pppt_task_update_state(pppt_task_t *ptask, 138*45039663SJohn Forte pppt_task_state_t new_state); 139*45039663SJohn Forte 140*45039663SJohn Forte /* 141*45039663SJohn Forte * Lock order: global --> target --> session --> task 142*45039663SJohn Forte */ 143*45039663SJohn Forte 144*45039663SJohn Forte int 145*45039663SJohn Forte _init(void) 146*45039663SJohn Forte { 147*45039663SJohn Forte int rc; 148*45039663SJohn Forte 149*45039663SJohn Forte mutex_init(&pppt_global.global_lock, NULL, MUTEX_DEFAULT, NULL); 150*45039663SJohn Forte mutex_init(&pppt_global.global_door_lock, NULL, MUTEX_DEFAULT, NULL); 151*45039663SJohn Forte pppt_global.global_svc_state = PSS_DETACHED; 152*45039663SJohn Forte 153*45039663SJohn Forte if ((rc = mod_install(&modlinkage)) != 0) { 154*45039663SJohn Forte mutex_destroy(&pppt_global.global_door_lock); 155*45039663SJohn Forte mutex_destroy(&pppt_global.global_lock); 156*45039663SJohn Forte return (rc); 157*45039663SJohn Forte } 158*45039663SJohn Forte 159*45039663SJohn Forte return (rc); 160*45039663SJohn Forte } 161*45039663SJohn Forte 162*45039663SJohn Forte int 163*45039663SJohn Forte _info(struct modinfo *modinfop) 164*45039663SJohn Forte { 165*45039663SJohn Forte return (mod_info(&modlinkage, modinfop)); 166*45039663SJohn Forte } 167*45039663SJohn Forte 168*45039663SJohn Forte int 169*45039663SJohn Forte _fini(void) 170*45039663SJohn Forte { 171*45039663SJohn Forte int rc; 172*45039663SJohn Forte 173*45039663SJohn Forte rc = mod_remove(&modlinkage); 174*45039663SJohn Forte 175*45039663SJohn Forte if (rc == 0) { 176*45039663SJohn Forte mutex_destroy(&pppt_global.global_lock); 177*45039663SJohn Forte mutex_destroy(&pppt_global.global_door_lock); 178*45039663SJohn Forte } 179*45039663SJohn Forte 180*45039663SJohn Forte return (rc); 181*45039663SJohn Forte } 182*45039663SJohn Forte 183*45039663SJohn Forte /* 184*45039663SJohn Forte * DDI entry points. 185*45039663SJohn Forte */ 186*45039663SJohn Forte 187*45039663SJohn Forte /* ARGSUSED */ 188*45039663SJohn Forte static int 189*45039663SJohn Forte pppt_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 190*45039663SJohn Forte void **result) 191*45039663SJohn Forte { 192*45039663SJohn Forte ulong_t instance = getminor((dev_t)arg); 193*45039663SJohn Forte 194*45039663SJohn Forte switch (cmd) { 195*45039663SJohn Forte case DDI_INFO_DEVT2DEVINFO: 196*45039663SJohn Forte *result = pppt_global.global_dip; 197*45039663SJohn Forte return (DDI_SUCCESS); 198*45039663SJohn Forte 199*45039663SJohn Forte case DDI_INFO_DEVT2INSTANCE: 200*45039663SJohn Forte *result = (void *)instance; 201*45039663SJohn Forte return (DDI_SUCCESS); 202*45039663SJohn Forte 203*45039663SJohn Forte default: 204*45039663SJohn Forte break; 205*45039663SJohn Forte } 206*45039663SJohn Forte 207*45039663SJohn Forte return (DDI_FAILURE); 208*45039663SJohn Forte } 209*45039663SJohn Forte 210*45039663SJohn Forte static int 211*45039663SJohn Forte pppt_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 212*45039663SJohn Forte { 213*45039663SJohn Forte if (cmd != DDI_ATTACH) { 214*45039663SJohn Forte return (DDI_FAILURE); 215*45039663SJohn Forte } 216*45039663SJohn Forte 217*45039663SJohn Forte if (ddi_get_instance(dip) != 0) { 218*45039663SJohn Forte /* we only allow instance 0 to attach */ 219*45039663SJohn Forte return (DDI_FAILURE); 220*45039663SJohn Forte } 221*45039663SJohn Forte 222*45039663SJohn Forte /* create the minor node */ 223*45039663SJohn Forte if (ddi_create_minor_node(dip, PPPT_MODNAME, S_IFCHR, 0, 224*45039663SJohn Forte DDI_PSEUDO, 0) != DDI_SUCCESS) { 225*45039663SJohn Forte cmn_err(CE_WARN, "pppt_drv_attach: " 226*45039663SJohn Forte "failed creating minor node"); 227*45039663SJohn Forte return (DDI_FAILURE); 228*45039663SJohn Forte } 229*45039663SJohn Forte 230*45039663SJohn Forte pppt_global.global_svc_state = PSS_DISABLED; 231*45039663SJohn Forte pppt_global.global_dip = dip; 232*45039663SJohn Forte 233*45039663SJohn Forte return (DDI_SUCCESS); 234*45039663SJohn Forte } 235*45039663SJohn Forte 236*45039663SJohn Forte /*ARGSUSED*/ 237*45039663SJohn Forte static int 238*45039663SJohn Forte pppt_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 239*45039663SJohn Forte { 240*45039663SJohn Forte if (cmd != DDI_DETACH) 241*45039663SJohn Forte return (DDI_FAILURE); 242*45039663SJohn Forte 243*45039663SJohn Forte PPPT_GLOBAL_LOCK(); 244*45039663SJohn Forte if (pppt_drv_busy()) { 245*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 246*45039663SJohn Forte return (EBUSY); 247*45039663SJohn Forte } 248*45039663SJohn Forte 249*45039663SJohn Forte ddi_remove_minor_node(dip, NULL); 250*45039663SJohn Forte ddi_prop_remove_all(dip); 251*45039663SJohn Forte 252*45039663SJohn Forte pppt_global.global_svc_state = PSS_DETACHED; 253*45039663SJohn Forte 254*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 255*45039663SJohn Forte 256*45039663SJohn Forte return (DDI_SUCCESS); 257*45039663SJohn Forte } 258*45039663SJohn Forte 259*45039663SJohn Forte /*ARGSUSED*/ 260*45039663SJohn Forte static int 261*45039663SJohn Forte pppt_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp) 262*45039663SJohn Forte { 263*45039663SJohn Forte int rc = 0; 264*45039663SJohn Forte 265*45039663SJohn Forte PPPT_GLOBAL_LOCK(); 266*45039663SJohn Forte 267*45039663SJohn Forte switch (pppt_global.global_svc_state) { 268*45039663SJohn Forte case PSS_DISABLED: 269*45039663SJohn Forte pppt_global.global_svc_state = PSS_ENABLING; 270*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 271*45039663SJohn Forte rc = pppt_enable_svc(); 272*45039663SJohn Forte PPPT_GLOBAL_LOCK(); 273*45039663SJohn Forte if (rc == 0) { 274*45039663SJohn Forte pppt_global.global_svc_state = PSS_ENABLED; 275*45039663SJohn Forte } else { 276*45039663SJohn Forte pppt_global.global_svc_state = PSS_DISABLED; 277*45039663SJohn Forte } 278*45039663SJohn Forte break; 279*45039663SJohn Forte case PSS_DISABLING: 280*45039663SJohn Forte case PSS_ENABLING: 281*45039663SJohn Forte case PSS_ENABLED: 282*45039663SJohn Forte rc = EBUSY; 283*45039663SJohn Forte break; 284*45039663SJohn Forte default: 285*45039663SJohn Forte rc = EFAULT; 286*45039663SJohn Forte break; 287*45039663SJohn Forte } 288*45039663SJohn Forte 289*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 290*45039663SJohn Forte 291*45039663SJohn Forte return (rc); 292*45039663SJohn Forte } 293*45039663SJohn Forte 294*45039663SJohn Forte /* ARGSUSED */ 295*45039663SJohn Forte static int 296*45039663SJohn Forte pppt_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 297*45039663SJohn Forte { 298*45039663SJohn Forte int rc = 0; 299*45039663SJohn Forte 300*45039663SJohn Forte PPPT_GLOBAL_LOCK(); 301*45039663SJohn Forte 302*45039663SJohn Forte switch (pppt_global.global_svc_state) { 303*45039663SJohn Forte case PSS_ENABLED: 304*45039663SJohn Forte pppt_global.global_svc_state = PSS_DISABLING; 305*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 306*45039663SJohn Forte pppt_disable_svc(); 307*45039663SJohn Forte PPPT_GLOBAL_LOCK(); 308*45039663SJohn Forte pppt_global.global_svc_state = PSS_DISABLED; 309*45039663SJohn Forte /* 310*45039663SJohn Forte * release the door to the daemon 311*45039663SJohn Forte */ 312*45039663SJohn Forte mutex_enter(&pppt_global.global_door_lock); 313*45039663SJohn Forte if (pppt_global.global_door != NULL) { 314*45039663SJohn Forte door_ki_rele(pppt_global.global_door); 315*45039663SJohn Forte pppt_global.global_door = NULL; 316*45039663SJohn Forte } 317*45039663SJohn Forte mutex_exit(&pppt_global.global_door_lock); 318*45039663SJohn Forte break; 319*45039663SJohn Forte default: 320*45039663SJohn Forte rc = EFAULT; 321*45039663SJohn Forte break; 322*45039663SJohn Forte } 323*45039663SJohn Forte 324*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 325*45039663SJohn Forte 326*45039663SJohn Forte return (rc); 327*45039663SJohn Forte } 328*45039663SJohn Forte 329*45039663SJohn Forte static boolean_t 330*45039663SJohn Forte pppt_drv_busy(void) 331*45039663SJohn Forte { 332*45039663SJohn Forte switch (pppt_global.global_svc_state) { 333*45039663SJohn Forte case PSS_DISABLED: 334*45039663SJohn Forte case PSS_DETACHED: 335*45039663SJohn Forte return (B_FALSE); 336*45039663SJohn Forte default: 337*45039663SJohn Forte return (B_TRUE); 338*45039663SJohn Forte } 339*45039663SJohn Forte /* NOTREACHED */ 340*45039663SJohn Forte } 341*45039663SJohn Forte 342*45039663SJohn Forte /* ARGSUSED */ 343*45039663SJohn Forte static int 344*45039663SJohn Forte pppt_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred, 345*45039663SJohn Forte int *retval) 346*45039663SJohn Forte { 347*45039663SJohn Forte int rc; 348*45039663SJohn Forte void *buf; 349*45039663SJohn Forte size_t buf_size; 350*45039663SJohn Forte pppt_iocdata_t iocd; 351*45039663SJohn Forte door_handle_t new_handle; 352*45039663SJohn Forte 353*45039663SJohn Forte if (drv_priv(cred) != 0) { 354*45039663SJohn Forte return (EPERM); 355*45039663SJohn Forte } 356*45039663SJohn Forte 357*45039663SJohn Forte rc = ddi_copyin((void *)argp, &iocd, sizeof (iocd), flag); 358*45039663SJohn Forte if (rc) 359*45039663SJohn Forte return (EFAULT); 360*45039663SJohn Forte 361*45039663SJohn Forte if (iocd.pppt_version != PPPT_VERSION_1) 362*45039663SJohn Forte return (EINVAL); 363*45039663SJohn Forte 364*45039663SJohn Forte switch (cmd) { 365*45039663SJohn Forte case PPPT_MESSAGE: 366*45039663SJohn Forte 367*45039663SJohn Forte /* XXX limit buf_size ? */ 368*45039663SJohn Forte buf_size = (size_t)iocd.pppt_buf_size; 369*45039663SJohn Forte buf = kmem_alloc(buf_size, KM_SLEEP); 370*45039663SJohn Forte if (buf == NULL) 371*45039663SJohn Forte return (ENOMEM); 372*45039663SJohn Forte 373*45039663SJohn Forte rc = ddi_copyin((void *)(unsigned long)iocd.pppt_buf, 374*45039663SJohn Forte buf, buf_size, flag); 375*45039663SJohn Forte if (rc) { 376*45039663SJohn Forte kmem_free(buf, buf_size); 377*45039663SJohn Forte return (EFAULT); 378*45039663SJohn Forte } 379*45039663SJohn Forte 380*45039663SJohn Forte stmf_ic_rx_msg(buf, buf_size); 381*45039663SJohn Forte 382*45039663SJohn Forte kmem_free(buf, buf_size); 383*45039663SJohn Forte break; 384*45039663SJohn Forte case PPPT_INSTALL_DOOR: 385*45039663SJohn Forte 386*45039663SJohn Forte cmn_err(CE_NOTE, "RECEIVE DOOR HANDLE"); 387*45039663SJohn Forte 388*45039663SJohn Forte new_handle = door_ki_lookup((int)iocd.pppt_door_fd); 389*45039663SJohn Forte if (new_handle == NULL) 390*45039663SJohn Forte return (EINVAL); 391*45039663SJohn Forte 392*45039663SJohn Forte mutex_enter(&pppt_global.global_door_lock); 393*45039663SJohn Forte ASSERT(pppt_global.global_svc_state == PSS_ENABLED); 394*45039663SJohn Forte if (pppt_global.global_door != NULL) { 395*45039663SJohn Forte /* 396*45039663SJohn Forte * There can only be one door installed 397*45039663SJohn Forte */ 398*45039663SJohn Forte mutex_exit(&pppt_global.global_door_lock); 399*45039663SJohn Forte door_ki_rele(new_handle); 400*45039663SJohn Forte return (EBUSY); 401*45039663SJohn Forte } 402*45039663SJohn Forte pppt_global.global_door = new_handle; 403*45039663SJohn Forte mutex_exit(&pppt_global.global_door_lock); 404*45039663SJohn Forte break; 405*45039663SJohn Forte } 406*45039663SJohn Forte 407*45039663SJohn Forte return (rc); 408*45039663SJohn Forte } 409*45039663SJohn Forte 410*45039663SJohn Forte /* 411*45039663SJohn Forte * pppt_enable_svc 412*45039663SJohn Forte * 413*45039663SJohn Forte * registers all the configured targets and target portals with STMF 414*45039663SJohn Forte */ 415*45039663SJohn Forte static int 416*45039663SJohn Forte pppt_enable_svc(void) 417*45039663SJohn Forte { 418*45039663SJohn Forte stmf_port_provider_t *pp; 419*45039663SJohn Forte stmf_dbuf_store_t *dbuf_store; 420*45039663SJohn Forte int rc = 0; 421*45039663SJohn Forte 422*45039663SJohn Forte ASSERT(pppt_global.global_svc_state == PSS_ENABLING); 423*45039663SJohn Forte 424*45039663SJohn Forte /* 425*45039663SJohn Forte * Make sure that can tell if we have partially allocated 426*45039663SJohn Forte * in case we need to exit and tear down anything allocated. 427*45039663SJohn Forte */ 428*45039663SJohn Forte pppt_global.global_dbuf_store = NULL; 429*45039663SJohn Forte pp = NULL; 430*45039663SJohn Forte pppt_global.global_pp = NULL; 431*45039663SJohn Forte pppt_global.global_dispatch_taskq = NULL; 432*45039663SJohn Forte pppt_global.global_sess_taskq = NULL; 433*45039663SJohn Forte 434*45039663SJohn Forte avl_create(&pppt_global.global_target_list, 435*45039663SJohn Forte pppt_tgt_avl_compare, sizeof (pppt_tgt_t), 436*45039663SJohn Forte offsetof(pppt_tgt_t, target_global_ln)); 437*45039663SJohn Forte 438*45039663SJohn Forte avl_create(&pppt_global.global_sess_list, 439*45039663SJohn Forte pppt_sess_avl_compare_by_id, sizeof (pppt_sess_t), 440*45039663SJohn Forte offsetof(pppt_sess_t, ps_global_ln)); 441*45039663SJohn Forte 442*45039663SJohn Forte /* 443*45039663SJohn Forte * Setup STMF dbuf store. Tf buffers are associated with a particular 444*45039663SJohn Forte * lport (FC, SRP) then the dbuf_store should stored in the lport 445*45039663SJohn Forte * context, otherwise (iSCSI) the dbuf_store should be global. 446*45039663SJohn Forte */ 447*45039663SJohn Forte dbuf_store = stmf_alloc(STMF_STRUCT_DBUF_STORE, 0, 0); 448*45039663SJohn Forte if (dbuf_store == NULL) { 449*45039663SJohn Forte rc = ENOMEM; 450*45039663SJohn Forte goto tear_down_and_return; 451*45039663SJohn Forte } 452*45039663SJohn Forte dbuf_store->ds_alloc_data_buf = pppt_dbuf_alloc; 453*45039663SJohn Forte dbuf_store->ds_free_data_buf = pppt_dbuf_free; 454*45039663SJohn Forte dbuf_store->ds_port_private = NULL; 455*45039663SJohn Forte pppt_global.global_dbuf_store = dbuf_store; 456*45039663SJohn Forte 457*45039663SJohn Forte /* Register port provider */ 458*45039663SJohn Forte pp = stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0); 459*45039663SJohn Forte if (pp == NULL) { 460*45039663SJohn Forte rc = ENOMEM; 461*45039663SJohn Forte goto tear_down_and_return; 462*45039663SJohn Forte } 463*45039663SJohn Forte 464*45039663SJohn Forte pp->pp_portif_rev = PORTIF_REV_1; 465*45039663SJohn Forte pp->pp_instance = 0; 466*45039663SJohn Forte pp->pp_name = PPPT_MODNAME; 467*45039663SJohn Forte pp->pp_cb = NULL; 468*45039663SJohn Forte 469*45039663SJohn Forte pppt_global.global_pp = pp; 470*45039663SJohn Forte 471*45039663SJohn Forte if (stmf_register_port_provider(pp) != STMF_SUCCESS) { 472*45039663SJohn Forte rc = EIO; 473*45039663SJohn Forte goto tear_down_and_return; 474*45039663SJohn Forte } 475*45039663SJohn Forte 476*45039663SJohn Forte pppt_global.global_dispatch_taskq = taskq_create("pppt_dispatch", 477*45039663SJohn Forte 1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE); 478*45039663SJohn Forte 479*45039663SJohn Forte pppt_global.global_sess_taskq = taskq_create("pppt_session", 480*45039663SJohn Forte 1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE); 481*45039663SJohn Forte 482*45039663SJohn Forte return (0); 483*45039663SJohn Forte 484*45039663SJohn Forte tear_down_and_return: 485*45039663SJohn Forte 486*45039663SJohn Forte if (pppt_global.global_sess_taskq) { 487*45039663SJohn Forte taskq_destroy(pppt_global.global_sess_taskq); 488*45039663SJohn Forte pppt_global.global_sess_taskq = NULL; 489*45039663SJohn Forte } 490*45039663SJohn Forte 491*45039663SJohn Forte if (pppt_global.global_dispatch_taskq) { 492*45039663SJohn Forte taskq_destroy(pppt_global.global_dispatch_taskq); 493*45039663SJohn Forte pppt_global.global_dispatch_taskq = NULL; 494*45039663SJohn Forte } 495*45039663SJohn Forte 496*45039663SJohn Forte if (pppt_global.global_pp) 497*45039663SJohn Forte pppt_global.global_pp = NULL; 498*45039663SJohn Forte 499*45039663SJohn Forte if (pp) 500*45039663SJohn Forte stmf_free(pp); 501*45039663SJohn Forte 502*45039663SJohn Forte if (pppt_global.global_dbuf_store) { 503*45039663SJohn Forte stmf_free(pppt_global.global_dbuf_store); 504*45039663SJohn Forte pppt_global.global_dbuf_store = NULL; 505*45039663SJohn Forte } 506*45039663SJohn Forte 507*45039663SJohn Forte avl_destroy(&pppt_global.global_sess_list); 508*45039663SJohn Forte avl_destroy(&pppt_global.global_target_list); 509*45039663SJohn Forte 510*45039663SJohn Forte return (rc); 511*45039663SJohn Forte } 512*45039663SJohn Forte 513*45039663SJohn Forte /* 514*45039663SJohn Forte * pppt_disable_svc 515*45039663SJohn Forte * 516*45039663SJohn Forte * clean up all existing sessions and deregister targets from STMF 517*45039663SJohn Forte */ 518*45039663SJohn Forte static void 519*45039663SJohn Forte pppt_disable_svc(void) 520*45039663SJohn Forte { 521*45039663SJohn Forte pppt_tgt_t *tgt, *next_tgt; 522*45039663SJohn Forte avl_tree_t delete_target_list; 523*45039663SJohn Forte 524*45039663SJohn Forte ASSERT(pppt_global.global_svc_state == PSS_DISABLING); 525*45039663SJohn Forte 526*45039663SJohn Forte avl_create(&delete_target_list, 527*45039663SJohn Forte pppt_tgt_avl_compare, sizeof (pppt_tgt_t), 528*45039663SJohn Forte offsetof(pppt_tgt_t, target_global_ln)); 529*45039663SJohn Forte 530*45039663SJohn Forte PPPT_GLOBAL_LOCK(); 531*45039663SJohn Forte for (tgt = avl_first(&pppt_global.global_target_list); 532*45039663SJohn Forte tgt != NULL; 533*45039663SJohn Forte tgt = next_tgt) { 534*45039663SJohn Forte next_tgt = AVL_NEXT(&pppt_global.global_target_list, tgt); 535*45039663SJohn Forte avl_remove(&pppt_global.global_target_list, tgt); 536*45039663SJohn Forte avl_add(&delete_target_list, tgt); 537*45039663SJohn Forte pppt_tgt_async_delete(tgt); 538*45039663SJohn Forte } 539*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 540*45039663SJohn Forte 541*45039663SJohn Forte for (tgt = avl_first(&delete_target_list); 542*45039663SJohn Forte tgt != NULL; 543*45039663SJohn Forte tgt = next_tgt) { 544*45039663SJohn Forte next_tgt = AVL_NEXT(&delete_target_list, tgt); 545*45039663SJohn Forte mutex_enter(&tgt->target_mutex); 546*45039663SJohn Forte while ((tgt->target_refcount > 0) || 547*45039663SJohn Forte (tgt->target_state != TS_DELETING)) { 548*45039663SJohn Forte cv_wait(&tgt->target_cv, &tgt->target_mutex); 549*45039663SJohn Forte } 550*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 551*45039663SJohn Forte 552*45039663SJohn Forte avl_remove(&delete_target_list, tgt); 553*45039663SJohn Forte pppt_tgt_destroy(tgt); 554*45039663SJohn Forte } 555*45039663SJohn Forte 556*45039663SJohn Forte taskq_destroy(pppt_global.global_sess_taskq); 557*45039663SJohn Forte 558*45039663SJohn Forte taskq_destroy(pppt_global.global_dispatch_taskq); 559*45039663SJohn Forte 560*45039663SJohn Forte avl_destroy(&pppt_global.global_sess_list); 561*45039663SJohn Forte avl_destroy(&pppt_global.global_target_list); 562*45039663SJohn Forte 563*45039663SJohn Forte (void) stmf_deregister_port_provider(pppt_global.global_pp); 564*45039663SJohn Forte 565*45039663SJohn Forte stmf_free(pppt_global.global_dbuf_store); 566*45039663SJohn Forte pppt_global.global_dbuf_store = NULL; 567*45039663SJohn Forte 568*45039663SJohn Forte stmf_free(pppt_global.global_pp); 569*45039663SJohn Forte pppt_global.global_pp = NULL; 570*45039663SJohn Forte } 571*45039663SJohn Forte 572*45039663SJohn Forte /* 573*45039663SJohn Forte * STMF callbacks 574*45039663SJohn Forte */ 575*45039663SJohn Forte 576*45039663SJohn Forte /*ARGSUSED*/ 577*45039663SJohn Forte static stmf_data_buf_t * 578*45039663SJohn Forte pppt_dbuf_alloc(scsi_task_t *task, uint32_t size, uint32_t *pminsize, 579*45039663SJohn Forte uint32_t flags) 580*45039663SJohn Forte { 581*45039663SJohn Forte stmf_data_buf_t *result; 582*45039663SJohn Forte pppt_buf_t *pbuf; 583*45039663SJohn Forte uint8_t *buf; 584*45039663SJohn Forte 585*45039663SJohn Forte /* Get buffer */ 586*45039663SJohn Forte buf = kmem_alloc(size, KM_SLEEP); 587*45039663SJohn Forte 588*45039663SJohn Forte /* 589*45039663SJohn Forte * Allocate stmf buf with private port provider section 590*45039663SJohn Forte * (pppt_buf_t) 591*45039663SJohn Forte */ 592*45039663SJohn Forte result = stmf_alloc(STMF_STRUCT_DATA_BUF, sizeof (pppt_buf_t), 0); 593*45039663SJohn Forte if (result != NULL) { 594*45039663SJohn Forte /* Fill in pppt_buf_t */ 595*45039663SJohn Forte pbuf = result->db_port_private; 596*45039663SJohn Forte pbuf->pbuf_stmf_buf = result; 597*45039663SJohn Forte pbuf->pbuf_is_immed = B_FALSE; 598*45039663SJohn Forte 599*45039663SJohn Forte /* 600*45039663SJohn Forte * Fill in stmf_data_buf_t. DB_DONT CACHE tells 601*45039663SJohn Forte * stmf not to cache buffers but STMF doesn't do 602*45039663SJohn Forte * that yet so it's a no-op. Port providers like 603*45039663SJohn Forte * FC and SRP that have buffers associated with the 604*45039663SJohn Forte * target port would want to let STMF cache 605*45039663SJohn Forte * the buffers. Port providers like iSCSI would 606*45039663SJohn Forte * not want STMF to cache because the buffers are 607*45039663SJohn Forte * really associated with a connection, not an 608*45039663SJohn Forte * STMF target port so there is no way for STMF 609*45039663SJohn Forte * to cache the buffers effectively. These port 610*45039663SJohn Forte * providers should cache buffers internally if 611*45039663SJohn Forte * there is significant buffer setup overhead. 612*45039663SJohn Forte * 613*45039663SJohn Forte * And of course, since STMF doesn't do any internal 614*45039663SJohn Forte * caching right now anyway, all port providers should 615*45039663SJohn Forte * do what they can to minimize buffer setup overhead. 616*45039663SJohn Forte */ 617*45039663SJohn Forte result->db_flags = DB_DONT_CACHE; 618*45039663SJohn Forte result->db_buf_size = size; 619*45039663SJohn Forte result->db_data_size = size; 620*45039663SJohn Forte result->db_sglist_length = 1; 621*45039663SJohn Forte result->db_sglist[0].seg_addr = buf; 622*45039663SJohn Forte result->db_sglist[0].seg_length = size; 623*45039663SJohn Forte return (result); 624*45039663SJohn Forte } else { 625*45039663SJohn Forte /* 626*45039663SJohn Forte * Couldn't get the stmf_data_buf_t so free the 627*45039663SJohn Forte * buffer 628*45039663SJohn Forte */ 629*45039663SJohn Forte kmem_free(buf, size); 630*45039663SJohn Forte } 631*45039663SJohn Forte 632*45039663SJohn Forte return (NULL); 633*45039663SJohn Forte } 634*45039663SJohn Forte 635*45039663SJohn Forte /*ARGSUSED*/ 636*45039663SJohn Forte static void 637*45039663SJohn Forte pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf) 638*45039663SJohn Forte { 639*45039663SJohn Forte pppt_buf_t *pbuf = dbuf->db_port_private; 640*45039663SJohn Forte 641*45039663SJohn Forte if (pbuf->pbuf_is_immed) { 642*45039663SJohn Forte stmf_ic_msg_free(pbuf->pbuf_immed_msg); 643*45039663SJohn Forte } else { 644*45039663SJohn Forte kmem_free(dbuf->db_sglist[0].seg_addr, 645*45039663SJohn Forte dbuf->db_sglist[0].seg_length); 646*45039663SJohn Forte stmf_free(dbuf); 647*45039663SJohn Forte } 648*45039663SJohn Forte } 649*45039663SJohn Forte 650*45039663SJohn Forte /*ARGSUSED*/ 651*45039663SJohn Forte stmf_status_t 652*45039663SJohn Forte pppt_lport_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, 653*45039663SJohn Forte uint32_t ioflags) 654*45039663SJohn Forte { 655*45039663SJohn Forte pppt_task_t *pppt_task = task->task_port_private; 656*45039663SJohn Forte pppt_buf_t *pbuf = dbuf->db_port_private; 657*45039663SJohn Forte stmf_ic_msg_t *msg; 658*45039663SJohn Forte stmf_ic_msg_status_t ic_msg_status; 659*45039663SJohn Forte 660*45039663SJohn Forte /* 661*45039663SJohn Forte * If we are aborting then we can ignore this request, otherwise 662*45039663SJohn Forte * add a reference. 663*45039663SJohn Forte */ 664*45039663SJohn Forte if (pppt_task_hold(pppt_task) != PPPT_STATUS_SUCCESS) { 665*45039663SJohn Forte return (STMF_SUCCESS); 666*45039663SJohn Forte } 667*45039663SJohn Forte 668*45039663SJohn Forte /* 669*45039663SJohn Forte * If it's not immediate data then start the transfer 670*45039663SJohn Forte */ 671*45039663SJohn Forte ASSERT(pbuf->pbuf_is_immed == B_FALSE); 672*45039663SJohn Forte if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) { 673*45039663SJohn Forte 674*45039663SJohn Forte /* Send read data */ 675*45039663SJohn Forte msg = stmf_ic_scsi_data_msg_alloc( 676*45039663SJohn Forte pppt_task->pt_task_id, 677*45039663SJohn Forte pppt_task->pt_sess->ps_session_id, 678*45039663SJohn Forte pppt_task->pt_lun_id, 679*45039663SJohn Forte dbuf->db_sglist[0].seg_length, 680*45039663SJohn Forte dbuf->db_sglist[0].seg_addr, 0); 681*45039663SJohn Forte 682*45039663SJohn Forte pppt_task->pt_read_buf = pbuf; 683*45039663SJohn Forte pppt_task->pt_read_xfer_msgid = msg->icm_msgid; 684*45039663SJohn Forte 685*45039663SJohn Forte ic_msg_status = stmf_ic_tx_msg(msg); 686*45039663SJohn Forte pppt_task_rele(pppt_task); 687*45039663SJohn Forte if (ic_msg_status != STMF_IC_MSG_SUCCESS) { 688*45039663SJohn Forte return (STMF_FAILURE); 689*45039663SJohn Forte } else { 690*45039663SJohn Forte return (STMF_SUCCESS); 691*45039663SJohn Forte } 692*45039663SJohn Forte } else if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) { 693*45039663SJohn Forte pppt_task_rele(pppt_task); 694*45039663SJohn Forte return (STMF_FAILURE); 695*45039663SJohn Forte } 696*45039663SJohn Forte 697*45039663SJohn Forte pppt_task_rele(pppt_task); 698*45039663SJohn Forte 699*45039663SJohn Forte return (STMF_INVALID_ARG); 700*45039663SJohn Forte } 701*45039663SJohn Forte 702*45039663SJohn Forte void 703*45039663SJohn Forte pppt_xfer_read_complete(pppt_task_t *pppt_task, stmf_status_t status) 704*45039663SJohn Forte { 705*45039663SJohn Forte pppt_buf_t *pppt_buf; 706*45039663SJohn Forte stmf_data_buf_t *dbuf; 707*45039663SJohn Forte 708*45039663SJohn Forte /* 709*45039663SJohn Forte * Caller should have taken a task hold (likely via pppt_task_lookup) 710*45039663SJohn Forte * 711*45039663SJohn Forte * Get pppt_buf_t and stmf_data_buf_t pointers 712*45039663SJohn Forte */ 713*45039663SJohn Forte pppt_buf = pppt_task->pt_read_buf; 714*45039663SJohn Forte dbuf = pppt_buf->pbuf_stmf_buf; 715*45039663SJohn Forte dbuf->db_xfer_status = (status == STMF_SUCCESS) ? 716*45039663SJohn Forte STMF_SUCCESS : STMF_FAILURE; 717*45039663SJohn Forte 718*45039663SJohn Forte /* 719*45039663SJohn Forte * COMSTAR currently requires port providers to support 720*45039663SJohn Forte * the DB_SEND_STATUS_GOOD flag even if phase collapse is 721*45039663SJohn Forte * not supported. So we will roll our own... pretend we are 722*45039663SJohn Forte * COMSTAR and ask for a status message. 723*45039663SJohn Forte */ 724*45039663SJohn Forte if ((dbuf->db_flags & DB_SEND_STATUS_GOOD) && 725*45039663SJohn Forte (status == STMF_SUCCESS)) { 726*45039663SJohn Forte /* 727*45039663SJohn Forte * It's possible the task has been aborted since the time we 728*45039663SJohn Forte * looked it up. We need to release the hold before calling 729*45039663SJohn Forte * pppt_lport_send_status and as soon as we release the hold 730*45039663SJohn Forte * the task may disappear. Calling pppt_task_done allows us 731*45039663SJohn Forte * to determine whether the task has been aborted (in which 732*45039663SJohn Forte * case we will stop processing and return) and mark the task 733*45039663SJohn Forte * "done" which will prevent the task from being aborted while 734*45039663SJohn Forte * we are trying to send the status. 735*45039663SJohn Forte */ 736*45039663SJohn Forte if (pppt_task_done(pppt_task) != PPPT_STATUS_SUCCESS) { 737*45039663SJohn Forte /* STMF will free task and buffer(s) */ 738*45039663SJohn Forte pppt_task_rele(pppt_task); 739*45039663SJohn Forte return; 740*45039663SJohn Forte } 741*45039663SJohn Forte pppt_task_rele(pppt_task); 742*45039663SJohn Forte 743*45039663SJohn Forte if (pppt_lport_send_status(pppt_task->pt_stmf_task, 0) 744*45039663SJohn Forte != STMF_SUCCESS) { 745*45039663SJohn Forte /* Failed to send status */ 746*45039663SJohn Forte dbuf->db_xfer_status = STMF_FAILURE; 747*45039663SJohn Forte stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf, 748*45039663SJohn Forte STMF_IOF_LPORT_DONE); 749*45039663SJohn Forte } 750*45039663SJohn Forte } else { 751*45039663SJohn Forte pppt_task_rele(pppt_task); 752*45039663SJohn Forte stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf, 0); 753*45039663SJohn Forte } 754*45039663SJohn Forte } 755*45039663SJohn Forte 756*45039663SJohn Forte /*ARGSUSED*/ 757*45039663SJohn Forte stmf_status_t 758*45039663SJohn Forte pppt_lport_send_status(scsi_task_t *task, uint32_t ioflags) 759*45039663SJohn Forte { 760*45039663SJohn Forte pppt_task_t *ptask = task->task_port_private; 761*45039663SJohn Forte stmf_ic_msg_t *msg; 762*45039663SJohn Forte stmf_ic_msg_status_t ic_msg_status; 763*45039663SJohn Forte 764*45039663SJohn Forte /* 765*45039663SJohn Forte * Mark task completed. If the state indicates it was aborted 766*45039663SJohn Forte * then we don't need to respond. 767*45039663SJohn Forte */ 768*45039663SJohn Forte if (pppt_task_done(ptask) == PPPT_STATUS_ABORTED) { 769*45039663SJohn Forte return (STMF_SUCCESS); 770*45039663SJohn Forte } 771*45039663SJohn Forte 772*45039663SJohn Forte /* 773*45039663SJohn Forte * Send status. 774*45039663SJohn Forte */ 775*45039663SJohn Forte msg = stmf_ic_scsi_status_msg_alloc( 776*45039663SJohn Forte ptask->pt_task_id, 777*45039663SJohn Forte ptask->pt_sess->ps_session_id, 778*45039663SJohn Forte ptask->pt_lun_id, 779*45039663SJohn Forte 0, 780*45039663SJohn Forte task->task_scsi_status, 781*45039663SJohn Forte task->task_status_ctrl, task->task_resid, 782*45039663SJohn Forte task->task_sense_length, task->task_sense_data, 0); 783*45039663SJohn Forte 784*45039663SJohn Forte ic_msg_status = stmf_ic_tx_msg(msg); 785*45039663SJohn Forte 786*45039663SJohn Forte if (ic_msg_status != STMF_IC_MSG_SUCCESS) { 787*45039663SJohn Forte pppt_task_sent_status(ptask); 788*45039663SJohn Forte stmf_send_status_done(ptask->pt_stmf_task, 789*45039663SJohn Forte STMF_FAILURE, STMF_IOF_LPORT_DONE); 790*45039663SJohn Forte return (STMF_FAILURE); 791*45039663SJohn Forte } else { 792*45039663SJohn Forte pppt_task_sent_status(ptask); 793*45039663SJohn Forte stmf_send_status_done(ptask->pt_stmf_task, 794*45039663SJohn Forte STMF_SUCCESS, STMF_IOF_LPORT_DONE); 795*45039663SJohn Forte return (STMF_SUCCESS); 796*45039663SJohn Forte } 797*45039663SJohn Forte } 798*45039663SJohn Forte 799*45039663SJohn Forte void 800*45039663SJohn Forte pppt_lport_task_free(scsi_task_t *task) 801*45039663SJohn Forte { 802*45039663SJohn Forte pppt_task_t *ptask = task->task_port_private; 803*45039663SJohn Forte pppt_sess_t *ps = ptask->pt_sess; 804*45039663SJohn Forte 805*45039663SJohn Forte pppt_task_free(ptask); 806*45039663SJohn Forte pppt_sess_rele(ps); 807*45039663SJohn Forte } 808*45039663SJohn Forte 809*45039663SJohn Forte /*ARGSUSED*/ 810*45039663SJohn Forte stmf_status_t 811*45039663SJohn Forte pppt_lport_abort(stmf_local_port_t *lport, int abort_cmd, void *arg, 812*45039663SJohn Forte uint32_t flags) 813*45039663SJohn Forte { 814*45039663SJohn Forte scsi_task_t *st = (scsi_task_t *)arg; 815*45039663SJohn Forte pppt_task_t *ptask; 816*45039663SJohn Forte 817*45039663SJohn Forte ptask = st->task_port_private; 818*45039663SJohn Forte 819*45039663SJohn Forte if (pppt_task_try_abort(ptask) == PPPT_STATUS_DONE) { 820*45039663SJohn Forte /* 821*45039663SJohn Forte * This task is beyond the point where abort makes sense 822*45039663SJohn Forte * and we will soon be sending status. Tell STMF to 823*45039663SJohn Forte * go away. 824*45039663SJohn Forte */ 825*45039663SJohn Forte return (STMF_BUSY); 826*45039663SJohn Forte } else { 827*45039663SJohn Forte return (STMF_ABORT_SUCCESS); 828*45039663SJohn Forte } 829*45039663SJohn Forte /*NOTREACHED*/ 830*45039663SJohn Forte } 831*45039663SJohn Forte 832*45039663SJohn Forte /*ARGSUSED*/ 833*45039663SJohn Forte void 834*45039663SJohn Forte pppt_lport_ctl(stmf_local_port_t *lport, int cmd, void *arg) 835*45039663SJohn Forte { 836*45039663SJohn Forte switch (cmd) { 837*45039663SJohn Forte case STMF_CMD_LPORT_ONLINE: 838*45039663SJohn Forte case STMF_CMD_LPORT_OFFLINE: 839*45039663SJohn Forte case STMF_ACK_LPORT_ONLINE_COMPLETE: 840*45039663SJohn Forte case STMF_ACK_LPORT_OFFLINE_COMPLETE: 841*45039663SJohn Forte pppt_tgt_sm_ctl(lport, cmd, arg); 842*45039663SJohn Forte break; 843*45039663SJohn Forte 844*45039663SJohn Forte default: 845*45039663SJohn Forte ASSERT(0); 846*45039663SJohn Forte break; 847*45039663SJohn Forte } 848*45039663SJohn Forte } 849*45039663SJohn Forte 850*45039663SJohn Forte pppt_sess_t * 851*45039663SJohn Forte pppt_sess_lookup_locked(uint64_t session_id, 852*45039663SJohn Forte scsi_devid_desc_t *lport_devid, 853*45039663SJohn Forte scsi_devid_desc_t *rport_devid) 854*45039663SJohn Forte { 855*45039663SJohn Forte pppt_tgt_t *tgt; 856*45039663SJohn Forte pppt_sess_t *ps; 857*45039663SJohn Forte int lport_cmp; 858*45039663SJohn Forte int rport_cmp; 859*45039663SJohn Forte 860*45039663SJohn Forte ASSERT(mutex_owned(&pppt_global.global_lock)); 861*45039663SJohn Forte 862*45039663SJohn Forte /* 863*45039663SJohn Forte * Look for existing session for this ID 864*45039663SJohn Forte */ 865*45039663SJohn Forte ps = pppt_sess_lookup_by_id_locked(session_id); 866*45039663SJohn Forte if (ps == NULL) { 867*45039663SJohn Forte PPPT_INC_STAT(es_sess_lookup_no_session); 868*45039663SJohn Forte return (NULL); 869*45039663SJohn Forte } 870*45039663SJohn Forte 871*45039663SJohn Forte tgt = ps->ps_target; 872*45039663SJohn Forte 873*45039663SJohn Forte mutex_enter(&tgt->target_mutex); 874*45039663SJohn Forte 875*45039663SJohn Forte /* Validate local/remote port names */ 876*45039663SJohn Forte if ((lport_devid->ident_length != 877*45039663SJohn Forte tgt->target_stmf_lport->lport_id->ident_length) || 878*45039663SJohn Forte (rport_devid->ident_length != 879*45039663SJohn Forte ps->ps_stmf_sess->ss_rport_id->ident_length)) { 880*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 881*45039663SJohn Forte PPPT_INC_STAT(es_sess_lookup_ident_mismatch); 882*45039663SJohn Forte return (NULL); 883*45039663SJohn Forte } else { 884*45039663SJohn Forte lport_cmp = bcmp(lport_devid->ident, 885*45039663SJohn Forte tgt->target_stmf_lport->lport_id->ident, 886*45039663SJohn Forte lport_devid->ident_length); 887*45039663SJohn Forte rport_cmp = bcmp(rport_devid->ident, 888*45039663SJohn Forte ps->ps_stmf_sess->ss_rport_id->ident, 889*45039663SJohn Forte rport_devid->ident_length); 890*45039663SJohn Forte if (lport_cmp || rport_cmp) { 891*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 892*45039663SJohn Forte PPPT_INC_STAT(es_sess_lookup_ident_mismatch); 893*45039663SJohn Forte return (NULL); 894*45039663SJohn Forte } 895*45039663SJohn Forte 896*45039663SJohn Forte if (tgt->target_state != TS_STMF_ONLINE) { 897*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 898*45039663SJohn Forte PPPT_INC_STAT(es_sess_lookup_bad_tgt_state); 899*45039663SJohn Forte return (NULL); 900*45039663SJohn Forte } 901*45039663SJohn Forte } 902*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 903*45039663SJohn Forte 904*45039663SJohn Forte return (ps); 905*45039663SJohn Forte } 906*45039663SJohn Forte 907*45039663SJohn Forte pppt_sess_t * 908*45039663SJohn Forte pppt_sess_lookup_by_id_locked(uint64_t session_id) 909*45039663SJohn Forte { 910*45039663SJohn Forte pppt_sess_t tmp_ps; 911*45039663SJohn Forte pppt_sess_t *ps; 912*45039663SJohn Forte 913*45039663SJohn Forte ASSERT(mutex_owned(&pppt_global.global_lock)); 914*45039663SJohn Forte tmp_ps.ps_session_id = session_id; 915*45039663SJohn Forte tmp_ps.ps_closed = 0; 916*45039663SJohn Forte ps = avl_find(&pppt_global.global_sess_list, &tmp_ps, NULL); 917*45039663SJohn Forte if (ps != NULL) { 918*45039663SJohn Forte mutex_enter(&ps->ps_mutex); 919*45039663SJohn Forte if (!ps->ps_closed) { 920*45039663SJohn Forte ps->ps_refcnt++; 921*45039663SJohn Forte mutex_exit(&ps->ps_mutex); 922*45039663SJohn Forte return (ps); 923*45039663SJohn Forte } 924*45039663SJohn Forte mutex_exit(&ps->ps_mutex); 925*45039663SJohn Forte } 926*45039663SJohn Forte 927*45039663SJohn Forte return (NULL); 928*45039663SJohn Forte } 929*45039663SJohn Forte 930*45039663SJohn Forte /* New session */ 931*45039663SJohn Forte pppt_sess_t * 932*45039663SJohn Forte pppt_sess_lookup_create(scsi_devid_desc_t *lport_devid, 933*45039663SJohn Forte scsi_devid_desc_t *rport_devid, uint64_t session_id, 934*45039663SJohn Forte stmf_status_t *statusp) 935*45039663SJohn Forte { 936*45039663SJohn Forte pppt_tgt_t *tgt; 937*45039663SJohn Forte pppt_sess_t *ps; 938*45039663SJohn Forte stmf_scsi_session_t *ss; 939*45039663SJohn Forte pppt_sess_t tmp_ps; 940*45039663SJohn Forte stmf_scsi_session_t tmp_ss; 941*45039663SJohn Forte *statusp = STMF_SUCCESS; 942*45039663SJohn Forte 943*45039663SJohn Forte PPPT_GLOBAL_LOCK(); 944*45039663SJohn Forte 945*45039663SJohn Forte /* 946*45039663SJohn Forte * Look for existing session for this ID 947*45039663SJohn Forte */ 948*45039663SJohn Forte ps = pppt_sess_lookup_locked(session_id, lport_devid, rport_devid); 949*45039663SJohn Forte 950*45039663SJohn Forte if (ps != NULL) { 951*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 952*45039663SJohn Forte return (ps); 953*45039663SJohn Forte } 954*45039663SJohn Forte 955*45039663SJohn Forte /* 956*45039663SJohn Forte * No session with that ID, look for another session corresponding 957*45039663SJohn Forte * to the same IT nexus. 958*45039663SJohn Forte */ 959*45039663SJohn Forte tgt = pppt_tgt_lookup_locked(lport_devid); 960*45039663SJohn Forte if (tgt == NULL) { 961*45039663SJohn Forte *statusp = STMF_NOT_FOUND; 962*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 963*45039663SJohn Forte return (NULL); 964*45039663SJohn Forte } 965*45039663SJohn Forte 966*45039663SJohn Forte mutex_enter(&tgt->target_mutex); 967*45039663SJohn Forte if (tgt->target_state != TS_STMF_ONLINE) { 968*45039663SJohn Forte *statusp = STMF_NOT_FOUND; 969*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 970*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 971*45039663SJohn Forte /* Can't create session to offline target */ 972*45039663SJohn Forte return (NULL); 973*45039663SJohn Forte } 974*45039663SJohn Forte 975*45039663SJohn Forte bzero(&tmp_ps, sizeof (tmp_ps)); 976*45039663SJohn Forte bzero(&tmp_ss, sizeof (tmp_ss)); 977*45039663SJohn Forte tmp_ps.ps_stmf_sess = &tmp_ss; 978*45039663SJohn Forte tmp_ss.ss_rport_id = rport_devid; 979*45039663SJohn Forte 980*45039663SJohn Forte /* 981*45039663SJohn Forte * Look for an existing session on this IT nexus 982*45039663SJohn Forte */ 983*45039663SJohn Forte ps = avl_find(&tgt->target_sess_list, &tmp_ps, NULL); 984*45039663SJohn Forte 985*45039663SJohn Forte if (ps != NULL) { 986*45039663SJohn Forte /* 987*45039663SJohn Forte * Now check the session ID. It should not match because if 988*45039663SJohn Forte * it did we would have found it on the global session list. 989*45039663SJohn Forte * If the session ID in the command is higher than the existing 990*45039663SJohn Forte * session ID then we need to tear down the existing session. 991*45039663SJohn Forte */ 992*45039663SJohn Forte mutex_enter(&ps->ps_mutex); 993*45039663SJohn Forte ASSERT(ps->ps_session_id != session_id); 994*45039663SJohn Forte if (ps->ps_session_id > session_id) { 995*45039663SJohn Forte /* Invalid session ID */ 996*45039663SJohn Forte mutex_exit(&ps->ps_mutex); 997*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 998*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 999*45039663SJohn Forte *statusp = STMF_INVALID_ARG; 1000*45039663SJohn Forte return (NULL); 1001*45039663SJohn Forte } else { 1002*45039663SJohn Forte /* Existing session needs to be invalidated */ 1003*45039663SJohn Forte if (!ps->ps_closed) { 1004*45039663SJohn Forte pppt_sess_close_locked(ps); 1005*45039663SJohn Forte } 1006*45039663SJohn Forte } 1007*45039663SJohn Forte mutex_exit(&ps->ps_mutex); 1008*45039663SJohn Forte 1009*45039663SJohn Forte /* Fallthrough and create new session */ 1010*45039663SJohn Forte } 1011*45039663SJohn Forte 1012*45039663SJohn Forte /* 1013*45039663SJohn Forte * Allocate and fill in pppt_session_t with the appropriate data 1014*45039663SJohn Forte * for the protocol. 1015*45039663SJohn Forte */ 1016*45039663SJohn Forte ps = kmem_zalloc(sizeof (*ps), KM_SLEEP); 1017*45039663SJohn Forte 1018*45039663SJohn Forte /* Fill in session fields */ 1019*45039663SJohn Forte ps->ps_target = tgt; 1020*45039663SJohn Forte ps->ps_session_id = session_id; 1021*45039663SJohn Forte 1022*45039663SJohn Forte ss = stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0, 1023*45039663SJohn Forte 0); 1024*45039663SJohn Forte if (ss == NULL) { 1025*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 1026*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 1027*45039663SJohn Forte kmem_free(ps, sizeof (*ps)); 1028*45039663SJohn Forte *statusp = STMF_ALLOC_FAILURE; 1029*45039663SJohn Forte return (NULL); 1030*45039663SJohn Forte } 1031*45039663SJohn Forte 1032*45039663SJohn Forte ss->ss_rport_id = kmem_zalloc(sizeof (scsi_devid_desc_t) + 1033*45039663SJohn Forte rport_devid->ident_length + 1, KM_SLEEP); 1034*45039663SJohn Forte bcopy(rport_devid, ss->ss_rport_id, 1035*45039663SJohn Forte sizeof (scsi_devid_desc_t) + rport_devid->ident_length + 1); 1036*45039663SJohn Forte 1037*45039663SJohn Forte ss->ss_lport = tgt->target_stmf_lport; 1038*45039663SJohn Forte 1039*45039663SJohn Forte if (stmf_register_scsi_session(tgt->target_stmf_lport, ss) != 1040*45039663SJohn Forte STMF_SUCCESS) { 1041*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 1042*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 1043*45039663SJohn Forte kmem_free(ss->ss_rport_id, 1044*45039663SJohn Forte sizeof (scsi_devid_desc_t) + 1045*45039663SJohn Forte rport_devid->ident_length + 1); 1046*45039663SJohn Forte stmf_free(ss); 1047*45039663SJohn Forte kmem_free(ps, sizeof (*ps)); 1048*45039663SJohn Forte *statusp = STMF_TARGET_FAILURE; 1049*45039663SJohn Forte return (NULL); 1050*45039663SJohn Forte } 1051*45039663SJohn Forte 1052*45039663SJohn Forte ss->ss_port_private = ps; 1053*45039663SJohn Forte mutex_init(&ps->ps_mutex, NULL, MUTEX_DEFAULT, NULL); 1054*45039663SJohn Forte cv_init(&ps->ps_cv, NULL, CV_DEFAULT, NULL); 1055*45039663SJohn Forte avl_create(&ps->ps_task_list, pppt_task_avl_compare, 1056*45039663SJohn Forte sizeof (pppt_task_t), offsetof(pppt_task_t, pt_sess_ln)); 1057*45039663SJohn Forte ps->ps_refcnt = 1; 1058*45039663SJohn Forte ps->ps_stmf_sess = ss; 1059*45039663SJohn Forte avl_add(&tgt->target_sess_list, ps); 1060*45039663SJohn Forte avl_add(&pppt_global.global_sess_list, ps); 1061*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 1062*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 1063*45039663SJohn Forte PPPT_LOG(CE_NOTE, "New session %p", (void *)ps); 1064*45039663SJohn Forte 1065*45039663SJohn Forte return (ps); 1066*45039663SJohn Forte } 1067*45039663SJohn Forte 1068*45039663SJohn Forte void 1069*45039663SJohn Forte pppt_sess_rele(pppt_sess_t *ps) 1070*45039663SJohn Forte { 1071*45039663SJohn Forte mutex_enter(&ps->ps_mutex); 1072*45039663SJohn Forte pppt_sess_rele_locked(ps); 1073*45039663SJohn Forte mutex_exit(&ps->ps_mutex); 1074*45039663SJohn Forte } 1075*45039663SJohn Forte 1076*45039663SJohn Forte void 1077*45039663SJohn Forte pppt_sess_rele_locked(pppt_sess_t *ps) 1078*45039663SJohn Forte { 1079*45039663SJohn Forte ASSERT(mutex_owned(&ps->ps_mutex)); 1080*45039663SJohn Forte ps->ps_refcnt--; 1081*45039663SJohn Forte if (ps->ps_refcnt == 0) { 1082*45039663SJohn Forte cv_signal(&ps->ps_cv); 1083*45039663SJohn Forte } 1084*45039663SJohn Forte } 1085*45039663SJohn Forte 1086*45039663SJohn Forte static void pppt_sess_destroy_task(void *ps_void) 1087*45039663SJohn Forte { 1088*45039663SJohn Forte pppt_sess_t *ps = ps_void; 1089*45039663SJohn Forte stmf_scsi_session_t *ss; 1090*45039663SJohn Forte 1091*45039663SJohn Forte PPPT_LOG(CE_NOTE, "Session destroy task %p", (void *)ps); 1092*45039663SJohn Forte 1093*45039663SJohn Forte ss = ps->ps_stmf_sess; 1094*45039663SJohn Forte mutex_enter(&ps->ps_mutex); 1095*45039663SJohn Forte stmf_deregister_scsi_session(ss->ss_lport, ss); 1096*45039663SJohn Forte kmem_free(ss->ss_rport_id, 1097*45039663SJohn Forte sizeof (scsi_devid_desc_t) + 1098*45039663SJohn Forte ss->ss_rport_id->ident_length + 1); 1099*45039663SJohn Forte avl_destroy(&ps->ps_task_list); 1100*45039663SJohn Forte mutex_exit(&ps->ps_mutex); 1101*45039663SJohn Forte cv_destroy(&ps->ps_cv); 1102*45039663SJohn Forte mutex_destroy(&ps->ps_mutex); 1103*45039663SJohn Forte stmf_free(ps->ps_stmf_sess); 1104*45039663SJohn Forte kmem_free(ps, sizeof (*ps)); 1105*45039663SJohn Forte 1106*45039663SJohn Forte PPPT_LOG(CE_NOTE, "Session destroy task complete %p", (void *)ps); 1107*45039663SJohn Forte } 1108*45039663SJohn Forte 1109*45039663SJohn Forte int 1110*45039663SJohn Forte pppt_sess_avl_compare_by_id(const void *void_sess1, const void *void_sess2) 1111*45039663SJohn Forte { 1112*45039663SJohn Forte const pppt_sess_t *psess1 = void_sess1; 1113*45039663SJohn Forte const pppt_sess_t *psess2 = void_sess2; 1114*45039663SJohn Forte 1115*45039663SJohn Forte if (psess1->ps_session_id < psess2->ps_session_id) 1116*45039663SJohn Forte return (-1); 1117*45039663SJohn Forte else if (psess1->ps_session_id > psess2->ps_session_id) 1118*45039663SJohn Forte return (1); 1119*45039663SJohn Forte 1120*45039663SJohn Forte /* Allow multiple duplicate sessions if one is closed */ 1121*45039663SJohn Forte ASSERT(!(psess1->ps_closed && psess2->ps_closed)); 1122*45039663SJohn Forte if (psess1->ps_closed) 1123*45039663SJohn Forte return (-1); 1124*45039663SJohn Forte else if (psess2->ps_closed) 1125*45039663SJohn Forte return (1); 1126*45039663SJohn Forte 1127*45039663SJohn Forte return (0); 1128*45039663SJohn Forte } 1129*45039663SJohn Forte 1130*45039663SJohn Forte int 1131*45039663SJohn Forte pppt_sess_avl_compare_by_name(const void *void_sess1, const void *void_sess2) 1132*45039663SJohn Forte { 1133*45039663SJohn Forte const pppt_sess_t *psess1 = void_sess1; 1134*45039663SJohn Forte const pppt_sess_t *psess2 = void_sess2; 1135*45039663SJohn Forte int result; 1136*45039663SJohn Forte 1137*45039663SJohn Forte /* Sort by code set then ident */ 1138*45039663SJohn Forte if (psess1->ps_stmf_sess->ss_rport_id->code_set < 1139*45039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->code_set) { 1140*45039663SJohn Forte return (-1); 1141*45039663SJohn Forte } else if (psess1->ps_stmf_sess->ss_rport_id->code_set > 1142*45039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->code_set) { 1143*45039663SJohn Forte return (1); 1144*45039663SJohn Forte } 1145*45039663SJohn Forte 1146*45039663SJohn Forte /* Next by ident length */ 1147*45039663SJohn Forte if (psess1->ps_stmf_sess->ss_rport_id->ident_length < 1148*45039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->ident_length) { 1149*45039663SJohn Forte return (-1); 1150*45039663SJohn Forte } else if (psess1->ps_stmf_sess->ss_rport_id->ident_length > 1151*45039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->ident_length) { 1152*45039663SJohn Forte return (1); 1153*45039663SJohn Forte } 1154*45039663SJohn Forte 1155*45039663SJohn Forte /* Code set and ident length both match, now compare idents */ 1156*45039663SJohn Forte result = memcmp(psess1->ps_stmf_sess->ss_rport_id->ident, 1157*45039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->ident, 1158*45039663SJohn Forte psess1->ps_stmf_sess->ss_rport_id->ident_length); 1159*45039663SJohn Forte 1160*45039663SJohn Forte if (result < 0) { 1161*45039663SJohn Forte return (-1); 1162*45039663SJohn Forte } else if (result > 0) { 1163*45039663SJohn Forte return (1); 1164*45039663SJohn Forte } 1165*45039663SJohn Forte 1166*45039663SJohn Forte return (0); 1167*45039663SJohn Forte } 1168*45039663SJohn Forte 1169*45039663SJohn Forte void 1170*45039663SJohn Forte pppt_sess_close_locked(pppt_sess_t *ps) 1171*45039663SJohn Forte { 1172*45039663SJohn Forte pppt_tgt_t *tgt = ps->ps_target; 1173*45039663SJohn Forte pppt_task_t *ptask; 1174*45039663SJohn Forte 1175*45039663SJohn Forte PPPT_LOG(CE_NOTE, "Session close %p", (void *)ps); 1176*45039663SJohn Forte 1177*45039663SJohn Forte ASSERT(mutex_owned(&pppt_global.global_lock)); 1178*45039663SJohn Forte ASSERT(mutex_owned(&tgt->target_mutex)); 1179*45039663SJohn Forte ASSERT(mutex_owned(&ps->ps_mutex)); 1180*45039663SJohn Forte ASSERT(!ps->ps_closed); /* Caller should ensure session is not closed */ 1181*45039663SJohn Forte 1182*45039663SJohn Forte ps->ps_closed = B_TRUE; 1183*45039663SJohn Forte for (ptask = avl_first(&ps->ps_task_list); ptask != NULL; 1184*45039663SJohn Forte ptask = AVL_NEXT(&ps->ps_task_list, ptask)) { 1185*45039663SJohn Forte mutex_enter(&ptask->pt_mutex); 1186*45039663SJohn Forte if (ptask->pt_state == PTS_ACTIVE) { 1187*45039663SJohn Forte stmf_abort(STMF_QUEUE_TASK_ABORT, ptask->pt_stmf_task, 1188*45039663SJohn Forte STMF_ABORTED, NULL); 1189*45039663SJohn Forte } 1190*45039663SJohn Forte mutex_exit(&ptask->pt_mutex); 1191*45039663SJohn Forte } 1192*45039663SJohn Forte 1193*45039663SJohn Forte /* 1194*45039663SJohn Forte * Now that all the tasks are aborting the session refcnt should 1195*45039663SJohn Forte * go to 0. 1196*45039663SJohn Forte */ 1197*45039663SJohn Forte while (ps->ps_refcnt != 0) { 1198*45039663SJohn Forte cv_wait(&ps->ps_cv, &ps->ps_mutex); 1199*45039663SJohn Forte } 1200*45039663SJohn Forte 1201*45039663SJohn Forte avl_remove(&tgt->target_sess_list, ps); 1202*45039663SJohn Forte avl_remove(&pppt_global.global_sess_list, ps); 1203*45039663SJohn Forte (void) taskq_dispatch(pppt_global.global_sess_taskq, 1204*45039663SJohn Forte &pppt_sess_destroy_task, ps, KM_SLEEP); 1205*45039663SJohn Forte 1206*45039663SJohn Forte PPPT_LOG(CE_NOTE, "Session close complete %p", (void *)ps); 1207*45039663SJohn Forte } 1208*45039663SJohn Forte 1209*45039663SJohn Forte pppt_task_t * 1210*45039663SJohn Forte pppt_task_alloc(void) 1211*45039663SJohn Forte { 1212*45039663SJohn Forte pppt_task_t *ptask; 1213*45039663SJohn Forte pppt_buf_t *immed_pbuf; 1214*45039663SJohn Forte 1215*45039663SJohn Forte ptask = kmem_alloc(sizeof (pppt_task_t) + sizeof (pppt_buf_t) + 1216*45039663SJohn Forte sizeof (stmf_data_buf_t), KM_NOSLEEP); 1217*45039663SJohn Forte if (ptask != NULL) { 1218*45039663SJohn Forte ptask->pt_state = PTS_INIT; 1219*45039663SJohn Forte ptask->pt_read_buf = NULL; 1220*45039663SJohn Forte ptask->pt_read_xfer_msgid = 0; 1221*45039663SJohn Forte cv_init(&ptask->pt_cv, NULL, CV_DRIVER, NULL); 1222*45039663SJohn Forte mutex_init(&ptask->pt_mutex, NULL, MUTEX_DRIVER, NULL); 1223*45039663SJohn Forte immed_pbuf = (pppt_buf_t *)(ptask + 1); 1224*45039663SJohn Forte bzero(immed_pbuf, sizeof (*immed_pbuf)); 1225*45039663SJohn Forte immed_pbuf->pbuf_is_immed = B_TRUE; 1226*45039663SJohn Forte immed_pbuf->pbuf_stmf_buf = (stmf_data_buf_t *)(immed_pbuf + 1); 1227*45039663SJohn Forte 1228*45039663SJohn Forte bzero(immed_pbuf->pbuf_stmf_buf, sizeof (stmf_data_buf_t)); 1229*45039663SJohn Forte immed_pbuf->pbuf_stmf_buf->db_port_private = immed_pbuf; 1230*45039663SJohn Forte immed_pbuf->pbuf_stmf_buf->db_sglist_length = 1; 1231*45039663SJohn Forte immed_pbuf->pbuf_stmf_buf->db_flags = DB_DIRECTION_FROM_RPORT | 1232*45039663SJohn Forte DB_DONT_CACHE; 1233*45039663SJohn Forte ptask->pt_immed_data = immed_pbuf; 1234*45039663SJohn Forte } 1235*45039663SJohn Forte 1236*45039663SJohn Forte return (ptask); 1237*45039663SJohn Forte 1238*45039663SJohn Forte } 1239*45039663SJohn Forte 1240*45039663SJohn Forte void 1241*45039663SJohn Forte pppt_task_free(pppt_task_t *ptask) 1242*45039663SJohn Forte { 1243*45039663SJohn Forte mutex_enter(&ptask->pt_mutex); 1244*45039663SJohn Forte mutex_destroy(&ptask->pt_mutex); 1245*45039663SJohn Forte cv_destroy(&ptask->pt_cv); 1246*45039663SJohn Forte kmem_free(ptask, sizeof (pppt_task_t) + sizeof (pppt_buf_t) + 1247*45039663SJohn Forte sizeof (stmf_data_buf_t)); 1248*45039663SJohn Forte } 1249*45039663SJohn Forte 1250*45039663SJohn Forte pppt_status_t 1251*45039663SJohn Forte pppt_task_start(pppt_task_t *ptask) 1252*45039663SJohn Forte { 1253*45039663SJohn Forte avl_index_t where; 1254*45039663SJohn Forte 1255*45039663SJohn Forte ASSERT(ptask->pt_state == PTS_INIT); 1256*45039663SJohn Forte 1257*45039663SJohn Forte mutex_enter(&ptask->pt_sess->ps_mutex); 1258*45039663SJohn Forte mutex_enter(&ptask->pt_mutex); 1259*45039663SJohn Forte if (avl_find(&ptask->pt_sess->ps_task_list, ptask, &where) == NULL) { 1260*45039663SJohn Forte pppt_task_update_state(ptask, PTS_ACTIVE); 1261*45039663SJohn Forte avl_insert(&ptask->pt_sess->ps_task_list, ptask, where); 1262*45039663SJohn Forte mutex_exit(&ptask->pt_mutex); 1263*45039663SJohn Forte mutex_exit(&ptask->pt_sess->ps_mutex); 1264*45039663SJohn Forte return (PPPT_STATUS_SUCCESS); 1265*45039663SJohn Forte } 1266*45039663SJohn Forte mutex_exit(&ptask->pt_mutex); 1267*45039663SJohn Forte mutex_exit(&ptask->pt_sess->ps_mutex); 1268*45039663SJohn Forte 1269*45039663SJohn Forte return (PPPT_STATUS_FAIL); 1270*45039663SJohn Forte } 1271*45039663SJohn Forte 1272*45039663SJohn Forte pppt_status_t 1273*45039663SJohn Forte pppt_task_done(pppt_task_t *ptask) 1274*45039663SJohn Forte { 1275*45039663SJohn Forte pppt_status_t pppt_status = PPPT_STATUS_SUCCESS; 1276*45039663SJohn Forte boolean_t remove = B_FALSE; 1277*45039663SJohn Forte 1278*45039663SJohn Forte mutex_enter(&ptask->pt_mutex); 1279*45039663SJohn Forte 1280*45039663SJohn Forte switch (ptask->pt_state) { 1281*45039663SJohn Forte case PTS_ACTIVE: 1282*45039663SJohn Forte remove = B_TRUE; 1283*45039663SJohn Forte pppt_task_update_state(ptask, PTS_DONE); 1284*45039663SJohn Forte break; 1285*45039663SJohn Forte case PTS_ABORTED: 1286*45039663SJohn Forte pppt_status = PPPT_STATUS_ABORTED; 1287*45039663SJohn Forte break; 1288*45039663SJohn Forte case PTS_DONE: 1289*45039663SJohn Forte /* Repeat calls are OK. Do nothing, return success */ 1290*45039663SJohn Forte break; 1291*45039663SJohn Forte default: 1292*45039663SJohn Forte ASSERT(0); 1293*45039663SJohn Forte } 1294*45039663SJohn Forte 1295*45039663SJohn Forte mutex_exit(&ptask->pt_mutex); 1296*45039663SJohn Forte 1297*45039663SJohn Forte if (remove) { 1298*45039663SJohn Forte mutex_enter(&ptask->pt_sess->ps_mutex); 1299*45039663SJohn Forte avl_remove(&ptask->pt_sess->ps_task_list, ptask); 1300*45039663SJohn Forte mutex_exit(&ptask->pt_sess->ps_mutex); 1301*45039663SJohn Forte } 1302*45039663SJohn Forte 1303*45039663SJohn Forte return (pppt_status); 1304*45039663SJohn Forte } 1305*45039663SJohn Forte 1306*45039663SJohn Forte void 1307*45039663SJohn Forte pppt_task_sent_status(pppt_task_t *ptask) 1308*45039663SJohn Forte { 1309*45039663SJohn Forte /* 1310*45039663SJohn Forte * If STMF tries to abort a task after the task state changed to 1311*45039663SJohn Forte * PTS_DONE (meaning all task processing is complete from 1312*45039663SJohn Forte * the port provider perspective) then we return STMF_BUSY 1313*45039663SJohn Forte * from pppt_lport_abort. STMF will return after a short interval 1314*45039663SJohn Forte * but our calls to stmf_send_status_done will be ignored since 1315*45039663SJohn Forte * STMF is aborting the task. That's where this state comes in. 1316*45039663SJohn Forte * This state essentially says we are calling stmf_send_status_done 1317*45039663SJohn Forte * so we will not be touching the task again. The next time 1318*45039663SJohn Forte * STMF calls pppt_lport_abort we will return a success full 1319*45039663SJohn Forte * status and the abort will succeed. 1320*45039663SJohn Forte */ 1321*45039663SJohn Forte mutex_enter(&ptask->pt_mutex); 1322*45039663SJohn Forte pppt_task_update_state(ptask, PTS_SENT_STATUS); 1323*45039663SJohn Forte mutex_exit(&ptask->pt_mutex); 1324*45039663SJohn Forte } 1325*45039663SJohn Forte 1326*45039663SJohn Forte pppt_task_t * 1327*45039663SJohn Forte pppt_task_lookup(stmf_ic_msgid_t msgid) 1328*45039663SJohn Forte { 1329*45039663SJohn Forte pppt_tgt_t *tgt; 1330*45039663SJohn Forte pppt_sess_t *sess; 1331*45039663SJohn Forte pppt_task_t lookup_task; 1332*45039663SJohn Forte pppt_task_t *result; 1333*45039663SJohn Forte 1334*45039663SJohn Forte bzero(&lookup_task, sizeof (lookup_task)); 1335*45039663SJohn Forte lookup_task.pt_task_id = msgid; 1336*45039663SJohn Forte PPPT_GLOBAL_LOCK(); 1337*45039663SJohn Forte for (tgt = avl_first(&pppt_global.global_target_list); tgt != NULL; 1338*45039663SJohn Forte tgt = AVL_NEXT(&pppt_global.global_target_list, tgt)) { 1339*45039663SJohn Forte 1340*45039663SJohn Forte mutex_enter(&tgt->target_mutex); 1341*45039663SJohn Forte for (sess = avl_first(&tgt->target_sess_list); sess != NULL; 1342*45039663SJohn Forte sess = AVL_NEXT(&tgt->target_sess_list, sess)) { 1343*45039663SJohn Forte mutex_enter(&sess->ps_mutex); 1344*45039663SJohn Forte if ((result = avl_find(&sess->ps_task_list, 1345*45039663SJohn Forte &lookup_task, NULL)) != NULL) { 1346*45039663SJohn Forte if (pppt_task_hold(result) != 1347*45039663SJohn Forte PPPT_STATUS_SUCCESS) { 1348*45039663SJohn Forte result = NULL; 1349*45039663SJohn Forte } 1350*45039663SJohn Forte mutex_exit(&sess->ps_mutex); 1351*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 1352*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 1353*45039663SJohn Forte return (result); 1354*45039663SJohn Forte } 1355*45039663SJohn Forte mutex_exit(&sess->ps_mutex); 1356*45039663SJohn Forte } 1357*45039663SJohn Forte mutex_exit(&tgt->target_mutex); 1358*45039663SJohn Forte } 1359*45039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 1360*45039663SJohn Forte 1361*45039663SJohn Forte return (NULL); 1362*45039663SJohn Forte } 1363*45039663SJohn Forte 1364*45039663SJohn Forte static int 1365*45039663SJohn Forte pppt_task_avl_compare(const void *void_task1, const void *void_task2) 1366*45039663SJohn Forte { 1367*45039663SJohn Forte const pppt_task_t *ptask1 = void_task1; 1368*45039663SJohn Forte const pppt_task_t *ptask2 = void_task2; 1369*45039663SJohn Forte 1370*45039663SJohn Forte if (ptask1->pt_task_id < ptask2->pt_task_id) 1371*45039663SJohn Forte return (-1); 1372*45039663SJohn Forte else if (ptask1->pt_task_id > ptask2->pt_task_id) 1373*45039663SJohn Forte return (1); 1374*45039663SJohn Forte 1375*45039663SJohn Forte return (0); 1376*45039663SJohn Forte } 1377*45039663SJohn Forte 1378*45039663SJohn Forte static pppt_status_t 1379*45039663SJohn Forte pppt_task_try_abort(pppt_task_t *ptask) 1380*45039663SJohn Forte { 1381*45039663SJohn Forte boolean_t remove = B_FALSE; 1382*45039663SJohn Forte pppt_status_t pppt_status = PPPT_STATUS_SUCCESS; 1383*45039663SJohn Forte 1384*45039663SJohn Forte mutex_enter(&ptask->pt_mutex); 1385*45039663SJohn Forte 1386*45039663SJohn Forte switch (ptask->pt_state) { 1387*45039663SJohn Forte case PTS_ACTIVE: 1388*45039663SJohn Forte remove = B_TRUE; 1389*45039663SJohn Forte pppt_task_update_state(ptask, PTS_ABORTED); 1390*45039663SJohn Forte break; 1391*45039663SJohn Forte case PTS_DONE: 1392*45039663SJohn Forte pppt_status = PPPT_STATUS_DONE; 1393*45039663SJohn Forte break; 1394*45039663SJohn Forte case PTS_SENT_STATUS: 1395*45039663SJohn Forte /* 1396*45039663SJohn Forte * Already removed so leave remove set to B_FALSE 1397*45039663SJohn Forte * and leave status set to PPPT_STATUS_SUCCESS. 1398*45039663SJohn Forte */ 1399*45039663SJohn Forte pppt_task_update_state(ptask, PTS_ABORTED); 1400*45039663SJohn Forte break; 1401*45039663SJohn Forte case PTS_ABORTED: 1402*45039663SJohn Forte break; 1403*45039663SJohn Forte default: 1404*45039663SJohn Forte ASSERT(0); 1405*45039663SJohn Forte } 1406*45039663SJohn Forte 1407*45039663SJohn Forte mutex_exit(&ptask->pt_mutex); 1408*45039663SJohn Forte 1409*45039663SJohn Forte if (remove) { 1410*45039663SJohn Forte mutex_enter(&ptask->pt_sess->ps_mutex); 1411*45039663SJohn Forte avl_remove(&ptask->pt_sess->ps_task_list, ptask); 1412*45039663SJohn Forte mutex_exit(&ptask->pt_sess->ps_mutex); 1413*45039663SJohn Forte } 1414*45039663SJohn Forte 1415*45039663SJohn Forte return (pppt_status); 1416*45039663SJohn Forte } 1417*45039663SJohn Forte 1418*45039663SJohn Forte static pppt_status_t 1419*45039663SJohn Forte pppt_task_hold(pppt_task_t *ptask) 1420*45039663SJohn Forte { 1421*45039663SJohn Forte pppt_status_t pppt_status = PPPT_STATUS_SUCCESS; 1422*45039663SJohn Forte 1423*45039663SJohn Forte mutex_enter(&ptask->pt_mutex); 1424*45039663SJohn Forte if (ptask->pt_state == PTS_ACTIVE) { 1425*45039663SJohn Forte ptask->pt_refcnt++; 1426*45039663SJohn Forte } else { 1427*45039663SJohn Forte pppt_status = PPPT_STATUS_FAIL; 1428*45039663SJohn Forte } 1429*45039663SJohn Forte mutex_exit(&ptask->pt_mutex); 1430*45039663SJohn Forte 1431*45039663SJohn Forte return (pppt_status); 1432*45039663SJohn Forte } 1433*45039663SJohn Forte 1434*45039663SJohn Forte static void 1435*45039663SJohn Forte pppt_task_rele(pppt_task_t *ptask) 1436*45039663SJohn Forte { 1437*45039663SJohn Forte mutex_enter(&ptask->pt_mutex); 1438*45039663SJohn Forte ptask->pt_refcnt--; 1439*45039663SJohn Forte cv_signal(&ptask->pt_cv); 1440*45039663SJohn Forte mutex_exit(&ptask->pt_mutex); 1441*45039663SJohn Forte } 1442*45039663SJohn Forte 1443*45039663SJohn Forte static void 1444*45039663SJohn Forte pppt_task_update_state(pppt_task_t *ptask, 1445*45039663SJohn Forte pppt_task_state_t new_state) 1446*45039663SJohn Forte { 1447*45039663SJohn Forte PPPT_LOG(CE_NOTE, "task %p %d -> %d", (void *)ptask, 1448*45039663SJohn Forte ptask->pt_state, new_state); 1449*45039663SJohn Forte 1450*45039663SJohn Forte ASSERT(mutex_owned(&ptask->pt_mutex)); 1451*45039663SJohn Forte ptask->pt_state = new_state; 1452*45039663SJohn Forte cv_signal(&ptask->pt_cv); 1453*45039663SJohn Forte } 1454