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