145039663SJohn Forte /* 245039663SJohn Forte * CDDL HEADER START 345039663SJohn Forte * 445039663SJohn Forte * The contents of this file are subject to the terms of the 545039663SJohn Forte * Common Development and Distribution License (the "License"). 645039663SJohn Forte * You may not use this file except in compliance with the License. 745039663SJohn Forte * 845039663SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 945039663SJohn Forte * or http://www.opensolaris.org/os/licensing. 1045039663SJohn Forte * See the License for the specific language governing permissions 1145039663SJohn Forte * and limitations under the License. 1245039663SJohn Forte * 1345039663SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 1445039663SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1545039663SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 1645039663SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 1745039663SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 1845039663SJohn Forte * 1945039663SJohn Forte * CDDL HEADER END 2045039663SJohn Forte */ 2145039663SJohn Forte /* 2245039663SJohn Forte * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2345039663SJohn Forte * Use is subject to license terms. 2445039663SJohn Forte */ 2545039663SJohn Forte 2645039663SJohn Forte #include <sys/cpuvar.h> 2745039663SJohn Forte #include <sys/types.h> 2845039663SJohn Forte #include <sys/conf.h> 2945039663SJohn Forte #include <sys/stat.h> 3045039663SJohn Forte #include <sys/file.h> 3145039663SJohn Forte #include <sys/ddi.h> 3245039663SJohn Forte #include <sys/sunddi.h> 3345039663SJohn Forte #include <sys/modctl.h> 3445039663SJohn Forte #include <sys/sysmacros.h> 3545039663SJohn Forte #include <sys/nvpair.h> 3645039663SJohn Forte #include <sys/door.h> 37*e617f214Speter dunlap #include <sys/sdt.h> 3845039663SJohn Forte 3945039663SJohn Forte #include <sys/stmf.h> 4045039663SJohn Forte #include <sys/stmf_ioctl.h> 4145039663SJohn Forte #include <sys/pppt_ioctl.h> 4245039663SJohn Forte #include <sys/portif.h> 4345039663SJohn Forte #include <pppt.h> 4445039663SJohn Forte 4545039663SJohn Forte #define PPPT_VERSION BUILD_DATE "-1.18dev" 4645039663SJohn Forte #define PPPT_NAME_VERSION "COMSTAR PPPT v" PPPT_VERSION 4745039663SJohn Forte 4845039663SJohn Forte /* 4945039663SJohn Forte * DDI entry points. 5045039663SJohn Forte */ 5145039663SJohn Forte static int pppt_drv_attach(dev_info_t *, ddi_attach_cmd_t); 5245039663SJohn Forte static int pppt_drv_detach(dev_info_t *, ddi_detach_cmd_t); 5345039663SJohn Forte static int pppt_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 5445039663SJohn Forte static int pppt_drv_open(dev_t *, int, int, cred_t *); 5545039663SJohn Forte static int pppt_drv_close(dev_t, int, int, cred_t *); 5645039663SJohn Forte static boolean_t pppt_drv_busy(void); 5745039663SJohn Forte static int pppt_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 5845039663SJohn Forte 5945039663SJohn Forte extern pppt_status_t pppt_ic_so_enable(boolean_t); 6045039663SJohn Forte extern void pppt_ic_so_disable(); 6145039663SJohn Forte extern void stmf_ic_rx_msg(char *, size_t); 6245039663SJohn Forte 6345039663SJohn Forte extern struct mod_ops mod_miscops; 6445039663SJohn Forte 6545039663SJohn Forte static struct cb_ops pppt_cb_ops = { 6645039663SJohn Forte pppt_drv_open, /* cb_open */ 6745039663SJohn Forte pppt_drv_close, /* cb_close */ 6845039663SJohn Forte nodev, /* cb_strategy */ 6945039663SJohn Forte nodev, /* cb_print */ 7045039663SJohn Forte nodev, /* cb_dump */ 7145039663SJohn Forte nodev, /* cb_read */ 7245039663SJohn Forte nodev, /* cb_write */ 7345039663SJohn Forte pppt_drv_ioctl, /* cb_ioctl */ 7445039663SJohn Forte nodev, /* cb_devmap */ 7545039663SJohn Forte nodev, /* cb_mmap */ 7645039663SJohn Forte nodev, /* cb_segmap */ 7745039663SJohn Forte nochpoll, /* cb_chpoll */ 7845039663SJohn Forte ddi_prop_op, /* cb_prop_op */ 7945039663SJohn Forte NULL, /* cb_streamtab */ 8045039663SJohn Forte D_MP, /* cb_flag */ 8145039663SJohn Forte CB_REV, /* cb_rev */ 8245039663SJohn Forte nodev, /* cb_aread */ 8345039663SJohn Forte nodev, /* cb_awrite */ 8445039663SJohn Forte }; 8545039663SJohn Forte 8645039663SJohn Forte static struct dev_ops pppt_dev_ops = { 8745039663SJohn Forte DEVO_REV, /* devo_rev */ 8845039663SJohn Forte 0, /* devo_refcnt */ 8945039663SJohn Forte pppt_drv_getinfo, /* devo_getinfo */ 9045039663SJohn Forte nulldev, /* devo_identify */ 9145039663SJohn Forte nulldev, /* devo_probe */ 9245039663SJohn Forte pppt_drv_attach, /* devo_attach */ 9345039663SJohn Forte pppt_drv_detach, /* devo_detach */ 9445039663SJohn Forte nodev, /* devo_reset */ 9545039663SJohn Forte &pppt_cb_ops, /* devo_cb_ops */ 9645039663SJohn Forte NULL, /* devo_bus_ops */ 9745039663SJohn Forte NULL, /* devo_power */ 9845039663SJohn Forte ddi_quiesce_not_needed, /* quiesce */ 9945039663SJohn Forte }; 10045039663SJohn Forte 10145039663SJohn Forte static struct modldrv modldrv = { 10245039663SJohn Forte &mod_driverops, 10345039663SJohn Forte "Proxy Port Provider", 10445039663SJohn Forte &pppt_dev_ops, 10545039663SJohn Forte }; 10645039663SJohn Forte 10745039663SJohn Forte static struct modlinkage modlinkage = { 10845039663SJohn Forte MODREV_1, 10945039663SJohn Forte &modldrv, 11045039663SJohn Forte NULL, 11145039663SJohn Forte }; 11245039663SJohn Forte 11345039663SJohn Forte pppt_global_t pppt_global; 11445039663SJohn Forte 11545039663SJohn Forte int pppt_logging = 0; 11645039663SJohn Forte 11745039663SJohn Forte static int pppt_enable_svc(void); 11845039663SJohn Forte 11945039663SJohn Forte static void pppt_disable_svc(void); 12045039663SJohn Forte 12145039663SJohn Forte static int pppt_task_avl_compare(const void *tgt1, const void *tgt2); 12245039663SJohn Forte 12345039663SJohn Forte static stmf_data_buf_t *pppt_dbuf_alloc(scsi_task_t *task, 12445039663SJohn Forte uint32_t size, uint32_t *pminsize, uint32_t flags); 12545039663SJohn Forte 12645039663SJohn Forte static void pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf); 12745039663SJohn Forte 12845039663SJohn Forte static void pppt_sess_destroy_task(void *ps_void); 12945039663SJohn Forte 13045039663SJohn Forte static void pppt_task_sent_status(pppt_task_t *ptask); 13145039663SJohn Forte 13245039663SJohn Forte static pppt_status_t pppt_task_try_abort(pppt_task_t *ptask); 13345039663SJohn Forte 13445039663SJohn Forte static pppt_status_t pppt_task_hold(pppt_task_t *ptask); 13545039663SJohn Forte 13645039663SJohn Forte static void pppt_task_rele(pppt_task_t *ptask); 13745039663SJohn Forte 13845039663SJohn Forte static void pppt_task_update_state(pppt_task_t *ptask, 13945039663SJohn Forte pppt_task_state_t new_state); 14045039663SJohn Forte 14145039663SJohn Forte /* 14245039663SJohn Forte * Lock order: global --> target --> session --> task 14345039663SJohn Forte */ 14445039663SJohn Forte 14545039663SJohn Forte int 14645039663SJohn Forte _init(void) 14745039663SJohn Forte { 14845039663SJohn Forte int rc; 14945039663SJohn Forte 15045039663SJohn Forte mutex_init(&pppt_global.global_lock, NULL, MUTEX_DEFAULT, NULL); 15145039663SJohn Forte mutex_init(&pppt_global.global_door_lock, NULL, MUTEX_DEFAULT, NULL); 15245039663SJohn Forte pppt_global.global_svc_state = PSS_DETACHED; 15345039663SJohn Forte 15445039663SJohn Forte if ((rc = mod_install(&modlinkage)) != 0) { 15545039663SJohn Forte mutex_destroy(&pppt_global.global_door_lock); 15645039663SJohn Forte mutex_destroy(&pppt_global.global_lock); 15745039663SJohn Forte return (rc); 15845039663SJohn Forte } 15945039663SJohn Forte 16045039663SJohn Forte return (rc); 16145039663SJohn Forte } 16245039663SJohn Forte 16345039663SJohn Forte int 16445039663SJohn Forte _info(struct modinfo *modinfop) 16545039663SJohn Forte { 16645039663SJohn Forte return (mod_info(&modlinkage, modinfop)); 16745039663SJohn Forte } 16845039663SJohn Forte 16945039663SJohn Forte int 17045039663SJohn Forte _fini(void) 17145039663SJohn Forte { 17245039663SJohn Forte int rc; 17345039663SJohn Forte 17445039663SJohn Forte rc = mod_remove(&modlinkage); 17545039663SJohn Forte 17645039663SJohn Forte if (rc == 0) { 17745039663SJohn Forte mutex_destroy(&pppt_global.global_lock); 17845039663SJohn Forte mutex_destroy(&pppt_global.global_door_lock); 17945039663SJohn Forte } 18045039663SJohn Forte 18145039663SJohn Forte return (rc); 18245039663SJohn Forte } 18345039663SJohn Forte 18445039663SJohn Forte /* 18545039663SJohn Forte * DDI entry points. 18645039663SJohn Forte */ 18745039663SJohn Forte 18845039663SJohn Forte /* ARGSUSED */ 18945039663SJohn Forte static int 19045039663SJohn Forte pppt_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 19145039663SJohn Forte void **result) 19245039663SJohn Forte { 19345039663SJohn Forte ulong_t instance = getminor((dev_t)arg); 19445039663SJohn Forte 19545039663SJohn Forte switch (cmd) { 19645039663SJohn Forte case DDI_INFO_DEVT2DEVINFO: 19745039663SJohn Forte *result = pppt_global.global_dip; 19845039663SJohn Forte return (DDI_SUCCESS); 19945039663SJohn Forte 20045039663SJohn Forte case DDI_INFO_DEVT2INSTANCE: 20145039663SJohn Forte *result = (void *)instance; 20245039663SJohn Forte return (DDI_SUCCESS); 20345039663SJohn Forte 20445039663SJohn Forte default: 20545039663SJohn Forte break; 20645039663SJohn Forte } 20745039663SJohn Forte 20845039663SJohn Forte return (DDI_FAILURE); 20945039663SJohn Forte } 21045039663SJohn Forte 21145039663SJohn Forte static int 21245039663SJohn Forte pppt_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 21345039663SJohn Forte { 21445039663SJohn Forte if (cmd != DDI_ATTACH) { 21545039663SJohn Forte return (DDI_FAILURE); 21645039663SJohn Forte } 21745039663SJohn Forte 21845039663SJohn Forte if (ddi_get_instance(dip) != 0) { 21945039663SJohn Forte /* we only allow instance 0 to attach */ 22045039663SJohn Forte return (DDI_FAILURE); 22145039663SJohn Forte } 22245039663SJohn Forte 22345039663SJohn Forte /* create the minor node */ 22445039663SJohn Forte if (ddi_create_minor_node(dip, PPPT_MODNAME, S_IFCHR, 0, 22545039663SJohn Forte DDI_PSEUDO, 0) != DDI_SUCCESS) { 22645039663SJohn Forte cmn_err(CE_WARN, "pppt_drv_attach: " 22745039663SJohn Forte "failed creating minor node"); 22845039663SJohn Forte return (DDI_FAILURE); 22945039663SJohn Forte } 23045039663SJohn Forte 23145039663SJohn Forte pppt_global.global_svc_state = PSS_DISABLED; 23245039663SJohn Forte pppt_global.global_dip = dip; 23345039663SJohn Forte 23445039663SJohn Forte return (DDI_SUCCESS); 23545039663SJohn Forte } 23645039663SJohn Forte 23745039663SJohn Forte /*ARGSUSED*/ 23845039663SJohn Forte static int 23945039663SJohn Forte pppt_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 24045039663SJohn Forte { 24145039663SJohn Forte if (cmd != DDI_DETACH) 24245039663SJohn Forte return (DDI_FAILURE); 24345039663SJohn Forte 24445039663SJohn Forte PPPT_GLOBAL_LOCK(); 24545039663SJohn Forte if (pppt_drv_busy()) { 24645039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 24745039663SJohn Forte return (EBUSY); 24845039663SJohn Forte } 24945039663SJohn Forte 25045039663SJohn Forte ddi_remove_minor_node(dip, NULL); 25145039663SJohn Forte ddi_prop_remove_all(dip); 25245039663SJohn Forte 25345039663SJohn Forte pppt_global.global_svc_state = PSS_DETACHED; 25445039663SJohn Forte 25545039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 25645039663SJohn Forte 25745039663SJohn Forte return (DDI_SUCCESS); 25845039663SJohn Forte } 25945039663SJohn Forte 26045039663SJohn Forte /*ARGSUSED*/ 26145039663SJohn Forte static int 26245039663SJohn Forte pppt_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp) 26345039663SJohn Forte { 26445039663SJohn Forte int rc = 0; 26545039663SJohn Forte 26645039663SJohn Forte PPPT_GLOBAL_LOCK(); 26745039663SJohn Forte 26845039663SJohn Forte switch (pppt_global.global_svc_state) { 26945039663SJohn Forte case PSS_DISABLED: 27045039663SJohn Forte pppt_global.global_svc_state = PSS_ENABLING; 27145039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 27245039663SJohn Forte rc = pppt_enable_svc(); 27345039663SJohn Forte PPPT_GLOBAL_LOCK(); 27445039663SJohn Forte if (rc == 0) { 27545039663SJohn Forte pppt_global.global_svc_state = PSS_ENABLED; 27645039663SJohn Forte } else { 27745039663SJohn Forte pppt_global.global_svc_state = PSS_DISABLED; 27845039663SJohn Forte } 27945039663SJohn Forte break; 28045039663SJohn Forte case PSS_DISABLING: 28145039663SJohn Forte case PSS_ENABLING: 28245039663SJohn Forte case PSS_ENABLED: 28345039663SJohn Forte rc = EBUSY; 28445039663SJohn Forte break; 28545039663SJohn Forte default: 28645039663SJohn Forte rc = EFAULT; 28745039663SJohn Forte break; 28845039663SJohn Forte } 28945039663SJohn Forte 29045039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 29145039663SJohn Forte 29245039663SJohn Forte return (rc); 29345039663SJohn Forte } 29445039663SJohn Forte 29545039663SJohn Forte /* ARGSUSED */ 29645039663SJohn Forte static int 29745039663SJohn Forte pppt_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 29845039663SJohn Forte { 29945039663SJohn Forte int rc = 0; 30045039663SJohn Forte 30145039663SJohn Forte PPPT_GLOBAL_LOCK(); 30245039663SJohn Forte 30345039663SJohn Forte switch (pppt_global.global_svc_state) { 30445039663SJohn Forte case PSS_ENABLED: 30545039663SJohn Forte pppt_global.global_svc_state = PSS_DISABLING; 30645039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 30745039663SJohn Forte pppt_disable_svc(); 30845039663SJohn Forte PPPT_GLOBAL_LOCK(); 30945039663SJohn Forte pppt_global.global_svc_state = PSS_DISABLED; 31045039663SJohn Forte /* 31145039663SJohn Forte * release the door to the daemon 31245039663SJohn Forte */ 31345039663SJohn Forte mutex_enter(&pppt_global.global_door_lock); 31445039663SJohn Forte if (pppt_global.global_door != NULL) { 31545039663SJohn Forte door_ki_rele(pppt_global.global_door); 31645039663SJohn Forte pppt_global.global_door = NULL; 31745039663SJohn Forte } 31845039663SJohn Forte mutex_exit(&pppt_global.global_door_lock); 31945039663SJohn Forte break; 32045039663SJohn Forte default: 32145039663SJohn Forte rc = EFAULT; 32245039663SJohn Forte break; 32345039663SJohn Forte } 32445039663SJohn Forte 32545039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 32645039663SJohn Forte 32745039663SJohn Forte return (rc); 32845039663SJohn Forte } 32945039663SJohn Forte 33045039663SJohn Forte static boolean_t 33145039663SJohn Forte pppt_drv_busy(void) 33245039663SJohn Forte { 33345039663SJohn Forte switch (pppt_global.global_svc_state) { 33445039663SJohn Forte case PSS_DISABLED: 33545039663SJohn Forte case PSS_DETACHED: 33645039663SJohn Forte return (B_FALSE); 33745039663SJohn Forte default: 33845039663SJohn Forte return (B_TRUE); 33945039663SJohn Forte } 34045039663SJohn Forte /* NOTREACHED */ 34145039663SJohn Forte } 34245039663SJohn Forte 34345039663SJohn Forte /* ARGSUSED */ 34445039663SJohn Forte static int 34545039663SJohn Forte pppt_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred, 34645039663SJohn Forte int *retval) 34745039663SJohn Forte { 34845039663SJohn Forte int rc; 34945039663SJohn Forte void *buf; 35045039663SJohn Forte size_t buf_size; 35145039663SJohn Forte pppt_iocdata_t iocd; 35245039663SJohn Forte door_handle_t new_handle; 35345039663SJohn Forte 35445039663SJohn Forte if (drv_priv(cred) != 0) { 35545039663SJohn Forte return (EPERM); 35645039663SJohn Forte } 35745039663SJohn Forte 35845039663SJohn Forte rc = ddi_copyin((void *)argp, &iocd, sizeof (iocd), flag); 35945039663SJohn Forte if (rc) 36045039663SJohn Forte return (EFAULT); 36145039663SJohn Forte 36245039663SJohn Forte if (iocd.pppt_version != PPPT_VERSION_1) 36345039663SJohn Forte return (EINVAL); 36445039663SJohn Forte 36545039663SJohn Forte switch (cmd) { 36645039663SJohn Forte case PPPT_MESSAGE: 36745039663SJohn Forte 36845039663SJohn Forte /* XXX limit buf_size ? */ 36945039663SJohn Forte buf_size = (size_t)iocd.pppt_buf_size; 37045039663SJohn Forte buf = kmem_alloc(buf_size, KM_SLEEP); 37145039663SJohn Forte if (buf == NULL) 37245039663SJohn Forte return (ENOMEM); 37345039663SJohn Forte 37445039663SJohn Forte rc = ddi_copyin((void *)(unsigned long)iocd.pppt_buf, 37545039663SJohn Forte buf, buf_size, flag); 37645039663SJohn Forte if (rc) { 37745039663SJohn Forte kmem_free(buf, buf_size); 37845039663SJohn Forte return (EFAULT); 37945039663SJohn Forte } 38045039663SJohn Forte 38145039663SJohn Forte stmf_ic_rx_msg(buf, buf_size); 38245039663SJohn Forte 38345039663SJohn Forte kmem_free(buf, buf_size); 38445039663SJohn Forte break; 38545039663SJohn Forte case PPPT_INSTALL_DOOR: 38645039663SJohn Forte 38745039663SJohn Forte new_handle = door_ki_lookup((int)iocd.pppt_door_fd); 38845039663SJohn Forte if (new_handle == NULL) 38945039663SJohn Forte return (EINVAL); 39045039663SJohn Forte 39145039663SJohn Forte mutex_enter(&pppt_global.global_door_lock); 39245039663SJohn Forte ASSERT(pppt_global.global_svc_state == PSS_ENABLED); 39345039663SJohn Forte if (pppt_global.global_door != NULL) { 39445039663SJohn Forte /* 39545039663SJohn Forte * There can only be one door installed 39645039663SJohn Forte */ 39745039663SJohn Forte mutex_exit(&pppt_global.global_door_lock); 39845039663SJohn Forte door_ki_rele(new_handle); 39945039663SJohn Forte return (EBUSY); 40045039663SJohn Forte } 40145039663SJohn Forte pppt_global.global_door = new_handle; 40245039663SJohn Forte mutex_exit(&pppt_global.global_door_lock); 40345039663SJohn Forte break; 40445039663SJohn Forte } 40545039663SJohn Forte 40645039663SJohn Forte return (rc); 40745039663SJohn Forte } 40845039663SJohn Forte 40945039663SJohn Forte /* 41045039663SJohn Forte * pppt_enable_svc 41145039663SJohn Forte * 41245039663SJohn Forte * registers all the configured targets and target portals with STMF 41345039663SJohn Forte */ 41445039663SJohn Forte static int 41545039663SJohn Forte pppt_enable_svc(void) 41645039663SJohn Forte { 41745039663SJohn Forte stmf_port_provider_t *pp; 41845039663SJohn Forte stmf_dbuf_store_t *dbuf_store; 41945039663SJohn Forte int rc = 0; 42045039663SJohn Forte 42145039663SJohn Forte ASSERT(pppt_global.global_svc_state == PSS_ENABLING); 42245039663SJohn Forte 42345039663SJohn Forte /* 42445039663SJohn Forte * Make sure that can tell if we have partially allocated 42545039663SJohn Forte * in case we need to exit and tear down anything allocated. 42645039663SJohn Forte */ 42745039663SJohn Forte pppt_global.global_dbuf_store = NULL; 42845039663SJohn Forte pp = NULL; 42945039663SJohn Forte pppt_global.global_pp = NULL; 43045039663SJohn Forte pppt_global.global_dispatch_taskq = NULL; 43145039663SJohn Forte pppt_global.global_sess_taskq = NULL; 43245039663SJohn Forte 43345039663SJohn Forte avl_create(&pppt_global.global_target_list, 43445039663SJohn Forte pppt_tgt_avl_compare, sizeof (pppt_tgt_t), 43545039663SJohn Forte offsetof(pppt_tgt_t, target_global_ln)); 43645039663SJohn Forte 43745039663SJohn Forte avl_create(&pppt_global.global_sess_list, 43845039663SJohn Forte pppt_sess_avl_compare_by_id, sizeof (pppt_sess_t), 43945039663SJohn Forte offsetof(pppt_sess_t, ps_global_ln)); 44045039663SJohn Forte 44145039663SJohn Forte /* 44245039663SJohn Forte * Setup STMF dbuf store. Tf buffers are associated with a particular 44345039663SJohn Forte * lport (FC, SRP) then the dbuf_store should stored in the lport 44445039663SJohn Forte * context, otherwise (iSCSI) the dbuf_store should be global. 44545039663SJohn Forte */ 44645039663SJohn Forte dbuf_store = stmf_alloc(STMF_STRUCT_DBUF_STORE, 0, 0); 44745039663SJohn Forte if (dbuf_store == NULL) { 44845039663SJohn Forte rc = ENOMEM; 44945039663SJohn Forte goto tear_down_and_return; 45045039663SJohn Forte } 45145039663SJohn Forte dbuf_store->ds_alloc_data_buf = pppt_dbuf_alloc; 45245039663SJohn Forte dbuf_store->ds_free_data_buf = pppt_dbuf_free; 45345039663SJohn Forte dbuf_store->ds_port_private = NULL; 45445039663SJohn Forte pppt_global.global_dbuf_store = dbuf_store; 45545039663SJohn Forte 45645039663SJohn Forte /* Register port provider */ 45745039663SJohn Forte pp = stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0); 45845039663SJohn Forte if (pp == NULL) { 45945039663SJohn Forte rc = ENOMEM; 46045039663SJohn Forte goto tear_down_and_return; 46145039663SJohn Forte } 46245039663SJohn Forte 46345039663SJohn Forte pp->pp_portif_rev = PORTIF_REV_1; 46445039663SJohn Forte pp->pp_instance = 0; 46545039663SJohn Forte pp->pp_name = PPPT_MODNAME; 46645039663SJohn Forte pp->pp_cb = NULL; 46745039663SJohn Forte 46845039663SJohn Forte pppt_global.global_pp = pp; 46945039663SJohn Forte 47045039663SJohn Forte if (stmf_register_port_provider(pp) != STMF_SUCCESS) { 47145039663SJohn Forte rc = EIO; 47245039663SJohn Forte goto tear_down_and_return; 47345039663SJohn Forte } 47445039663SJohn Forte 47545039663SJohn Forte pppt_global.global_dispatch_taskq = taskq_create("pppt_dispatch", 47645039663SJohn Forte 1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE); 47745039663SJohn Forte 47845039663SJohn Forte pppt_global.global_sess_taskq = taskq_create("pppt_session", 47945039663SJohn Forte 1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE); 48045039663SJohn Forte 48145039663SJohn Forte return (0); 48245039663SJohn Forte 48345039663SJohn Forte tear_down_and_return: 48445039663SJohn Forte 48545039663SJohn Forte if (pppt_global.global_sess_taskq) { 48645039663SJohn Forte taskq_destroy(pppt_global.global_sess_taskq); 48745039663SJohn Forte pppt_global.global_sess_taskq = NULL; 48845039663SJohn Forte } 48945039663SJohn Forte 49045039663SJohn Forte if (pppt_global.global_dispatch_taskq) { 49145039663SJohn Forte taskq_destroy(pppt_global.global_dispatch_taskq); 49245039663SJohn Forte pppt_global.global_dispatch_taskq = NULL; 49345039663SJohn Forte } 49445039663SJohn Forte 49545039663SJohn Forte if (pppt_global.global_pp) 49645039663SJohn Forte pppt_global.global_pp = NULL; 49745039663SJohn Forte 49845039663SJohn Forte if (pp) 49945039663SJohn Forte stmf_free(pp); 50045039663SJohn Forte 50145039663SJohn Forte if (pppt_global.global_dbuf_store) { 50245039663SJohn Forte stmf_free(pppt_global.global_dbuf_store); 50345039663SJohn Forte pppt_global.global_dbuf_store = NULL; 50445039663SJohn Forte } 50545039663SJohn Forte 50645039663SJohn Forte avl_destroy(&pppt_global.global_sess_list); 50745039663SJohn Forte avl_destroy(&pppt_global.global_target_list); 50845039663SJohn Forte 50945039663SJohn Forte return (rc); 51045039663SJohn Forte } 51145039663SJohn Forte 51245039663SJohn Forte /* 51345039663SJohn Forte * pppt_disable_svc 51445039663SJohn Forte * 51545039663SJohn Forte * clean up all existing sessions and deregister targets from STMF 51645039663SJohn Forte */ 51745039663SJohn Forte static void 51845039663SJohn Forte pppt_disable_svc(void) 51945039663SJohn Forte { 52045039663SJohn Forte pppt_tgt_t *tgt, *next_tgt; 52145039663SJohn Forte avl_tree_t delete_target_list; 52245039663SJohn Forte 52345039663SJohn Forte ASSERT(pppt_global.global_svc_state == PSS_DISABLING); 52445039663SJohn Forte 52545039663SJohn Forte avl_create(&delete_target_list, 52645039663SJohn Forte pppt_tgt_avl_compare, sizeof (pppt_tgt_t), 52745039663SJohn Forte offsetof(pppt_tgt_t, target_global_ln)); 52845039663SJohn Forte 52945039663SJohn Forte PPPT_GLOBAL_LOCK(); 53045039663SJohn Forte for (tgt = avl_first(&pppt_global.global_target_list); 53145039663SJohn Forte tgt != NULL; 53245039663SJohn Forte tgt = next_tgt) { 53345039663SJohn Forte next_tgt = AVL_NEXT(&pppt_global.global_target_list, tgt); 53445039663SJohn Forte avl_remove(&pppt_global.global_target_list, tgt); 53545039663SJohn Forte avl_add(&delete_target_list, tgt); 53645039663SJohn Forte pppt_tgt_async_delete(tgt); 53745039663SJohn Forte } 53845039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 53945039663SJohn Forte 54045039663SJohn Forte for (tgt = avl_first(&delete_target_list); 54145039663SJohn Forte tgt != NULL; 54245039663SJohn Forte tgt = next_tgt) { 54345039663SJohn Forte next_tgt = AVL_NEXT(&delete_target_list, tgt); 54445039663SJohn Forte mutex_enter(&tgt->target_mutex); 54545039663SJohn Forte while ((tgt->target_refcount > 0) || 54645039663SJohn Forte (tgt->target_state != TS_DELETING)) { 54745039663SJohn Forte cv_wait(&tgt->target_cv, &tgt->target_mutex); 54845039663SJohn Forte } 54945039663SJohn Forte mutex_exit(&tgt->target_mutex); 55045039663SJohn Forte 55145039663SJohn Forte avl_remove(&delete_target_list, tgt); 55245039663SJohn Forte pppt_tgt_destroy(tgt); 55345039663SJohn Forte } 55445039663SJohn Forte 55545039663SJohn Forte taskq_destroy(pppt_global.global_sess_taskq); 55645039663SJohn Forte 55745039663SJohn Forte taskq_destroy(pppt_global.global_dispatch_taskq); 55845039663SJohn Forte 55945039663SJohn Forte avl_destroy(&pppt_global.global_sess_list); 56045039663SJohn Forte avl_destroy(&pppt_global.global_target_list); 56145039663SJohn Forte 56245039663SJohn Forte (void) stmf_deregister_port_provider(pppt_global.global_pp); 56345039663SJohn Forte 56445039663SJohn Forte stmf_free(pppt_global.global_dbuf_store); 56545039663SJohn Forte pppt_global.global_dbuf_store = NULL; 56645039663SJohn Forte 56745039663SJohn Forte stmf_free(pppt_global.global_pp); 56845039663SJohn Forte pppt_global.global_pp = NULL; 56945039663SJohn Forte } 57045039663SJohn Forte 57145039663SJohn Forte /* 57245039663SJohn Forte * STMF callbacks 57345039663SJohn Forte */ 57445039663SJohn Forte 57545039663SJohn Forte /*ARGSUSED*/ 57645039663SJohn Forte static stmf_data_buf_t * 57745039663SJohn Forte pppt_dbuf_alloc(scsi_task_t *task, uint32_t size, uint32_t *pminsize, 57845039663SJohn Forte uint32_t flags) 57945039663SJohn Forte { 58045039663SJohn Forte stmf_data_buf_t *result; 58145039663SJohn Forte pppt_buf_t *pbuf; 58245039663SJohn Forte uint8_t *buf; 58345039663SJohn Forte 58445039663SJohn Forte /* Get buffer */ 58545039663SJohn Forte buf = kmem_alloc(size, KM_SLEEP); 58645039663SJohn Forte 58745039663SJohn Forte /* 58845039663SJohn Forte * Allocate stmf buf with private port provider section 58945039663SJohn Forte * (pppt_buf_t) 59045039663SJohn Forte */ 59145039663SJohn Forte result = stmf_alloc(STMF_STRUCT_DATA_BUF, sizeof (pppt_buf_t), 0); 59245039663SJohn Forte if (result != NULL) { 59345039663SJohn Forte /* Fill in pppt_buf_t */ 59445039663SJohn Forte pbuf = result->db_port_private; 59545039663SJohn Forte pbuf->pbuf_stmf_buf = result; 59645039663SJohn Forte pbuf->pbuf_is_immed = B_FALSE; 59745039663SJohn Forte 59845039663SJohn Forte /* 59945039663SJohn Forte * Fill in stmf_data_buf_t. DB_DONT CACHE tells 60045039663SJohn Forte * stmf not to cache buffers but STMF doesn't do 60145039663SJohn Forte * that yet so it's a no-op. Port providers like 60245039663SJohn Forte * FC and SRP that have buffers associated with the 60345039663SJohn Forte * target port would want to let STMF cache 60445039663SJohn Forte * the buffers. Port providers like iSCSI would 60545039663SJohn Forte * not want STMF to cache because the buffers are 60645039663SJohn Forte * really associated with a connection, not an 60745039663SJohn Forte * STMF target port so there is no way for STMF 60845039663SJohn Forte * to cache the buffers effectively. These port 60945039663SJohn Forte * providers should cache buffers internally if 61045039663SJohn Forte * there is significant buffer setup overhead. 61145039663SJohn Forte * 61245039663SJohn Forte * And of course, since STMF doesn't do any internal 61345039663SJohn Forte * caching right now anyway, all port providers should 61445039663SJohn Forte * do what they can to minimize buffer setup overhead. 61545039663SJohn Forte */ 61645039663SJohn Forte result->db_flags = DB_DONT_CACHE; 61745039663SJohn Forte result->db_buf_size = size; 61845039663SJohn Forte result->db_data_size = size; 61945039663SJohn Forte result->db_sglist_length = 1; 62045039663SJohn Forte result->db_sglist[0].seg_addr = buf; 62145039663SJohn Forte result->db_sglist[0].seg_length = size; 62245039663SJohn Forte return (result); 62345039663SJohn Forte } else { 62445039663SJohn Forte /* 62545039663SJohn Forte * Couldn't get the stmf_data_buf_t so free the 62645039663SJohn Forte * buffer 62745039663SJohn Forte */ 62845039663SJohn Forte kmem_free(buf, size); 62945039663SJohn Forte } 63045039663SJohn Forte 63145039663SJohn Forte return (NULL); 63245039663SJohn Forte } 63345039663SJohn Forte 63445039663SJohn Forte /*ARGSUSED*/ 63545039663SJohn Forte static void 63645039663SJohn Forte pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf) 63745039663SJohn Forte { 63845039663SJohn Forte pppt_buf_t *pbuf = dbuf->db_port_private; 63945039663SJohn Forte 64045039663SJohn Forte if (pbuf->pbuf_is_immed) { 64145039663SJohn Forte stmf_ic_msg_free(pbuf->pbuf_immed_msg); 64245039663SJohn Forte } else { 64345039663SJohn Forte kmem_free(dbuf->db_sglist[0].seg_addr, 64445039663SJohn Forte dbuf->db_sglist[0].seg_length); 64545039663SJohn Forte stmf_free(dbuf); 64645039663SJohn Forte } 64745039663SJohn Forte } 64845039663SJohn Forte 64945039663SJohn Forte /*ARGSUSED*/ 65045039663SJohn Forte stmf_status_t 65145039663SJohn Forte pppt_lport_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, 65245039663SJohn Forte uint32_t ioflags) 65345039663SJohn Forte { 65445039663SJohn Forte pppt_task_t *pppt_task = task->task_port_private; 65545039663SJohn Forte pppt_buf_t *pbuf = dbuf->db_port_private; 65645039663SJohn Forte stmf_ic_msg_t *msg; 65745039663SJohn Forte stmf_ic_msg_status_t ic_msg_status; 65845039663SJohn Forte 65945039663SJohn Forte /* 66045039663SJohn Forte * If we are aborting then we can ignore this request, otherwise 66145039663SJohn Forte * add a reference. 66245039663SJohn Forte */ 66345039663SJohn Forte if (pppt_task_hold(pppt_task) != PPPT_STATUS_SUCCESS) { 66445039663SJohn Forte return (STMF_SUCCESS); 66545039663SJohn Forte } 66645039663SJohn Forte 66745039663SJohn Forte /* 66845039663SJohn Forte * If it's not immediate data then start the transfer 66945039663SJohn Forte */ 67045039663SJohn Forte ASSERT(pbuf->pbuf_is_immed == B_FALSE); 67145039663SJohn Forte if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) { 67245039663SJohn Forte 67345039663SJohn Forte /* Send read data */ 67445039663SJohn Forte msg = stmf_ic_scsi_data_msg_alloc( 67545039663SJohn Forte pppt_task->pt_task_id, 67645039663SJohn Forte pppt_task->pt_sess->ps_session_id, 67745039663SJohn Forte pppt_task->pt_lun_id, 67845039663SJohn Forte dbuf->db_sglist[0].seg_length, 67945039663SJohn Forte dbuf->db_sglist[0].seg_addr, 0); 68045039663SJohn Forte 68145039663SJohn Forte pppt_task->pt_read_buf = pbuf; 68245039663SJohn Forte pppt_task->pt_read_xfer_msgid = msg->icm_msgid; 68345039663SJohn Forte 68445039663SJohn Forte ic_msg_status = stmf_ic_tx_msg(msg); 68545039663SJohn Forte pppt_task_rele(pppt_task); 68645039663SJohn Forte if (ic_msg_status != STMF_IC_MSG_SUCCESS) { 68745039663SJohn Forte return (STMF_FAILURE); 68845039663SJohn Forte } else { 68945039663SJohn Forte return (STMF_SUCCESS); 69045039663SJohn Forte } 69145039663SJohn Forte } else if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) { 69245039663SJohn Forte pppt_task_rele(pppt_task); 69345039663SJohn Forte return (STMF_FAILURE); 69445039663SJohn Forte } 69545039663SJohn Forte 69645039663SJohn Forte pppt_task_rele(pppt_task); 69745039663SJohn Forte 69845039663SJohn Forte return (STMF_INVALID_ARG); 69945039663SJohn Forte } 70045039663SJohn Forte 70145039663SJohn Forte void 70245039663SJohn Forte pppt_xfer_read_complete(pppt_task_t *pppt_task, stmf_status_t status) 70345039663SJohn Forte { 70445039663SJohn Forte pppt_buf_t *pppt_buf; 70545039663SJohn Forte stmf_data_buf_t *dbuf; 70645039663SJohn Forte 70745039663SJohn Forte /* 70845039663SJohn Forte * Caller should have taken a task hold (likely via pppt_task_lookup) 70945039663SJohn Forte * 71045039663SJohn Forte * Get pppt_buf_t and stmf_data_buf_t pointers 71145039663SJohn Forte */ 71245039663SJohn Forte pppt_buf = pppt_task->pt_read_buf; 71345039663SJohn Forte dbuf = pppt_buf->pbuf_stmf_buf; 71445039663SJohn Forte dbuf->db_xfer_status = (status == STMF_SUCCESS) ? 71545039663SJohn Forte STMF_SUCCESS : STMF_FAILURE; 71645039663SJohn Forte 71745039663SJohn Forte /* 71845039663SJohn Forte * COMSTAR currently requires port providers to support 71945039663SJohn Forte * the DB_SEND_STATUS_GOOD flag even if phase collapse is 72045039663SJohn Forte * not supported. So we will roll our own... pretend we are 72145039663SJohn Forte * COMSTAR and ask for a status message. 72245039663SJohn Forte */ 72345039663SJohn Forte if ((dbuf->db_flags & DB_SEND_STATUS_GOOD) && 72445039663SJohn Forte (status == STMF_SUCCESS)) { 72545039663SJohn Forte /* 72645039663SJohn Forte * It's possible the task has been aborted since the time we 72745039663SJohn Forte * looked it up. We need to release the hold before calling 72845039663SJohn Forte * pppt_lport_send_status and as soon as we release the hold 72945039663SJohn Forte * the task may disappear. Calling pppt_task_done allows us 73045039663SJohn Forte * to determine whether the task has been aborted (in which 73145039663SJohn Forte * case we will stop processing and return) and mark the task 73245039663SJohn Forte * "done" which will prevent the task from being aborted while 73345039663SJohn Forte * we are trying to send the status. 73445039663SJohn Forte */ 73545039663SJohn Forte if (pppt_task_done(pppt_task) != PPPT_STATUS_SUCCESS) { 73645039663SJohn Forte /* STMF will free task and buffer(s) */ 73745039663SJohn Forte pppt_task_rele(pppt_task); 73845039663SJohn Forte return; 73945039663SJohn Forte } 74045039663SJohn Forte pppt_task_rele(pppt_task); 74145039663SJohn Forte 74245039663SJohn Forte if (pppt_lport_send_status(pppt_task->pt_stmf_task, 0) 74345039663SJohn Forte != STMF_SUCCESS) { 74445039663SJohn Forte /* Failed to send status */ 74545039663SJohn Forte dbuf->db_xfer_status = STMF_FAILURE; 74645039663SJohn Forte stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf, 74745039663SJohn Forte STMF_IOF_LPORT_DONE); 74845039663SJohn Forte } 74945039663SJohn Forte } else { 75045039663SJohn Forte pppt_task_rele(pppt_task); 75145039663SJohn Forte stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf, 0); 75245039663SJohn Forte } 75345039663SJohn Forte } 75445039663SJohn Forte 75545039663SJohn Forte /*ARGSUSED*/ 75645039663SJohn Forte stmf_status_t 75745039663SJohn Forte pppt_lport_send_status(scsi_task_t *task, uint32_t ioflags) 75845039663SJohn Forte { 75945039663SJohn Forte pppt_task_t *ptask = task->task_port_private; 76045039663SJohn Forte stmf_ic_msg_t *msg; 76145039663SJohn Forte stmf_ic_msg_status_t ic_msg_status; 76245039663SJohn Forte 76345039663SJohn Forte /* 76445039663SJohn Forte * Mark task completed. If the state indicates it was aborted 76545039663SJohn Forte * then we don't need to respond. 76645039663SJohn Forte */ 76745039663SJohn Forte if (pppt_task_done(ptask) == PPPT_STATUS_ABORTED) { 76845039663SJohn Forte return (STMF_SUCCESS); 76945039663SJohn Forte } 77045039663SJohn Forte 77145039663SJohn Forte /* 77245039663SJohn Forte * Send status. 77345039663SJohn Forte */ 77445039663SJohn Forte msg = stmf_ic_scsi_status_msg_alloc( 77545039663SJohn Forte ptask->pt_task_id, 77645039663SJohn Forte ptask->pt_sess->ps_session_id, 77745039663SJohn Forte ptask->pt_lun_id, 77845039663SJohn Forte 0, 77945039663SJohn Forte task->task_scsi_status, 78045039663SJohn Forte task->task_status_ctrl, task->task_resid, 78145039663SJohn Forte task->task_sense_length, task->task_sense_data, 0); 78245039663SJohn Forte 78345039663SJohn Forte ic_msg_status = stmf_ic_tx_msg(msg); 78445039663SJohn Forte 78545039663SJohn Forte if (ic_msg_status != STMF_IC_MSG_SUCCESS) { 78645039663SJohn Forte pppt_task_sent_status(ptask); 78745039663SJohn Forte stmf_send_status_done(ptask->pt_stmf_task, 78845039663SJohn Forte STMF_FAILURE, STMF_IOF_LPORT_DONE); 78945039663SJohn Forte return (STMF_FAILURE); 79045039663SJohn Forte } else { 79145039663SJohn Forte pppt_task_sent_status(ptask); 79245039663SJohn Forte stmf_send_status_done(ptask->pt_stmf_task, 79345039663SJohn Forte STMF_SUCCESS, STMF_IOF_LPORT_DONE); 79445039663SJohn Forte return (STMF_SUCCESS); 79545039663SJohn Forte } 79645039663SJohn Forte } 79745039663SJohn Forte 79845039663SJohn Forte void 79945039663SJohn Forte pppt_lport_task_free(scsi_task_t *task) 80045039663SJohn Forte { 80145039663SJohn Forte pppt_task_t *ptask = task->task_port_private; 80245039663SJohn Forte pppt_sess_t *ps = ptask->pt_sess; 80345039663SJohn Forte 80445039663SJohn Forte pppt_task_free(ptask); 80545039663SJohn Forte pppt_sess_rele(ps); 80645039663SJohn Forte } 80745039663SJohn Forte 80845039663SJohn Forte /*ARGSUSED*/ 80945039663SJohn Forte stmf_status_t 81045039663SJohn Forte pppt_lport_abort(stmf_local_port_t *lport, int abort_cmd, void *arg, 81145039663SJohn Forte uint32_t flags) 81245039663SJohn Forte { 81345039663SJohn Forte scsi_task_t *st = (scsi_task_t *)arg; 81445039663SJohn Forte pppt_task_t *ptask; 81545039663SJohn Forte 81645039663SJohn Forte ptask = st->task_port_private; 81745039663SJohn Forte 81845039663SJohn Forte if (pppt_task_try_abort(ptask) == PPPT_STATUS_DONE) { 81945039663SJohn Forte /* 82045039663SJohn Forte * This task is beyond the point where abort makes sense 82145039663SJohn Forte * and we will soon be sending status. Tell STMF to 82245039663SJohn Forte * go away. 82345039663SJohn Forte */ 82445039663SJohn Forte return (STMF_BUSY); 82545039663SJohn Forte } else { 82645039663SJohn Forte return (STMF_ABORT_SUCCESS); 82745039663SJohn Forte } 82845039663SJohn Forte /*NOTREACHED*/ 82945039663SJohn Forte } 83045039663SJohn Forte 83145039663SJohn Forte /*ARGSUSED*/ 83245039663SJohn Forte void 83345039663SJohn Forte pppt_lport_ctl(stmf_local_port_t *lport, int cmd, void *arg) 83445039663SJohn Forte { 83545039663SJohn Forte switch (cmd) { 83645039663SJohn Forte case STMF_CMD_LPORT_ONLINE: 83745039663SJohn Forte case STMF_CMD_LPORT_OFFLINE: 83845039663SJohn Forte case STMF_ACK_LPORT_ONLINE_COMPLETE: 83945039663SJohn Forte case STMF_ACK_LPORT_OFFLINE_COMPLETE: 84045039663SJohn Forte pppt_tgt_sm_ctl(lport, cmd, arg); 84145039663SJohn Forte break; 84245039663SJohn Forte 84345039663SJohn Forte default: 84445039663SJohn Forte ASSERT(0); 84545039663SJohn Forte break; 84645039663SJohn Forte } 84745039663SJohn Forte } 84845039663SJohn Forte 84945039663SJohn Forte pppt_sess_t * 85045039663SJohn Forte pppt_sess_lookup_locked(uint64_t session_id, 85145039663SJohn Forte scsi_devid_desc_t *lport_devid, 85245039663SJohn Forte scsi_devid_desc_t *rport_devid) 85345039663SJohn Forte { 85445039663SJohn Forte pppt_tgt_t *tgt; 85545039663SJohn Forte pppt_sess_t *ps; 85645039663SJohn Forte int lport_cmp; 85745039663SJohn Forte int rport_cmp; 85845039663SJohn Forte 85945039663SJohn Forte ASSERT(mutex_owned(&pppt_global.global_lock)); 86045039663SJohn Forte 86145039663SJohn Forte /* 86245039663SJohn Forte * Look for existing session for this ID 86345039663SJohn Forte */ 86445039663SJohn Forte ps = pppt_sess_lookup_by_id_locked(session_id); 86545039663SJohn Forte if (ps == NULL) { 86645039663SJohn Forte PPPT_INC_STAT(es_sess_lookup_no_session); 86745039663SJohn Forte return (NULL); 86845039663SJohn Forte } 86945039663SJohn Forte 87045039663SJohn Forte tgt = ps->ps_target; 87145039663SJohn Forte 87245039663SJohn Forte mutex_enter(&tgt->target_mutex); 87345039663SJohn Forte 87445039663SJohn Forte /* Validate local/remote port names */ 87545039663SJohn Forte if ((lport_devid->ident_length != 87645039663SJohn Forte tgt->target_stmf_lport->lport_id->ident_length) || 87745039663SJohn Forte (rport_devid->ident_length != 87845039663SJohn Forte ps->ps_stmf_sess->ss_rport_id->ident_length)) { 87945039663SJohn Forte mutex_exit(&tgt->target_mutex); 88045039663SJohn Forte PPPT_INC_STAT(es_sess_lookup_ident_mismatch); 88145039663SJohn Forte return (NULL); 88245039663SJohn Forte } else { 88345039663SJohn Forte lport_cmp = bcmp(lport_devid->ident, 88445039663SJohn Forte tgt->target_stmf_lport->lport_id->ident, 88545039663SJohn Forte lport_devid->ident_length); 88645039663SJohn Forte rport_cmp = bcmp(rport_devid->ident, 88745039663SJohn Forte ps->ps_stmf_sess->ss_rport_id->ident, 88845039663SJohn Forte rport_devid->ident_length); 88945039663SJohn Forte if (lport_cmp || rport_cmp) { 89045039663SJohn Forte mutex_exit(&tgt->target_mutex); 89145039663SJohn Forte PPPT_INC_STAT(es_sess_lookup_ident_mismatch); 89245039663SJohn Forte return (NULL); 89345039663SJohn Forte } 89445039663SJohn Forte 89545039663SJohn Forte if (tgt->target_state != TS_STMF_ONLINE) { 89645039663SJohn Forte mutex_exit(&tgt->target_mutex); 89745039663SJohn Forte PPPT_INC_STAT(es_sess_lookup_bad_tgt_state); 89845039663SJohn Forte return (NULL); 89945039663SJohn Forte } 90045039663SJohn Forte } 90145039663SJohn Forte mutex_exit(&tgt->target_mutex); 90245039663SJohn Forte 90345039663SJohn Forte return (ps); 90445039663SJohn Forte } 90545039663SJohn Forte 90645039663SJohn Forte pppt_sess_t * 90745039663SJohn Forte pppt_sess_lookup_by_id_locked(uint64_t session_id) 90845039663SJohn Forte { 90945039663SJohn Forte pppt_sess_t tmp_ps; 91045039663SJohn Forte pppt_sess_t *ps; 91145039663SJohn Forte 91245039663SJohn Forte ASSERT(mutex_owned(&pppt_global.global_lock)); 91345039663SJohn Forte tmp_ps.ps_session_id = session_id; 91445039663SJohn Forte tmp_ps.ps_closed = 0; 91545039663SJohn Forte ps = avl_find(&pppt_global.global_sess_list, &tmp_ps, NULL); 91645039663SJohn Forte if (ps != NULL) { 91745039663SJohn Forte mutex_enter(&ps->ps_mutex); 91845039663SJohn Forte if (!ps->ps_closed) { 91945039663SJohn Forte ps->ps_refcnt++; 92045039663SJohn Forte mutex_exit(&ps->ps_mutex); 92145039663SJohn Forte return (ps); 92245039663SJohn Forte } 92345039663SJohn Forte mutex_exit(&ps->ps_mutex); 92445039663SJohn Forte } 92545039663SJohn Forte 92645039663SJohn Forte return (NULL); 92745039663SJohn Forte } 92845039663SJohn Forte 92945039663SJohn Forte /* New session */ 93045039663SJohn Forte pppt_sess_t * 93145039663SJohn Forte pppt_sess_lookup_create(scsi_devid_desc_t *lport_devid, 93245039663SJohn Forte scsi_devid_desc_t *rport_devid, uint64_t session_id, 93345039663SJohn Forte stmf_status_t *statusp) 93445039663SJohn Forte { 93545039663SJohn Forte pppt_tgt_t *tgt; 93645039663SJohn Forte pppt_sess_t *ps; 93745039663SJohn Forte stmf_scsi_session_t *ss; 93845039663SJohn Forte pppt_sess_t tmp_ps; 93945039663SJohn Forte stmf_scsi_session_t tmp_ss; 94045039663SJohn Forte *statusp = STMF_SUCCESS; 94145039663SJohn Forte 94245039663SJohn Forte PPPT_GLOBAL_LOCK(); 94345039663SJohn Forte 94445039663SJohn Forte /* 94545039663SJohn Forte * Look for existing session for this ID 94645039663SJohn Forte */ 94745039663SJohn Forte ps = pppt_sess_lookup_locked(session_id, lport_devid, rport_devid); 94845039663SJohn Forte 94945039663SJohn Forte if (ps != NULL) { 95045039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 95145039663SJohn Forte return (ps); 95245039663SJohn Forte } 95345039663SJohn Forte 95445039663SJohn Forte /* 95545039663SJohn Forte * No session with that ID, look for another session corresponding 95645039663SJohn Forte * to the same IT nexus. 95745039663SJohn Forte */ 95845039663SJohn Forte tgt = pppt_tgt_lookup_locked(lport_devid); 95945039663SJohn Forte if (tgt == NULL) { 96045039663SJohn Forte *statusp = STMF_NOT_FOUND; 96145039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 96245039663SJohn Forte return (NULL); 96345039663SJohn Forte } 96445039663SJohn Forte 96545039663SJohn Forte mutex_enter(&tgt->target_mutex); 96645039663SJohn Forte if (tgt->target_state != TS_STMF_ONLINE) { 96745039663SJohn Forte *statusp = STMF_NOT_FOUND; 96845039663SJohn Forte mutex_exit(&tgt->target_mutex); 96945039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 97045039663SJohn Forte /* Can't create session to offline target */ 97145039663SJohn Forte return (NULL); 97245039663SJohn Forte } 97345039663SJohn Forte 97445039663SJohn Forte bzero(&tmp_ps, sizeof (tmp_ps)); 97545039663SJohn Forte bzero(&tmp_ss, sizeof (tmp_ss)); 97645039663SJohn Forte tmp_ps.ps_stmf_sess = &tmp_ss; 97745039663SJohn Forte tmp_ss.ss_rport_id = rport_devid; 97845039663SJohn Forte 97945039663SJohn Forte /* 98045039663SJohn Forte * Look for an existing session on this IT nexus 98145039663SJohn Forte */ 98245039663SJohn Forte ps = avl_find(&tgt->target_sess_list, &tmp_ps, NULL); 98345039663SJohn Forte 98445039663SJohn Forte if (ps != NULL) { 98545039663SJohn Forte /* 98645039663SJohn Forte * Now check the session ID. It should not match because if 98745039663SJohn Forte * it did we would have found it on the global session list. 98845039663SJohn Forte * If the session ID in the command is higher than the existing 98945039663SJohn Forte * session ID then we need to tear down the existing session. 99045039663SJohn Forte */ 99145039663SJohn Forte mutex_enter(&ps->ps_mutex); 99245039663SJohn Forte ASSERT(ps->ps_session_id != session_id); 99345039663SJohn Forte if (ps->ps_session_id > session_id) { 99445039663SJohn Forte /* Invalid session ID */ 99545039663SJohn Forte mutex_exit(&ps->ps_mutex); 99645039663SJohn Forte mutex_exit(&tgt->target_mutex); 99745039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 99845039663SJohn Forte *statusp = STMF_INVALID_ARG; 99945039663SJohn Forte return (NULL); 100045039663SJohn Forte } else { 100145039663SJohn Forte /* Existing session needs to be invalidated */ 100245039663SJohn Forte if (!ps->ps_closed) { 100345039663SJohn Forte pppt_sess_close_locked(ps); 100445039663SJohn Forte } 100545039663SJohn Forte } 100645039663SJohn Forte mutex_exit(&ps->ps_mutex); 100745039663SJohn Forte 100845039663SJohn Forte /* Fallthrough and create new session */ 100945039663SJohn Forte } 101045039663SJohn Forte 101145039663SJohn Forte /* 101245039663SJohn Forte * Allocate and fill in pppt_session_t with the appropriate data 101345039663SJohn Forte * for the protocol. 101445039663SJohn Forte */ 101545039663SJohn Forte ps = kmem_zalloc(sizeof (*ps), KM_SLEEP); 101645039663SJohn Forte 101745039663SJohn Forte /* Fill in session fields */ 101845039663SJohn Forte ps->ps_target = tgt; 101945039663SJohn Forte ps->ps_session_id = session_id; 102045039663SJohn Forte 102145039663SJohn Forte ss = stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0, 102245039663SJohn Forte 0); 102345039663SJohn Forte if (ss == NULL) { 102445039663SJohn Forte mutex_exit(&tgt->target_mutex); 102545039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 102645039663SJohn Forte kmem_free(ps, sizeof (*ps)); 102745039663SJohn Forte *statusp = STMF_ALLOC_FAILURE; 102845039663SJohn Forte return (NULL); 102945039663SJohn Forte } 103045039663SJohn Forte 103145039663SJohn Forte ss->ss_rport_id = kmem_zalloc(sizeof (scsi_devid_desc_t) + 103245039663SJohn Forte rport_devid->ident_length + 1, KM_SLEEP); 103345039663SJohn Forte bcopy(rport_devid, ss->ss_rport_id, 103445039663SJohn Forte sizeof (scsi_devid_desc_t) + rport_devid->ident_length + 1); 103545039663SJohn Forte 103645039663SJohn Forte ss->ss_lport = tgt->target_stmf_lport; 103745039663SJohn Forte 103845039663SJohn Forte if (stmf_register_scsi_session(tgt->target_stmf_lport, ss) != 103945039663SJohn Forte STMF_SUCCESS) { 104045039663SJohn Forte mutex_exit(&tgt->target_mutex); 104145039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 104245039663SJohn Forte kmem_free(ss->ss_rport_id, 104345039663SJohn Forte sizeof (scsi_devid_desc_t) + 104445039663SJohn Forte rport_devid->ident_length + 1); 104545039663SJohn Forte stmf_free(ss); 104645039663SJohn Forte kmem_free(ps, sizeof (*ps)); 104745039663SJohn Forte *statusp = STMF_TARGET_FAILURE; 104845039663SJohn Forte return (NULL); 104945039663SJohn Forte } 105045039663SJohn Forte 105145039663SJohn Forte ss->ss_port_private = ps; 105245039663SJohn Forte mutex_init(&ps->ps_mutex, NULL, MUTEX_DEFAULT, NULL); 105345039663SJohn Forte cv_init(&ps->ps_cv, NULL, CV_DEFAULT, NULL); 105445039663SJohn Forte avl_create(&ps->ps_task_list, pppt_task_avl_compare, 105545039663SJohn Forte sizeof (pppt_task_t), offsetof(pppt_task_t, pt_sess_ln)); 105645039663SJohn Forte ps->ps_refcnt = 1; 105745039663SJohn Forte ps->ps_stmf_sess = ss; 105845039663SJohn Forte avl_add(&tgt->target_sess_list, ps); 105945039663SJohn Forte avl_add(&pppt_global.global_sess_list, ps); 106045039663SJohn Forte mutex_exit(&tgt->target_mutex); 106145039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 1062*e617f214Speter dunlap stmf_trace("pppt", "New session %p", (void *)ps); 106345039663SJohn Forte 106445039663SJohn Forte return (ps); 106545039663SJohn Forte } 106645039663SJohn Forte 106745039663SJohn Forte void 106845039663SJohn Forte pppt_sess_rele(pppt_sess_t *ps) 106945039663SJohn Forte { 107045039663SJohn Forte mutex_enter(&ps->ps_mutex); 107145039663SJohn Forte pppt_sess_rele_locked(ps); 107245039663SJohn Forte mutex_exit(&ps->ps_mutex); 107345039663SJohn Forte } 107445039663SJohn Forte 107545039663SJohn Forte void 107645039663SJohn Forte pppt_sess_rele_locked(pppt_sess_t *ps) 107745039663SJohn Forte { 107845039663SJohn Forte ASSERT(mutex_owned(&ps->ps_mutex)); 107945039663SJohn Forte ps->ps_refcnt--; 108045039663SJohn Forte if (ps->ps_refcnt == 0) { 108145039663SJohn Forte cv_signal(&ps->ps_cv); 108245039663SJohn Forte } 108345039663SJohn Forte } 108445039663SJohn Forte 108545039663SJohn Forte static void pppt_sess_destroy_task(void *ps_void) 108645039663SJohn Forte { 108745039663SJohn Forte pppt_sess_t *ps = ps_void; 108845039663SJohn Forte stmf_scsi_session_t *ss; 108945039663SJohn Forte 1090*e617f214Speter dunlap stmf_trace("pppt", "Session destroy task %p", (void *)ps); 109145039663SJohn Forte 109245039663SJohn Forte ss = ps->ps_stmf_sess; 109345039663SJohn Forte mutex_enter(&ps->ps_mutex); 109445039663SJohn Forte stmf_deregister_scsi_session(ss->ss_lport, ss); 109545039663SJohn Forte kmem_free(ss->ss_rport_id, 109645039663SJohn Forte sizeof (scsi_devid_desc_t) + 109745039663SJohn Forte ss->ss_rport_id->ident_length + 1); 109845039663SJohn Forte avl_destroy(&ps->ps_task_list); 109945039663SJohn Forte mutex_exit(&ps->ps_mutex); 110045039663SJohn Forte cv_destroy(&ps->ps_cv); 110145039663SJohn Forte mutex_destroy(&ps->ps_mutex); 110245039663SJohn Forte stmf_free(ps->ps_stmf_sess); 110345039663SJohn Forte kmem_free(ps, sizeof (*ps)); 110445039663SJohn Forte 1105*e617f214Speter dunlap stmf_trace("pppt", "Session destroy task complete %p", (void *)ps); 110645039663SJohn Forte } 110745039663SJohn Forte 110845039663SJohn Forte int 110945039663SJohn Forte pppt_sess_avl_compare_by_id(const void *void_sess1, const void *void_sess2) 111045039663SJohn Forte { 111145039663SJohn Forte const pppt_sess_t *psess1 = void_sess1; 111245039663SJohn Forte const pppt_sess_t *psess2 = void_sess2; 111345039663SJohn Forte 111445039663SJohn Forte if (psess1->ps_session_id < psess2->ps_session_id) 111545039663SJohn Forte return (-1); 111645039663SJohn Forte else if (psess1->ps_session_id > psess2->ps_session_id) 111745039663SJohn Forte return (1); 111845039663SJohn Forte 111945039663SJohn Forte /* Allow multiple duplicate sessions if one is closed */ 112045039663SJohn Forte ASSERT(!(psess1->ps_closed && psess2->ps_closed)); 112145039663SJohn Forte if (psess1->ps_closed) 112245039663SJohn Forte return (-1); 112345039663SJohn Forte else if (psess2->ps_closed) 112445039663SJohn Forte return (1); 112545039663SJohn Forte 112645039663SJohn Forte return (0); 112745039663SJohn Forte } 112845039663SJohn Forte 112945039663SJohn Forte int 113045039663SJohn Forte pppt_sess_avl_compare_by_name(const void *void_sess1, const void *void_sess2) 113145039663SJohn Forte { 113245039663SJohn Forte const pppt_sess_t *psess1 = void_sess1; 113345039663SJohn Forte const pppt_sess_t *psess2 = void_sess2; 113445039663SJohn Forte int result; 113545039663SJohn Forte 113645039663SJohn Forte /* Sort by code set then ident */ 113745039663SJohn Forte if (psess1->ps_stmf_sess->ss_rport_id->code_set < 113845039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->code_set) { 113945039663SJohn Forte return (-1); 114045039663SJohn Forte } else if (psess1->ps_stmf_sess->ss_rport_id->code_set > 114145039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->code_set) { 114245039663SJohn Forte return (1); 114345039663SJohn Forte } 114445039663SJohn Forte 114545039663SJohn Forte /* Next by ident length */ 114645039663SJohn Forte if (psess1->ps_stmf_sess->ss_rport_id->ident_length < 114745039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->ident_length) { 114845039663SJohn Forte return (-1); 114945039663SJohn Forte } else if (psess1->ps_stmf_sess->ss_rport_id->ident_length > 115045039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->ident_length) { 115145039663SJohn Forte return (1); 115245039663SJohn Forte } 115345039663SJohn Forte 115445039663SJohn Forte /* Code set and ident length both match, now compare idents */ 115545039663SJohn Forte result = memcmp(psess1->ps_stmf_sess->ss_rport_id->ident, 115645039663SJohn Forte psess2->ps_stmf_sess->ss_rport_id->ident, 115745039663SJohn Forte psess1->ps_stmf_sess->ss_rport_id->ident_length); 115845039663SJohn Forte 115945039663SJohn Forte if (result < 0) { 116045039663SJohn Forte return (-1); 116145039663SJohn Forte } else if (result > 0) { 116245039663SJohn Forte return (1); 116345039663SJohn Forte } 116445039663SJohn Forte 116545039663SJohn Forte return (0); 116645039663SJohn Forte } 116745039663SJohn Forte 116845039663SJohn Forte void 116945039663SJohn Forte pppt_sess_close_locked(pppt_sess_t *ps) 117045039663SJohn Forte { 117145039663SJohn Forte pppt_tgt_t *tgt = ps->ps_target; 117245039663SJohn Forte pppt_task_t *ptask; 117345039663SJohn Forte 1174*e617f214Speter dunlap stmf_trace("pppt", "Session close %p", (void *)ps); 117545039663SJohn Forte 117645039663SJohn Forte ASSERT(mutex_owned(&pppt_global.global_lock)); 117745039663SJohn Forte ASSERT(mutex_owned(&tgt->target_mutex)); 117845039663SJohn Forte ASSERT(mutex_owned(&ps->ps_mutex)); 117945039663SJohn Forte ASSERT(!ps->ps_closed); /* Caller should ensure session is not closed */ 118045039663SJohn Forte 118145039663SJohn Forte ps->ps_closed = B_TRUE; 118245039663SJohn Forte for (ptask = avl_first(&ps->ps_task_list); ptask != NULL; 118345039663SJohn Forte ptask = AVL_NEXT(&ps->ps_task_list, ptask)) { 118445039663SJohn Forte mutex_enter(&ptask->pt_mutex); 118545039663SJohn Forte if (ptask->pt_state == PTS_ACTIVE) { 118645039663SJohn Forte stmf_abort(STMF_QUEUE_TASK_ABORT, ptask->pt_stmf_task, 118745039663SJohn Forte STMF_ABORTED, NULL); 118845039663SJohn Forte } 118945039663SJohn Forte mutex_exit(&ptask->pt_mutex); 119045039663SJohn Forte } 119145039663SJohn Forte 119245039663SJohn Forte /* 119345039663SJohn Forte * Now that all the tasks are aborting the session refcnt should 119445039663SJohn Forte * go to 0. 119545039663SJohn Forte */ 119645039663SJohn Forte while (ps->ps_refcnt != 0) { 119745039663SJohn Forte cv_wait(&ps->ps_cv, &ps->ps_mutex); 119845039663SJohn Forte } 119945039663SJohn Forte 120045039663SJohn Forte avl_remove(&tgt->target_sess_list, ps); 120145039663SJohn Forte avl_remove(&pppt_global.global_sess_list, ps); 120245039663SJohn Forte (void) taskq_dispatch(pppt_global.global_sess_taskq, 120345039663SJohn Forte &pppt_sess_destroy_task, ps, KM_SLEEP); 120445039663SJohn Forte 1205*e617f214Speter dunlap stmf_trace("pppt", "Session close complete %p", (void *)ps); 120645039663SJohn Forte } 120745039663SJohn Forte 120845039663SJohn Forte pppt_task_t * 120945039663SJohn Forte pppt_task_alloc(void) 121045039663SJohn Forte { 121145039663SJohn Forte pppt_task_t *ptask; 121245039663SJohn Forte pppt_buf_t *immed_pbuf; 121345039663SJohn Forte 121445039663SJohn Forte ptask = kmem_alloc(sizeof (pppt_task_t) + sizeof (pppt_buf_t) + 121545039663SJohn Forte sizeof (stmf_data_buf_t), KM_NOSLEEP); 121645039663SJohn Forte if (ptask != NULL) { 121745039663SJohn Forte ptask->pt_state = PTS_INIT; 121845039663SJohn Forte ptask->pt_read_buf = NULL; 121945039663SJohn Forte ptask->pt_read_xfer_msgid = 0; 122045039663SJohn Forte cv_init(&ptask->pt_cv, NULL, CV_DRIVER, NULL); 122145039663SJohn Forte mutex_init(&ptask->pt_mutex, NULL, MUTEX_DRIVER, NULL); 122245039663SJohn Forte immed_pbuf = (pppt_buf_t *)(ptask + 1); 122345039663SJohn Forte bzero(immed_pbuf, sizeof (*immed_pbuf)); 122445039663SJohn Forte immed_pbuf->pbuf_is_immed = B_TRUE; 122545039663SJohn Forte immed_pbuf->pbuf_stmf_buf = (stmf_data_buf_t *)(immed_pbuf + 1); 122645039663SJohn Forte 122745039663SJohn Forte bzero(immed_pbuf->pbuf_stmf_buf, sizeof (stmf_data_buf_t)); 122845039663SJohn Forte immed_pbuf->pbuf_stmf_buf->db_port_private = immed_pbuf; 122945039663SJohn Forte immed_pbuf->pbuf_stmf_buf->db_sglist_length = 1; 123045039663SJohn Forte immed_pbuf->pbuf_stmf_buf->db_flags = DB_DIRECTION_FROM_RPORT | 123145039663SJohn Forte DB_DONT_CACHE; 123245039663SJohn Forte ptask->pt_immed_data = immed_pbuf; 123345039663SJohn Forte } 123445039663SJohn Forte 123545039663SJohn Forte return (ptask); 123645039663SJohn Forte 123745039663SJohn Forte } 123845039663SJohn Forte 123945039663SJohn Forte void 124045039663SJohn Forte pppt_task_free(pppt_task_t *ptask) 124145039663SJohn Forte { 124245039663SJohn Forte mutex_enter(&ptask->pt_mutex); 124345039663SJohn Forte mutex_destroy(&ptask->pt_mutex); 124445039663SJohn Forte cv_destroy(&ptask->pt_cv); 124545039663SJohn Forte kmem_free(ptask, sizeof (pppt_task_t) + sizeof (pppt_buf_t) + 124645039663SJohn Forte sizeof (stmf_data_buf_t)); 124745039663SJohn Forte } 124845039663SJohn Forte 124945039663SJohn Forte pppt_status_t 125045039663SJohn Forte pppt_task_start(pppt_task_t *ptask) 125145039663SJohn Forte { 125245039663SJohn Forte avl_index_t where; 125345039663SJohn Forte 125445039663SJohn Forte ASSERT(ptask->pt_state == PTS_INIT); 125545039663SJohn Forte 125645039663SJohn Forte mutex_enter(&ptask->pt_sess->ps_mutex); 125745039663SJohn Forte mutex_enter(&ptask->pt_mutex); 125845039663SJohn Forte if (avl_find(&ptask->pt_sess->ps_task_list, ptask, &where) == NULL) { 125945039663SJohn Forte pppt_task_update_state(ptask, PTS_ACTIVE); 126045039663SJohn Forte avl_insert(&ptask->pt_sess->ps_task_list, ptask, where); 126145039663SJohn Forte mutex_exit(&ptask->pt_mutex); 126245039663SJohn Forte mutex_exit(&ptask->pt_sess->ps_mutex); 126345039663SJohn Forte return (PPPT_STATUS_SUCCESS); 126445039663SJohn Forte } 126545039663SJohn Forte mutex_exit(&ptask->pt_mutex); 126645039663SJohn Forte mutex_exit(&ptask->pt_sess->ps_mutex); 126745039663SJohn Forte 126845039663SJohn Forte return (PPPT_STATUS_FAIL); 126945039663SJohn Forte } 127045039663SJohn Forte 127145039663SJohn Forte pppt_status_t 127245039663SJohn Forte pppt_task_done(pppt_task_t *ptask) 127345039663SJohn Forte { 127445039663SJohn Forte pppt_status_t pppt_status = PPPT_STATUS_SUCCESS; 127545039663SJohn Forte boolean_t remove = B_FALSE; 127645039663SJohn Forte 127745039663SJohn Forte mutex_enter(&ptask->pt_mutex); 127845039663SJohn Forte 127945039663SJohn Forte switch (ptask->pt_state) { 128045039663SJohn Forte case PTS_ACTIVE: 128145039663SJohn Forte remove = B_TRUE; 128245039663SJohn Forte pppt_task_update_state(ptask, PTS_DONE); 128345039663SJohn Forte break; 128445039663SJohn Forte case PTS_ABORTED: 128545039663SJohn Forte pppt_status = PPPT_STATUS_ABORTED; 128645039663SJohn Forte break; 128745039663SJohn Forte case PTS_DONE: 128845039663SJohn Forte /* Repeat calls are OK. Do nothing, return success */ 128945039663SJohn Forte break; 129045039663SJohn Forte default: 129145039663SJohn Forte ASSERT(0); 129245039663SJohn Forte } 129345039663SJohn Forte 129445039663SJohn Forte mutex_exit(&ptask->pt_mutex); 129545039663SJohn Forte 129645039663SJohn Forte if (remove) { 129745039663SJohn Forte mutex_enter(&ptask->pt_sess->ps_mutex); 129845039663SJohn Forte avl_remove(&ptask->pt_sess->ps_task_list, ptask); 129945039663SJohn Forte mutex_exit(&ptask->pt_sess->ps_mutex); 130045039663SJohn Forte } 130145039663SJohn Forte 130245039663SJohn Forte return (pppt_status); 130345039663SJohn Forte } 130445039663SJohn Forte 130545039663SJohn Forte void 130645039663SJohn Forte pppt_task_sent_status(pppt_task_t *ptask) 130745039663SJohn Forte { 130845039663SJohn Forte /* 130945039663SJohn Forte * If STMF tries to abort a task after the task state changed to 131045039663SJohn Forte * PTS_DONE (meaning all task processing is complete from 131145039663SJohn Forte * the port provider perspective) then we return STMF_BUSY 131245039663SJohn Forte * from pppt_lport_abort. STMF will return after a short interval 131345039663SJohn Forte * but our calls to stmf_send_status_done will be ignored since 131445039663SJohn Forte * STMF is aborting the task. That's where this state comes in. 131545039663SJohn Forte * This state essentially says we are calling stmf_send_status_done 131645039663SJohn Forte * so we will not be touching the task again. The next time 131745039663SJohn Forte * STMF calls pppt_lport_abort we will return a success full 131845039663SJohn Forte * status and the abort will succeed. 131945039663SJohn Forte */ 132045039663SJohn Forte mutex_enter(&ptask->pt_mutex); 132145039663SJohn Forte pppt_task_update_state(ptask, PTS_SENT_STATUS); 132245039663SJohn Forte mutex_exit(&ptask->pt_mutex); 132345039663SJohn Forte } 132445039663SJohn Forte 132545039663SJohn Forte pppt_task_t * 132645039663SJohn Forte pppt_task_lookup(stmf_ic_msgid_t msgid) 132745039663SJohn Forte { 132845039663SJohn Forte pppt_tgt_t *tgt; 132945039663SJohn Forte pppt_sess_t *sess; 133045039663SJohn Forte pppt_task_t lookup_task; 133145039663SJohn Forte pppt_task_t *result; 133245039663SJohn Forte 133345039663SJohn Forte bzero(&lookup_task, sizeof (lookup_task)); 133445039663SJohn Forte lookup_task.pt_task_id = msgid; 133545039663SJohn Forte PPPT_GLOBAL_LOCK(); 133645039663SJohn Forte for (tgt = avl_first(&pppt_global.global_target_list); tgt != NULL; 133745039663SJohn Forte tgt = AVL_NEXT(&pppt_global.global_target_list, tgt)) { 133845039663SJohn Forte 133945039663SJohn Forte mutex_enter(&tgt->target_mutex); 134045039663SJohn Forte for (sess = avl_first(&tgt->target_sess_list); sess != NULL; 134145039663SJohn Forte sess = AVL_NEXT(&tgt->target_sess_list, sess)) { 134245039663SJohn Forte mutex_enter(&sess->ps_mutex); 134345039663SJohn Forte if ((result = avl_find(&sess->ps_task_list, 134445039663SJohn Forte &lookup_task, NULL)) != NULL) { 134545039663SJohn Forte if (pppt_task_hold(result) != 134645039663SJohn Forte PPPT_STATUS_SUCCESS) { 134745039663SJohn Forte result = NULL; 134845039663SJohn Forte } 134945039663SJohn Forte mutex_exit(&sess->ps_mutex); 135045039663SJohn Forte mutex_exit(&tgt->target_mutex); 135145039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 135245039663SJohn Forte return (result); 135345039663SJohn Forte } 135445039663SJohn Forte mutex_exit(&sess->ps_mutex); 135545039663SJohn Forte } 135645039663SJohn Forte mutex_exit(&tgt->target_mutex); 135745039663SJohn Forte } 135845039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 135945039663SJohn Forte 136045039663SJohn Forte return (NULL); 136145039663SJohn Forte } 136245039663SJohn Forte 136345039663SJohn Forte static int 136445039663SJohn Forte pppt_task_avl_compare(const void *void_task1, const void *void_task2) 136545039663SJohn Forte { 136645039663SJohn Forte const pppt_task_t *ptask1 = void_task1; 136745039663SJohn Forte const pppt_task_t *ptask2 = void_task2; 136845039663SJohn Forte 136945039663SJohn Forte if (ptask1->pt_task_id < ptask2->pt_task_id) 137045039663SJohn Forte return (-1); 137145039663SJohn Forte else if (ptask1->pt_task_id > ptask2->pt_task_id) 137245039663SJohn Forte return (1); 137345039663SJohn Forte 137445039663SJohn Forte return (0); 137545039663SJohn Forte } 137645039663SJohn Forte 137745039663SJohn Forte static pppt_status_t 137845039663SJohn Forte pppt_task_try_abort(pppt_task_t *ptask) 137945039663SJohn Forte { 138045039663SJohn Forte boolean_t remove = B_FALSE; 138145039663SJohn Forte pppt_status_t pppt_status = PPPT_STATUS_SUCCESS; 138245039663SJohn Forte 138345039663SJohn Forte mutex_enter(&ptask->pt_mutex); 138445039663SJohn Forte 138545039663SJohn Forte switch (ptask->pt_state) { 138645039663SJohn Forte case PTS_ACTIVE: 138745039663SJohn Forte remove = B_TRUE; 138845039663SJohn Forte pppt_task_update_state(ptask, PTS_ABORTED); 138945039663SJohn Forte break; 139045039663SJohn Forte case PTS_DONE: 139145039663SJohn Forte pppt_status = PPPT_STATUS_DONE; 139245039663SJohn Forte break; 139345039663SJohn Forte case PTS_SENT_STATUS: 139445039663SJohn Forte /* 139545039663SJohn Forte * Already removed so leave remove set to B_FALSE 139645039663SJohn Forte * and leave status set to PPPT_STATUS_SUCCESS. 139745039663SJohn Forte */ 139845039663SJohn Forte pppt_task_update_state(ptask, PTS_ABORTED); 139945039663SJohn Forte break; 140045039663SJohn Forte case PTS_ABORTED: 140145039663SJohn Forte break; 140245039663SJohn Forte default: 140345039663SJohn Forte ASSERT(0); 140445039663SJohn Forte } 140545039663SJohn Forte 140645039663SJohn Forte mutex_exit(&ptask->pt_mutex); 140745039663SJohn Forte 140845039663SJohn Forte if (remove) { 140945039663SJohn Forte mutex_enter(&ptask->pt_sess->ps_mutex); 141045039663SJohn Forte avl_remove(&ptask->pt_sess->ps_task_list, ptask); 141145039663SJohn Forte mutex_exit(&ptask->pt_sess->ps_mutex); 141245039663SJohn Forte } 141345039663SJohn Forte 141445039663SJohn Forte return (pppt_status); 141545039663SJohn Forte } 141645039663SJohn Forte 141745039663SJohn Forte static pppt_status_t 141845039663SJohn Forte pppt_task_hold(pppt_task_t *ptask) 141945039663SJohn Forte { 142045039663SJohn Forte pppt_status_t pppt_status = PPPT_STATUS_SUCCESS; 142145039663SJohn Forte 142245039663SJohn Forte mutex_enter(&ptask->pt_mutex); 142345039663SJohn Forte if (ptask->pt_state == PTS_ACTIVE) { 142445039663SJohn Forte ptask->pt_refcnt++; 142545039663SJohn Forte } else { 142645039663SJohn Forte pppt_status = PPPT_STATUS_FAIL; 142745039663SJohn Forte } 142845039663SJohn Forte mutex_exit(&ptask->pt_mutex); 142945039663SJohn Forte 143045039663SJohn Forte return (pppt_status); 143145039663SJohn Forte } 143245039663SJohn Forte 143345039663SJohn Forte static void 143445039663SJohn Forte pppt_task_rele(pppt_task_t *ptask) 143545039663SJohn Forte { 143645039663SJohn Forte mutex_enter(&ptask->pt_mutex); 143745039663SJohn Forte ptask->pt_refcnt--; 143845039663SJohn Forte cv_signal(&ptask->pt_cv); 143945039663SJohn Forte mutex_exit(&ptask->pt_mutex); 144045039663SJohn Forte } 144145039663SJohn Forte 144245039663SJohn Forte static void 144345039663SJohn Forte pppt_task_update_state(pppt_task_t *ptask, 144445039663SJohn Forte pppt_task_state_t new_state) 144545039663SJohn Forte { 144645039663SJohn Forte PPPT_LOG(CE_NOTE, "task %p %d -> %d", (void *)ptask, 144745039663SJohn Forte ptask->pt_state, new_state); 144845039663SJohn Forte 144945039663SJohn Forte ASSERT(mutex_owned(&ptask->pt_mutex)); 145045039663SJohn Forte ptask->pt_state = new_state; 145145039663SJohn Forte cv_signal(&ptask->pt_cv); 145245039663SJohn Forte } 1453