xref: /onnv-gate/usr/src/uts/common/io/comstar/port/pppt/pppt.c (revision 12750:f559965e4a2f)
110725SJohn.Forte@Sun.COM /*
210725SJohn.Forte@Sun.COM  * CDDL HEADER START
310725SJohn.Forte@Sun.COM  *
410725SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
510725SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
610725SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
710725SJohn.Forte@Sun.COM  *
810725SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910725SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010725SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
1110725SJohn.Forte@Sun.COM  * and limitations under the License.
1210725SJohn.Forte@Sun.COM  *
1310725SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410725SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510725SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610725SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710725SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810725SJohn.Forte@Sun.COM  *
1910725SJohn.Forte@Sun.COM  * CDDL HEADER END
2010725SJohn.Forte@Sun.COM  */
2110725SJohn.Forte@Sun.COM /*
2212571SViswanathan.Kannappan@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2310725SJohn.Forte@Sun.COM  */
2410725SJohn.Forte@Sun.COM 
2510725SJohn.Forte@Sun.COM #include <sys/cpuvar.h>
2610725SJohn.Forte@Sun.COM #include <sys/types.h>
2710725SJohn.Forte@Sun.COM #include <sys/conf.h>
2810725SJohn.Forte@Sun.COM #include <sys/stat.h>
2910725SJohn.Forte@Sun.COM #include <sys/file.h>
3010725SJohn.Forte@Sun.COM #include <sys/ddi.h>
3110725SJohn.Forte@Sun.COM #include <sys/sunddi.h>
3210725SJohn.Forte@Sun.COM #include <sys/modctl.h>
3310725SJohn.Forte@Sun.COM #include <sys/sysmacros.h>
3410725SJohn.Forte@Sun.COM #include <sys/nvpair.h>
3510725SJohn.Forte@Sun.COM #include <sys/door.h>
3611132SPeter.Dunlap@Sun.COM #include <sys/sdt.h>
3710725SJohn.Forte@Sun.COM 
3810725SJohn.Forte@Sun.COM #include <sys/stmf.h>
3910725SJohn.Forte@Sun.COM #include <sys/stmf_ioctl.h>
4010725SJohn.Forte@Sun.COM #include <sys/pppt_ioctl.h>
4110725SJohn.Forte@Sun.COM #include <sys/portif.h>
4212571SViswanathan.Kannappan@Sun.COM 
4312571SViswanathan.Kannappan@Sun.COM #include "pppt.h"
4410725SJohn.Forte@Sun.COM 
4510725SJohn.Forte@Sun.COM #define	PPPT_VERSION		BUILD_DATE "-1.18dev"
4610725SJohn.Forte@Sun.COM #define	PPPT_NAME_VERSION	"COMSTAR PPPT v" PPPT_VERSION
4710725SJohn.Forte@Sun.COM 
4810725SJohn.Forte@Sun.COM /*
4910725SJohn.Forte@Sun.COM  * DDI entry points.
5010725SJohn.Forte@Sun.COM  */
5110725SJohn.Forte@Sun.COM static int pppt_drv_attach(dev_info_t *, ddi_attach_cmd_t);
5210725SJohn.Forte@Sun.COM static int pppt_drv_detach(dev_info_t *, ddi_detach_cmd_t);
5310725SJohn.Forte@Sun.COM static int pppt_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
5410725SJohn.Forte@Sun.COM static int pppt_drv_open(dev_t *, int, int, cred_t *);
5510725SJohn.Forte@Sun.COM static int pppt_drv_close(dev_t, int, int, cred_t *);
5610725SJohn.Forte@Sun.COM static boolean_t pppt_drv_busy(void);
5710725SJohn.Forte@Sun.COM static int pppt_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
5810725SJohn.Forte@Sun.COM 
5910725SJohn.Forte@Sun.COM extern pppt_status_t pppt_ic_so_enable(boolean_t);
6010725SJohn.Forte@Sun.COM extern void pppt_ic_so_disable();
6110725SJohn.Forte@Sun.COM extern void stmf_ic_rx_msg(char *, size_t);
6210725SJohn.Forte@Sun.COM 
6310725SJohn.Forte@Sun.COM extern struct mod_ops mod_miscops;
6410725SJohn.Forte@Sun.COM 
6510725SJohn.Forte@Sun.COM static struct cb_ops pppt_cb_ops = {
6610725SJohn.Forte@Sun.COM 	pppt_drv_open,	/* cb_open */
6710725SJohn.Forte@Sun.COM 	pppt_drv_close,	/* cb_close */
6810725SJohn.Forte@Sun.COM 	nodev,			/* cb_strategy */
6910725SJohn.Forte@Sun.COM 	nodev,			/* cb_print */
7010725SJohn.Forte@Sun.COM 	nodev,			/* cb_dump */
7110725SJohn.Forte@Sun.COM 	nodev,			/* cb_read */
7210725SJohn.Forte@Sun.COM 	nodev,			/* cb_write */
7310725SJohn.Forte@Sun.COM 	pppt_drv_ioctl,		/* cb_ioctl */
7410725SJohn.Forte@Sun.COM 	nodev,			/* cb_devmap */
7510725SJohn.Forte@Sun.COM 	nodev,			/* cb_mmap */
7610725SJohn.Forte@Sun.COM 	nodev,			/* cb_segmap */
7710725SJohn.Forte@Sun.COM 	nochpoll,		/* cb_chpoll */
7810725SJohn.Forte@Sun.COM 	ddi_prop_op,		/* cb_prop_op */
7910725SJohn.Forte@Sun.COM 	NULL,			/* cb_streamtab */
8010725SJohn.Forte@Sun.COM 	D_MP,			/* cb_flag */
8110725SJohn.Forte@Sun.COM 	CB_REV,			/* cb_rev */
8210725SJohn.Forte@Sun.COM 	nodev,			/* cb_aread */
8310725SJohn.Forte@Sun.COM 	nodev,			/* cb_awrite */
8410725SJohn.Forte@Sun.COM };
8510725SJohn.Forte@Sun.COM 
8610725SJohn.Forte@Sun.COM static struct dev_ops pppt_dev_ops = {
8710725SJohn.Forte@Sun.COM 	DEVO_REV,		/* devo_rev */
8810725SJohn.Forte@Sun.COM 	0,			/* devo_refcnt */
8910725SJohn.Forte@Sun.COM 	pppt_drv_getinfo,	/* devo_getinfo */
9010725SJohn.Forte@Sun.COM 	nulldev,		/* devo_identify */
9110725SJohn.Forte@Sun.COM 	nulldev,		/* devo_probe */
9210725SJohn.Forte@Sun.COM 	pppt_drv_attach,	/* devo_attach */
9310725SJohn.Forte@Sun.COM 	pppt_drv_detach,	/* devo_detach */
9410725SJohn.Forte@Sun.COM 	nodev,			/* devo_reset */
9510725SJohn.Forte@Sun.COM 	&pppt_cb_ops,		/* devo_cb_ops */
9610725SJohn.Forte@Sun.COM 	NULL,			/* devo_bus_ops */
9710725SJohn.Forte@Sun.COM 	NULL,			/* devo_power */
9810725SJohn.Forte@Sun.COM 	ddi_quiesce_not_needed,	/* quiesce */
9910725SJohn.Forte@Sun.COM };
10010725SJohn.Forte@Sun.COM 
10110725SJohn.Forte@Sun.COM static struct modldrv modldrv = {
10210725SJohn.Forte@Sun.COM 	&mod_driverops,
10310725SJohn.Forte@Sun.COM 	"Proxy Port Provider",
10410725SJohn.Forte@Sun.COM 	&pppt_dev_ops,
10510725SJohn.Forte@Sun.COM };
10610725SJohn.Forte@Sun.COM 
10710725SJohn.Forte@Sun.COM static struct modlinkage modlinkage = {
10810725SJohn.Forte@Sun.COM 	MODREV_1,
10910725SJohn.Forte@Sun.COM 	&modldrv,
11010725SJohn.Forte@Sun.COM 	NULL,
11110725SJohn.Forte@Sun.COM };
11210725SJohn.Forte@Sun.COM 
11310725SJohn.Forte@Sun.COM pppt_global_t pppt_global;
11410725SJohn.Forte@Sun.COM 
11510725SJohn.Forte@Sun.COM int pppt_logging = 0;
11610725SJohn.Forte@Sun.COM 
11710725SJohn.Forte@Sun.COM static int pppt_enable_svc(void);
11810725SJohn.Forte@Sun.COM 
11910725SJohn.Forte@Sun.COM static void pppt_disable_svc(void);
12010725SJohn.Forte@Sun.COM 
12110725SJohn.Forte@Sun.COM static int pppt_task_avl_compare(const void *tgt1, const void *tgt2);
12210725SJohn.Forte@Sun.COM 
12310725SJohn.Forte@Sun.COM static stmf_data_buf_t *pppt_dbuf_alloc(scsi_task_t *task,
12410725SJohn.Forte@Sun.COM     uint32_t size, uint32_t *pminsize, uint32_t flags);
12510725SJohn.Forte@Sun.COM 
12610725SJohn.Forte@Sun.COM static void pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf);
12710725SJohn.Forte@Sun.COM 
12810725SJohn.Forte@Sun.COM static void pppt_sess_destroy_task(void *ps_void);
12910725SJohn.Forte@Sun.COM 
13010725SJohn.Forte@Sun.COM static void pppt_task_sent_status(pppt_task_t *ptask);
13110725SJohn.Forte@Sun.COM 
13210725SJohn.Forte@Sun.COM static pppt_status_t pppt_task_try_abort(pppt_task_t *ptask);
13310725SJohn.Forte@Sun.COM 
13410725SJohn.Forte@Sun.COM static pppt_status_t pppt_task_hold(pppt_task_t *ptask);
13510725SJohn.Forte@Sun.COM 
13610725SJohn.Forte@Sun.COM static void pppt_task_rele(pppt_task_t *ptask);
13710725SJohn.Forte@Sun.COM 
13810725SJohn.Forte@Sun.COM static void pppt_task_update_state(pppt_task_t *ptask,
13910725SJohn.Forte@Sun.COM     pppt_task_state_t new_state);
14010725SJohn.Forte@Sun.COM 
14110725SJohn.Forte@Sun.COM /*
14210725SJohn.Forte@Sun.COM  * Lock order:  global --> target --> session --> task
14310725SJohn.Forte@Sun.COM  */
14410725SJohn.Forte@Sun.COM 
14510725SJohn.Forte@Sun.COM int
_init(void)14610725SJohn.Forte@Sun.COM _init(void)
14710725SJohn.Forte@Sun.COM {
14810725SJohn.Forte@Sun.COM 	int rc;
14910725SJohn.Forte@Sun.COM 
15010725SJohn.Forte@Sun.COM 	mutex_init(&pppt_global.global_lock, NULL, MUTEX_DEFAULT, NULL);
15110725SJohn.Forte@Sun.COM 	mutex_init(&pppt_global.global_door_lock, NULL, MUTEX_DEFAULT, NULL);
15210725SJohn.Forte@Sun.COM 	pppt_global.global_svc_state = PSS_DETACHED;
15310725SJohn.Forte@Sun.COM 
15410725SJohn.Forte@Sun.COM 	if ((rc = mod_install(&modlinkage)) != 0) {
15510725SJohn.Forte@Sun.COM 		mutex_destroy(&pppt_global.global_door_lock);
15610725SJohn.Forte@Sun.COM 		mutex_destroy(&pppt_global.global_lock);
15710725SJohn.Forte@Sun.COM 		return (rc);
15810725SJohn.Forte@Sun.COM 	}
15910725SJohn.Forte@Sun.COM 
16010725SJohn.Forte@Sun.COM 	return (rc);
16110725SJohn.Forte@Sun.COM }
16210725SJohn.Forte@Sun.COM 
16310725SJohn.Forte@Sun.COM int
_info(struct modinfo * modinfop)16410725SJohn.Forte@Sun.COM _info(struct modinfo *modinfop)
16510725SJohn.Forte@Sun.COM {
16610725SJohn.Forte@Sun.COM 	return (mod_info(&modlinkage, modinfop));
16710725SJohn.Forte@Sun.COM }
16810725SJohn.Forte@Sun.COM 
16910725SJohn.Forte@Sun.COM int
_fini(void)17010725SJohn.Forte@Sun.COM _fini(void)
17110725SJohn.Forte@Sun.COM {
17210725SJohn.Forte@Sun.COM 	int rc;
17310725SJohn.Forte@Sun.COM 
17410725SJohn.Forte@Sun.COM 	rc = mod_remove(&modlinkage);
17510725SJohn.Forte@Sun.COM 
17610725SJohn.Forte@Sun.COM 	if (rc == 0) {
17710725SJohn.Forte@Sun.COM 		mutex_destroy(&pppt_global.global_lock);
17810725SJohn.Forte@Sun.COM 		mutex_destroy(&pppt_global.global_door_lock);
17910725SJohn.Forte@Sun.COM 	}
18010725SJohn.Forte@Sun.COM 
18110725SJohn.Forte@Sun.COM 	return (rc);
18210725SJohn.Forte@Sun.COM }
18310725SJohn.Forte@Sun.COM 
18410725SJohn.Forte@Sun.COM /*
18510725SJohn.Forte@Sun.COM  * DDI entry points.
18610725SJohn.Forte@Sun.COM  */
18710725SJohn.Forte@Sun.COM 
18810725SJohn.Forte@Sun.COM /* ARGSUSED */
18910725SJohn.Forte@Sun.COM static int
pppt_drv_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)19010725SJohn.Forte@Sun.COM pppt_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
19110725SJohn.Forte@Sun.COM     void **result)
19210725SJohn.Forte@Sun.COM {
19310725SJohn.Forte@Sun.COM 	ulong_t instance = getminor((dev_t)arg);
19410725SJohn.Forte@Sun.COM 
19510725SJohn.Forte@Sun.COM 	switch (cmd) {
19610725SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
19710725SJohn.Forte@Sun.COM 		*result = pppt_global.global_dip;
19810725SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
19910725SJohn.Forte@Sun.COM 
20010725SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
20110725SJohn.Forte@Sun.COM 		*result = (void *)instance;
20210725SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
20310725SJohn.Forte@Sun.COM 
20410725SJohn.Forte@Sun.COM 	default:
20510725SJohn.Forte@Sun.COM 		break;
20610725SJohn.Forte@Sun.COM 	}
20710725SJohn.Forte@Sun.COM 
20810725SJohn.Forte@Sun.COM 	return (DDI_FAILURE);
20910725SJohn.Forte@Sun.COM }
21010725SJohn.Forte@Sun.COM 
21110725SJohn.Forte@Sun.COM static int
pppt_drv_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)21210725SJohn.Forte@Sun.COM pppt_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
21310725SJohn.Forte@Sun.COM {
21410725SJohn.Forte@Sun.COM 	if (cmd != DDI_ATTACH) {
21510725SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
21610725SJohn.Forte@Sun.COM 	}
21710725SJohn.Forte@Sun.COM 
21810725SJohn.Forte@Sun.COM 	if (ddi_get_instance(dip) != 0) {
21910725SJohn.Forte@Sun.COM 		/* we only allow instance 0 to attach */
22010725SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
22110725SJohn.Forte@Sun.COM 	}
22210725SJohn.Forte@Sun.COM 
22310725SJohn.Forte@Sun.COM 	/* create the minor node */
22410725SJohn.Forte@Sun.COM 	if (ddi_create_minor_node(dip, PPPT_MODNAME, S_IFCHR, 0,
22510725SJohn.Forte@Sun.COM 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
22610725SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "pppt_drv_attach: "
22710725SJohn.Forte@Sun.COM 		    "failed creating minor node");
22810725SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
22910725SJohn.Forte@Sun.COM 	}
23010725SJohn.Forte@Sun.COM 
23110725SJohn.Forte@Sun.COM 	pppt_global.global_svc_state = PSS_DISABLED;
23210725SJohn.Forte@Sun.COM 	pppt_global.global_dip = dip;
23310725SJohn.Forte@Sun.COM 
23410725SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
23510725SJohn.Forte@Sun.COM }
23610725SJohn.Forte@Sun.COM 
23710725SJohn.Forte@Sun.COM /*ARGSUSED*/
23810725SJohn.Forte@Sun.COM static int
pppt_drv_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)23910725SJohn.Forte@Sun.COM pppt_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
24010725SJohn.Forte@Sun.COM {
24110725SJohn.Forte@Sun.COM 	if (cmd != DDI_DETACH)
24210725SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
24310725SJohn.Forte@Sun.COM 
24410725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_LOCK();
24510725SJohn.Forte@Sun.COM 	if (pppt_drv_busy()) {
24610725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_UNLOCK();
24710725SJohn.Forte@Sun.COM 		return (EBUSY);
24810725SJohn.Forte@Sun.COM 	}
24910725SJohn.Forte@Sun.COM 
25010725SJohn.Forte@Sun.COM 	ddi_remove_minor_node(dip, NULL);
25110725SJohn.Forte@Sun.COM 	ddi_prop_remove_all(dip);
25210725SJohn.Forte@Sun.COM 
25310725SJohn.Forte@Sun.COM 	pppt_global.global_svc_state = PSS_DETACHED;
25410725SJohn.Forte@Sun.COM 
25510725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_UNLOCK();
25610725SJohn.Forte@Sun.COM 
25710725SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
25810725SJohn.Forte@Sun.COM }
25910725SJohn.Forte@Sun.COM 
26010725SJohn.Forte@Sun.COM /*ARGSUSED*/
26110725SJohn.Forte@Sun.COM static int
pppt_drv_open(dev_t * devp,int flag,int otyp,cred_t * credp)26210725SJohn.Forte@Sun.COM pppt_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
26310725SJohn.Forte@Sun.COM {
26410725SJohn.Forte@Sun.COM 	int	rc = 0;
26510725SJohn.Forte@Sun.COM 
26610725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_LOCK();
26710725SJohn.Forte@Sun.COM 
26810725SJohn.Forte@Sun.COM 	switch (pppt_global.global_svc_state) {
26910725SJohn.Forte@Sun.COM 	case PSS_DISABLED:
27010725SJohn.Forte@Sun.COM 		pppt_global.global_svc_state = PSS_ENABLING;
27110725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_UNLOCK();
27210725SJohn.Forte@Sun.COM 		rc = pppt_enable_svc();
27310725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_LOCK();
27410725SJohn.Forte@Sun.COM 		if (rc == 0) {
27510725SJohn.Forte@Sun.COM 			pppt_global.global_svc_state = PSS_ENABLED;
27610725SJohn.Forte@Sun.COM 		} else {
27710725SJohn.Forte@Sun.COM 			pppt_global.global_svc_state = PSS_DISABLED;
27810725SJohn.Forte@Sun.COM 		}
27910725SJohn.Forte@Sun.COM 		break;
28010725SJohn.Forte@Sun.COM 	case PSS_DISABLING:
28110725SJohn.Forte@Sun.COM 	case PSS_ENABLING:
28210725SJohn.Forte@Sun.COM 	case PSS_ENABLED:
28310725SJohn.Forte@Sun.COM 		rc = EBUSY;
28410725SJohn.Forte@Sun.COM 		break;
28510725SJohn.Forte@Sun.COM 	default:
28610725SJohn.Forte@Sun.COM 		rc = EFAULT;
28710725SJohn.Forte@Sun.COM 		break;
28810725SJohn.Forte@Sun.COM 	}
28910725SJohn.Forte@Sun.COM 
29010725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_UNLOCK();
29110725SJohn.Forte@Sun.COM 
29210725SJohn.Forte@Sun.COM 	return (rc);
29310725SJohn.Forte@Sun.COM }
29410725SJohn.Forte@Sun.COM 
29510725SJohn.Forte@Sun.COM /* ARGSUSED */
29610725SJohn.Forte@Sun.COM static int
pppt_drv_close(dev_t dev,int flag,int otyp,cred_t * credp)29710725SJohn.Forte@Sun.COM pppt_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
29810725SJohn.Forte@Sun.COM {
29910725SJohn.Forte@Sun.COM 	int rc = 0;
30010725SJohn.Forte@Sun.COM 
30110725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_LOCK();
30210725SJohn.Forte@Sun.COM 
30310725SJohn.Forte@Sun.COM 	switch (pppt_global.global_svc_state) {
30410725SJohn.Forte@Sun.COM 	case PSS_ENABLED:
30510725SJohn.Forte@Sun.COM 		pppt_global.global_svc_state = PSS_DISABLING;
30610725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_UNLOCK();
30710725SJohn.Forte@Sun.COM 		pppt_disable_svc();
30810725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_LOCK();
30910725SJohn.Forte@Sun.COM 		pppt_global.global_svc_state = PSS_DISABLED;
31010725SJohn.Forte@Sun.COM 		/*
31110725SJohn.Forte@Sun.COM 		 * release the door to the daemon
31210725SJohn.Forte@Sun.COM 		 */
31310725SJohn.Forte@Sun.COM 		mutex_enter(&pppt_global.global_door_lock);
31410725SJohn.Forte@Sun.COM 		if (pppt_global.global_door != NULL) {
31510725SJohn.Forte@Sun.COM 			door_ki_rele(pppt_global.global_door);
31610725SJohn.Forte@Sun.COM 			pppt_global.global_door = NULL;
31710725SJohn.Forte@Sun.COM 		}
31810725SJohn.Forte@Sun.COM 		mutex_exit(&pppt_global.global_door_lock);
31910725SJohn.Forte@Sun.COM 		break;
32010725SJohn.Forte@Sun.COM 	default:
32110725SJohn.Forte@Sun.COM 		rc = EFAULT;
32210725SJohn.Forte@Sun.COM 		break;
32310725SJohn.Forte@Sun.COM 	}
32410725SJohn.Forte@Sun.COM 
32510725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_UNLOCK();
32610725SJohn.Forte@Sun.COM 
32710725SJohn.Forte@Sun.COM 	return (rc);
32810725SJohn.Forte@Sun.COM }
32910725SJohn.Forte@Sun.COM 
33010725SJohn.Forte@Sun.COM static boolean_t
pppt_drv_busy(void)33110725SJohn.Forte@Sun.COM pppt_drv_busy(void)
33210725SJohn.Forte@Sun.COM {
33310725SJohn.Forte@Sun.COM 	switch (pppt_global.global_svc_state) {
33410725SJohn.Forte@Sun.COM 	case PSS_DISABLED:
33510725SJohn.Forte@Sun.COM 	case PSS_DETACHED:
33610725SJohn.Forte@Sun.COM 		return (B_FALSE);
33710725SJohn.Forte@Sun.COM 	default:
33810725SJohn.Forte@Sun.COM 		return (B_TRUE);
33910725SJohn.Forte@Sun.COM 	}
34010725SJohn.Forte@Sun.COM 	/* NOTREACHED */
34110725SJohn.Forte@Sun.COM }
34210725SJohn.Forte@Sun.COM 
34310725SJohn.Forte@Sun.COM /* ARGSUSED */
34410725SJohn.Forte@Sun.COM static int
pppt_drv_ioctl(dev_t drv,int cmd,intptr_t argp,int flag,cred_t * cred,int * retval)34510725SJohn.Forte@Sun.COM pppt_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
34610725SJohn.Forte@Sun.COM     int *retval)
34710725SJohn.Forte@Sun.COM {
34810725SJohn.Forte@Sun.COM 	int				rc;
34910725SJohn.Forte@Sun.COM 	void				*buf;
35010725SJohn.Forte@Sun.COM 	size_t				buf_size;
35110725SJohn.Forte@Sun.COM 	pppt_iocdata_t			iocd;
35210725SJohn.Forte@Sun.COM 	door_handle_t			new_handle;
35310725SJohn.Forte@Sun.COM 
35410725SJohn.Forte@Sun.COM 	if (drv_priv(cred) != 0) {
35510725SJohn.Forte@Sun.COM 		return (EPERM);
35610725SJohn.Forte@Sun.COM 	}
35710725SJohn.Forte@Sun.COM 
35810725SJohn.Forte@Sun.COM 	rc = ddi_copyin((void *)argp, &iocd, sizeof (iocd), flag);
35910725SJohn.Forte@Sun.COM 	if (rc)
36010725SJohn.Forte@Sun.COM 		return (EFAULT);
36110725SJohn.Forte@Sun.COM 
36210725SJohn.Forte@Sun.COM 	if (iocd.pppt_version != PPPT_VERSION_1)
36310725SJohn.Forte@Sun.COM 		return (EINVAL);
36410725SJohn.Forte@Sun.COM 
36510725SJohn.Forte@Sun.COM 	switch (cmd) {
36610725SJohn.Forte@Sun.COM 	case PPPT_MESSAGE:
36710725SJohn.Forte@Sun.COM 
36810725SJohn.Forte@Sun.COM 		/* XXX limit buf_size ? */
36910725SJohn.Forte@Sun.COM 		buf_size = (size_t)iocd.pppt_buf_size;
37010725SJohn.Forte@Sun.COM 		buf = kmem_alloc(buf_size, KM_SLEEP);
37110725SJohn.Forte@Sun.COM 		if (buf == NULL)
37210725SJohn.Forte@Sun.COM 			return (ENOMEM);
37310725SJohn.Forte@Sun.COM 
37410725SJohn.Forte@Sun.COM 		rc = ddi_copyin((void *)(unsigned long)iocd.pppt_buf,
37510725SJohn.Forte@Sun.COM 		    buf, buf_size, flag);
37610725SJohn.Forte@Sun.COM 		if (rc) {
37710725SJohn.Forte@Sun.COM 			kmem_free(buf, buf_size);
37810725SJohn.Forte@Sun.COM 			return (EFAULT);
37910725SJohn.Forte@Sun.COM 		}
38010725SJohn.Forte@Sun.COM 
38110725SJohn.Forte@Sun.COM 		stmf_ic_rx_msg(buf, buf_size);
38210725SJohn.Forte@Sun.COM 
38310725SJohn.Forte@Sun.COM 		kmem_free(buf, buf_size);
38410725SJohn.Forte@Sun.COM 		break;
38510725SJohn.Forte@Sun.COM 	case PPPT_INSTALL_DOOR:
38610725SJohn.Forte@Sun.COM 
38710725SJohn.Forte@Sun.COM 		new_handle = door_ki_lookup((int)iocd.pppt_door_fd);
38810725SJohn.Forte@Sun.COM 		if (new_handle == NULL)
38910725SJohn.Forte@Sun.COM 			return (EINVAL);
39010725SJohn.Forte@Sun.COM 
39110725SJohn.Forte@Sun.COM 		mutex_enter(&pppt_global.global_door_lock);
39210725SJohn.Forte@Sun.COM 		ASSERT(pppt_global.global_svc_state == PSS_ENABLED);
39310725SJohn.Forte@Sun.COM 		if (pppt_global.global_door != NULL) {
39410725SJohn.Forte@Sun.COM 			/*
39510725SJohn.Forte@Sun.COM 			 * There can only be one door installed
39610725SJohn.Forte@Sun.COM 			 */
39710725SJohn.Forte@Sun.COM 			mutex_exit(&pppt_global.global_door_lock);
39810725SJohn.Forte@Sun.COM 			door_ki_rele(new_handle);
39910725SJohn.Forte@Sun.COM 			return (EBUSY);
40010725SJohn.Forte@Sun.COM 		}
40110725SJohn.Forte@Sun.COM 		pppt_global.global_door = new_handle;
40210725SJohn.Forte@Sun.COM 		mutex_exit(&pppt_global.global_door_lock);
40310725SJohn.Forte@Sun.COM 		break;
40410725SJohn.Forte@Sun.COM 	}
40510725SJohn.Forte@Sun.COM 
40610725SJohn.Forte@Sun.COM 	return (rc);
40710725SJohn.Forte@Sun.COM }
40810725SJohn.Forte@Sun.COM 
40910725SJohn.Forte@Sun.COM /*
41010725SJohn.Forte@Sun.COM  * pppt_enable_svc
41110725SJohn.Forte@Sun.COM  *
41210725SJohn.Forte@Sun.COM  * registers all the configured targets and target portals with STMF
41310725SJohn.Forte@Sun.COM  */
41410725SJohn.Forte@Sun.COM static int
pppt_enable_svc(void)41510725SJohn.Forte@Sun.COM pppt_enable_svc(void)
41610725SJohn.Forte@Sun.COM {
41710725SJohn.Forte@Sun.COM 	stmf_port_provider_t	*pp;
41810725SJohn.Forte@Sun.COM 	stmf_dbuf_store_t	*dbuf_store;
41910725SJohn.Forte@Sun.COM 	int			rc = 0;
42010725SJohn.Forte@Sun.COM 
42110725SJohn.Forte@Sun.COM 	ASSERT(pppt_global.global_svc_state == PSS_ENABLING);
42210725SJohn.Forte@Sun.COM 
42310725SJohn.Forte@Sun.COM 	/*
42410725SJohn.Forte@Sun.COM 	 * Make sure that can tell if we have partially allocated
42510725SJohn.Forte@Sun.COM 	 * in case we need to exit and tear down anything allocated.
42610725SJohn.Forte@Sun.COM 	 */
42710725SJohn.Forte@Sun.COM 	pppt_global.global_dbuf_store = NULL;
42810725SJohn.Forte@Sun.COM 	pp = NULL;
42910725SJohn.Forte@Sun.COM 	pppt_global.global_pp = NULL;
43010725SJohn.Forte@Sun.COM 	pppt_global.global_dispatch_taskq = NULL;
43110725SJohn.Forte@Sun.COM 	pppt_global.global_sess_taskq = NULL;
43210725SJohn.Forte@Sun.COM 
43310725SJohn.Forte@Sun.COM 	avl_create(&pppt_global.global_target_list,
43410725SJohn.Forte@Sun.COM 	    pppt_tgt_avl_compare, sizeof (pppt_tgt_t),
43510725SJohn.Forte@Sun.COM 	    offsetof(pppt_tgt_t, target_global_ln));
43610725SJohn.Forte@Sun.COM 
43710725SJohn.Forte@Sun.COM 	avl_create(&pppt_global.global_sess_list,
43810725SJohn.Forte@Sun.COM 	    pppt_sess_avl_compare_by_id, sizeof (pppt_sess_t),
43910725SJohn.Forte@Sun.COM 	    offsetof(pppt_sess_t, ps_global_ln));
44010725SJohn.Forte@Sun.COM 
44110725SJohn.Forte@Sun.COM 	/*
44210725SJohn.Forte@Sun.COM 	 * Setup STMF dbuf store.  Tf buffers are associated with a particular
44310725SJohn.Forte@Sun.COM 	 * lport (FC, SRP) then the dbuf_store should stored in the lport
44410725SJohn.Forte@Sun.COM 	 * context, otherwise (iSCSI) the dbuf_store should be global.
44510725SJohn.Forte@Sun.COM 	 */
44610725SJohn.Forte@Sun.COM 	dbuf_store = stmf_alloc(STMF_STRUCT_DBUF_STORE, 0, 0);
44710725SJohn.Forte@Sun.COM 	if (dbuf_store == NULL) {
44810725SJohn.Forte@Sun.COM 		rc = ENOMEM;
44910725SJohn.Forte@Sun.COM 		goto tear_down_and_return;
45010725SJohn.Forte@Sun.COM 	}
45110725SJohn.Forte@Sun.COM 	dbuf_store->ds_alloc_data_buf = pppt_dbuf_alloc;
45210725SJohn.Forte@Sun.COM 	dbuf_store->ds_free_data_buf = pppt_dbuf_free;
45310725SJohn.Forte@Sun.COM 	dbuf_store->ds_port_private = NULL;
45410725SJohn.Forte@Sun.COM 	pppt_global.global_dbuf_store = dbuf_store;
45510725SJohn.Forte@Sun.COM 
45610725SJohn.Forte@Sun.COM 	/* Register port provider */
45710725SJohn.Forte@Sun.COM 	pp = stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0);
45810725SJohn.Forte@Sun.COM 	if (pp == NULL) {
45910725SJohn.Forte@Sun.COM 		rc = ENOMEM;
46010725SJohn.Forte@Sun.COM 		goto tear_down_and_return;
46110725SJohn.Forte@Sun.COM 	}
46210725SJohn.Forte@Sun.COM 
46310725SJohn.Forte@Sun.COM 	pp->pp_portif_rev = PORTIF_REV_1;
46410725SJohn.Forte@Sun.COM 	pp->pp_instance = 0;
46510725SJohn.Forte@Sun.COM 	pp->pp_name = PPPT_MODNAME;
46610725SJohn.Forte@Sun.COM 	pp->pp_cb = NULL;
46710725SJohn.Forte@Sun.COM 
46810725SJohn.Forte@Sun.COM 	pppt_global.global_pp = pp;
46910725SJohn.Forte@Sun.COM 
47010725SJohn.Forte@Sun.COM 	if (stmf_register_port_provider(pp) != STMF_SUCCESS) {
47110725SJohn.Forte@Sun.COM 		rc = EIO;
47210725SJohn.Forte@Sun.COM 		goto tear_down_and_return;
47310725SJohn.Forte@Sun.COM 	}
47410725SJohn.Forte@Sun.COM 
47510725SJohn.Forte@Sun.COM 	pppt_global.global_dispatch_taskq = taskq_create("pppt_dispatch",
47610725SJohn.Forte@Sun.COM 	    1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE);
47710725SJohn.Forte@Sun.COM 
47810725SJohn.Forte@Sun.COM 	pppt_global.global_sess_taskq = taskq_create("pppt_session",
47910725SJohn.Forte@Sun.COM 	    1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE);
48010725SJohn.Forte@Sun.COM 
48110725SJohn.Forte@Sun.COM 	return (0);
48210725SJohn.Forte@Sun.COM 
48310725SJohn.Forte@Sun.COM tear_down_and_return:
48410725SJohn.Forte@Sun.COM 
48510725SJohn.Forte@Sun.COM 	if (pppt_global.global_sess_taskq) {
48610725SJohn.Forte@Sun.COM 		taskq_destroy(pppt_global.global_sess_taskq);
48710725SJohn.Forte@Sun.COM 		pppt_global.global_sess_taskq = NULL;
48810725SJohn.Forte@Sun.COM 	}
48910725SJohn.Forte@Sun.COM 
49010725SJohn.Forte@Sun.COM 	if (pppt_global.global_dispatch_taskq) {
49110725SJohn.Forte@Sun.COM 		taskq_destroy(pppt_global.global_dispatch_taskq);
49210725SJohn.Forte@Sun.COM 		pppt_global.global_dispatch_taskq = NULL;
49310725SJohn.Forte@Sun.COM 	}
49410725SJohn.Forte@Sun.COM 
49510725SJohn.Forte@Sun.COM 	if (pppt_global.global_pp)
49610725SJohn.Forte@Sun.COM 		pppt_global.global_pp = NULL;
49710725SJohn.Forte@Sun.COM 
49810725SJohn.Forte@Sun.COM 	if (pp)
49910725SJohn.Forte@Sun.COM 		stmf_free(pp);
50010725SJohn.Forte@Sun.COM 
50110725SJohn.Forte@Sun.COM 	if (pppt_global.global_dbuf_store) {
50210725SJohn.Forte@Sun.COM 		stmf_free(pppt_global.global_dbuf_store);
50310725SJohn.Forte@Sun.COM 		pppt_global.global_dbuf_store = NULL;
50410725SJohn.Forte@Sun.COM 	}
50510725SJohn.Forte@Sun.COM 
50610725SJohn.Forte@Sun.COM 	avl_destroy(&pppt_global.global_sess_list);
50710725SJohn.Forte@Sun.COM 	avl_destroy(&pppt_global.global_target_list);
50810725SJohn.Forte@Sun.COM 
50910725SJohn.Forte@Sun.COM 	return (rc);
51010725SJohn.Forte@Sun.COM }
51110725SJohn.Forte@Sun.COM 
51210725SJohn.Forte@Sun.COM /*
51310725SJohn.Forte@Sun.COM  * pppt_disable_svc
51410725SJohn.Forte@Sun.COM  *
51510725SJohn.Forte@Sun.COM  * clean up all existing sessions and deregister targets from STMF
51610725SJohn.Forte@Sun.COM  */
51710725SJohn.Forte@Sun.COM static void
pppt_disable_svc(void)51810725SJohn.Forte@Sun.COM pppt_disable_svc(void)
51910725SJohn.Forte@Sun.COM {
52010725SJohn.Forte@Sun.COM 	pppt_tgt_t	*tgt, *next_tgt;
52110725SJohn.Forte@Sun.COM 	avl_tree_t	delete_target_list;
52210725SJohn.Forte@Sun.COM 
52310725SJohn.Forte@Sun.COM 	ASSERT(pppt_global.global_svc_state == PSS_DISABLING);
52410725SJohn.Forte@Sun.COM 
52510725SJohn.Forte@Sun.COM 	avl_create(&delete_target_list,
52610725SJohn.Forte@Sun.COM 	    pppt_tgt_avl_compare, sizeof (pppt_tgt_t),
52710725SJohn.Forte@Sun.COM 	    offsetof(pppt_tgt_t, target_global_ln));
52810725SJohn.Forte@Sun.COM 
52910725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_LOCK();
53010725SJohn.Forte@Sun.COM 	for (tgt = avl_first(&pppt_global.global_target_list);
53110725SJohn.Forte@Sun.COM 	    tgt != NULL;
53210725SJohn.Forte@Sun.COM 	    tgt = next_tgt) {
53310725SJohn.Forte@Sun.COM 		next_tgt = AVL_NEXT(&pppt_global.global_target_list, tgt);
53410725SJohn.Forte@Sun.COM 		avl_remove(&pppt_global.global_target_list, tgt);
53510725SJohn.Forte@Sun.COM 		avl_add(&delete_target_list, tgt);
53610725SJohn.Forte@Sun.COM 		pppt_tgt_async_delete(tgt);
53710725SJohn.Forte@Sun.COM 	}
53810725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_UNLOCK();
53910725SJohn.Forte@Sun.COM 
54010725SJohn.Forte@Sun.COM 	for (tgt = avl_first(&delete_target_list);
54110725SJohn.Forte@Sun.COM 	    tgt != NULL;
54210725SJohn.Forte@Sun.COM 	    tgt = next_tgt) {
54310725SJohn.Forte@Sun.COM 		next_tgt = AVL_NEXT(&delete_target_list, tgt);
54410725SJohn.Forte@Sun.COM 		mutex_enter(&tgt->target_mutex);
54510725SJohn.Forte@Sun.COM 		while ((tgt->target_refcount > 0) ||
54610725SJohn.Forte@Sun.COM 		    (tgt->target_state != TS_DELETING)) {
54710725SJohn.Forte@Sun.COM 			cv_wait(&tgt->target_cv, &tgt->target_mutex);
54810725SJohn.Forte@Sun.COM 		}
54910725SJohn.Forte@Sun.COM 		mutex_exit(&tgt->target_mutex);
55010725SJohn.Forte@Sun.COM 
55110725SJohn.Forte@Sun.COM 		avl_remove(&delete_target_list, tgt);
55210725SJohn.Forte@Sun.COM 		pppt_tgt_destroy(tgt);
55310725SJohn.Forte@Sun.COM 	}
55410725SJohn.Forte@Sun.COM 
55510725SJohn.Forte@Sun.COM 	taskq_destroy(pppt_global.global_sess_taskq);
55610725SJohn.Forte@Sun.COM 
55710725SJohn.Forte@Sun.COM 	taskq_destroy(pppt_global.global_dispatch_taskq);
55810725SJohn.Forte@Sun.COM 
55910725SJohn.Forte@Sun.COM 	avl_destroy(&pppt_global.global_sess_list);
56010725SJohn.Forte@Sun.COM 	avl_destroy(&pppt_global.global_target_list);
56110725SJohn.Forte@Sun.COM 
56210725SJohn.Forte@Sun.COM 	(void) stmf_deregister_port_provider(pppt_global.global_pp);
56310725SJohn.Forte@Sun.COM 
56410725SJohn.Forte@Sun.COM 	stmf_free(pppt_global.global_dbuf_store);
56510725SJohn.Forte@Sun.COM 	pppt_global.global_dbuf_store = NULL;
56610725SJohn.Forte@Sun.COM 
56710725SJohn.Forte@Sun.COM 	stmf_free(pppt_global.global_pp);
56810725SJohn.Forte@Sun.COM 	pppt_global.global_pp = NULL;
56910725SJohn.Forte@Sun.COM }
57010725SJohn.Forte@Sun.COM 
57110725SJohn.Forte@Sun.COM /*
57210725SJohn.Forte@Sun.COM  * STMF callbacks
57310725SJohn.Forte@Sun.COM  */
57410725SJohn.Forte@Sun.COM 
57510725SJohn.Forte@Sun.COM /*ARGSUSED*/
57610725SJohn.Forte@Sun.COM static stmf_data_buf_t *
pppt_dbuf_alloc(scsi_task_t * task,uint32_t size,uint32_t * pminsize,uint32_t flags)57710725SJohn.Forte@Sun.COM pppt_dbuf_alloc(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
57810725SJohn.Forte@Sun.COM     uint32_t flags)
57910725SJohn.Forte@Sun.COM {
58010725SJohn.Forte@Sun.COM 	stmf_data_buf_t	*result;
58110725SJohn.Forte@Sun.COM 	pppt_buf_t	*pbuf;
58210725SJohn.Forte@Sun.COM 	uint8_t		*buf;
58310725SJohn.Forte@Sun.COM 
58410725SJohn.Forte@Sun.COM 	/* Get buffer */
58510725SJohn.Forte@Sun.COM 	buf = kmem_alloc(size, KM_SLEEP);
58610725SJohn.Forte@Sun.COM 
58710725SJohn.Forte@Sun.COM 	/*
58810725SJohn.Forte@Sun.COM 	 *  Allocate stmf buf with private port provider section
58910725SJohn.Forte@Sun.COM 	 * (pppt_buf_t)
59010725SJohn.Forte@Sun.COM 	 */
59110725SJohn.Forte@Sun.COM 	result = stmf_alloc(STMF_STRUCT_DATA_BUF, sizeof (pppt_buf_t), 0);
59210725SJohn.Forte@Sun.COM 	if (result != NULL) {
59310725SJohn.Forte@Sun.COM 		/* Fill in pppt_buf_t */
59410725SJohn.Forte@Sun.COM 		pbuf = result->db_port_private;
59510725SJohn.Forte@Sun.COM 		pbuf->pbuf_stmf_buf = result;
59610725SJohn.Forte@Sun.COM 		pbuf->pbuf_is_immed = B_FALSE;
59710725SJohn.Forte@Sun.COM 
59810725SJohn.Forte@Sun.COM 		/*
59910725SJohn.Forte@Sun.COM 		 * Fill in stmf_data_buf_t.  DB_DONT CACHE tells
60010725SJohn.Forte@Sun.COM 		 * stmf not to cache buffers but STMF doesn't do
60110725SJohn.Forte@Sun.COM 		 * that yet so it's a no-op.  Port providers like
60210725SJohn.Forte@Sun.COM 		 * FC and SRP that have buffers associated with the
60310725SJohn.Forte@Sun.COM 		 * target port would want to let STMF cache
60410725SJohn.Forte@Sun.COM 		 * the buffers.  Port providers like iSCSI would
60510725SJohn.Forte@Sun.COM 		 * not want STMF to cache because the buffers are
60610725SJohn.Forte@Sun.COM 		 * really associated with a connection, not an
60710725SJohn.Forte@Sun.COM 		 * STMF target port so there is no way for STMF
60810725SJohn.Forte@Sun.COM 		 * to cache the buffers effectively.  These port
60910725SJohn.Forte@Sun.COM 		 * providers should cache buffers internally if
61010725SJohn.Forte@Sun.COM 		 * there is significant buffer setup overhead.
61110725SJohn.Forte@Sun.COM 		 *
61210725SJohn.Forte@Sun.COM 		 * And of course, since STMF doesn't do any internal
61310725SJohn.Forte@Sun.COM 		 * caching right now anyway, all port providers should
61410725SJohn.Forte@Sun.COM 		 * do what they can to minimize buffer setup overhead.
61510725SJohn.Forte@Sun.COM 		 */
61610725SJohn.Forte@Sun.COM 		result->db_flags = DB_DONT_CACHE;
61710725SJohn.Forte@Sun.COM 		result->db_buf_size = size;
61810725SJohn.Forte@Sun.COM 		result->db_data_size = size;
61910725SJohn.Forte@Sun.COM 		result->db_sglist_length = 1;
62010725SJohn.Forte@Sun.COM 		result->db_sglist[0].seg_addr = buf;
62110725SJohn.Forte@Sun.COM 		result->db_sglist[0].seg_length = size;
62210725SJohn.Forte@Sun.COM 		return (result);
62310725SJohn.Forte@Sun.COM 	} else {
62410725SJohn.Forte@Sun.COM 		/*
62510725SJohn.Forte@Sun.COM 		 * Couldn't get the stmf_data_buf_t so free the
62610725SJohn.Forte@Sun.COM 		 * buffer
62710725SJohn.Forte@Sun.COM 		 */
62810725SJohn.Forte@Sun.COM 		kmem_free(buf, size);
62910725SJohn.Forte@Sun.COM 	}
63010725SJohn.Forte@Sun.COM 
63110725SJohn.Forte@Sun.COM 	return (NULL);
63210725SJohn.Forte@Sun.COM }
63310725SJohn.Forte@Sun.COM 
63410725SJohn.Forte@Sun.COM /*ARGSUSED*/
63510725SJohn.Forte@Sun.COM static void
pppt_dbuf_free(stmf_dbuf_store_t * ds,stmf_data_buf_t * dbuf)63610725SJohn.Forte@Sun.COM pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
63710725SJohn.Forte@Sun.COM {
63810725SJohn.Forte@Sun.COM 	pppt_buf_t *pbuf = dbuf->db_port_private;
63910725SJohn.Forte@Sun.COM 
64010725SJohn.Forte@Sun.COM 	if (pbuf->pbuf_is_immed) {
64110725SJohn.Forte@Sun.COM 		stmf_ic_msg_free(pbuf->pbuf_immed_msg);
64210725SJohn.Forte@Sun.COM 	} else {
64310725SJohn.Forte@Sun.COM 		kmem_free(dbuf->db_sglist[0].seg_addr,
64410725SJohn.Forte@Sun.COM 		    dbuf->db_sglist[0].seg_length);
64510725SJohn.Forte@Sun.COM 		stmf_free(dbuf);
64610725SJohn.Forte@Sun.COM 	}
64710725SJohn.Forte@Sun.COM }
64810725SJohn.Forte@Sun.COM 
64910725SJohn.Forte@Sun.COM /*ARGSUSED*/
65010725SJohn.Forte@Sun.COM stmf_status_t
pppt_lport_xfer_data(scsi_task_t * task,stmf_data_buf_t * dbuf,uint32_t ioflags)65110725SJohn.Forte@Sun.COM pppt_lport_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf,
65210725SJohn.Forte@Sun.COM     uint32_t ioflags)
65310725SJohn.Forte@Sun.COM {
65410725SJohn.Forte@Sun.COM 	pppt_task_t		*pppt_task = task->task_port_private;
65510725SJohn.Forte@Sun.COM 	pppt_buf_t		*pbuf = dbuf->db_port_private;
65610725SJohn.Forte@Sun.COM 	stmf_ic_msg_t		*msg;
65710725SJohn.Forte@Sun.COM 	stmf_ic_msg_status_t	ic_msg_status;
65810725SJohn.Forte@Sun.COM 
65910725SJohn.Forte@Sun.COM 	/*
66010725SJohn.Forte@Sun.COM 	 * If we are aborting then we can ignore this request, otherwise
66110725SJohn.Forte@Sun.COM 	 * add a reference.
66210725SJohn.Forte@Sun.COM 	 */
66310725SJohn.Forte@Sun.COM 	if (pppt_task_hold(pppt_task) != PPPT_STATUS_SUCCESS) {
66410725SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
66510725SJohn.Forte@Sun.COM 	}
66610725SJohn.Forte@Sun.COM 
66710725SJohn.Forte@Sun.COM 	/*
66810725SJohn.Forte@Sun.COM 	 * If it's not immediate data then start the transfer
66910725SJohn.Forte@Sun.COM 	 */
67010725SJohn.Forte@Sun.COM 	ASSERT(pbuf->pbuf_is_immed == B_FALSE);
67110725SJohn.Forte@Sun.COM 	if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
67210725SJohn.Forte@Sun.COM 
67310725SJohn.Forte@Sun.COM 		/* Send read data */
67410725SJohn.Forte@Sun.COM 		msg = stmf_ic_scsi_data_msg_alloc(
67510725SJohn.Forte@Sun.COM 		    pppt_task->pt_task_id,
67610725SJohn.Forte@Sun.COM 		    pppt_task->pt_sess->ps_session_id,
67710725SJohn.Forte@Sun.COM 		    pppt_task->pt_lun_id,
67810725SJohn.Forte@Sun.COM 		    dbuf->db_sglist[0].seg_length,
67910725SJohn.Forte@Sun.COM 		    dbuf->db_sglist[0].seg_addr, 0);
68010725SJohn.Forte@Sun.COM 
68110725SJohn.Forte@Sun.COM 		pppt_task->pt_read_buf = pbuf;
68210725SJohn.Forte@Sun.COM 		pppt_task->pt_read_xfer_msgid = msg->icm_msgid;
68310725SJohn.Forte@Sun.COM 
68410725SJohn.Forte@Sun.COM 		ic_msg_status = stmf_ic_tx_msg(msg);
68510725SJohn.Forte@Sun.COM 		pppt_task_rele(pppt_task);
68610725SJohn.Forte@Sun.COM 		if (ic_msg_status != STMF_IC_MSG_SUCCESS) {
68710725SJohn.Forte@Sun.COM 			return (STMF_FAILURE);
68810725SJohn.Forte@Sun.COM 		} else {
68910725SJohn.Forte@Sun.COM 			return (STMF_SUCCESS);
69010725SJohn.Forte@Sun.COM 		}
69110725SJohn.Forte@Sun.COM 	} else if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
69210725SJohn.Forte@Sun.COM 		pppt_task_rele(pppt_task);
69310725SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
69410725SJohn.Forte@Sun.COM 	}
69510725SJohn.Forte@Sun.COM 
69610725SJohn.Forte@Sun.COM 	pppt_task_rele(pppt_task);
69710725SJohn.Forte@Sun.COM 
69810725SJohn.Forte@Sun.COM 	return (STMF_INVALID_ARG);
69910725SJohn.Forte@Sun.COM }
70010725SJohn.Forte@Sun.COM 
70110725SJohn.Forte@Sun.COM void
pppt_xfer_read_complete(pppt_task_t * pppt_task,stmf_status_t status)70210725SJohn.Forte@Sun.COM pppt_xfer_read_complete(pppt_task_t *pppt_task, stmf_status_t status)
70310725SJohn.Forte@Sun.COM {
70410725SJohn.Forte@Sun.COM 	pppt_buf_t		*pppt_buf;
70510725SJohn.Forte@Sun.COM 	stmf_data_buf_t		*dbuf;
70610725SJohn.Forte@Sun.COM 
70710725SJohn.Forte@Sun.COM 	/*
70810725SJohn.Forte@Sun.COM 	 * Caller should have taken a task hold (likely via pppt_task_lookup)
70910725SJohn.Forte@Sun.COM 	 *
71010725SJohn.Forte@Sun.COM 	 * Get pppt_buf_t and stmf_data_buf_t pointers
71110725SJohn.Forte@Sun.COM 	 */
71210725SJohn.Forte@Sun.COM 	pppt_buf = pppt_task->pt_read_buf;
71310725SJohn.Forte@Sun.COM 	dbuf = pppt_buf->pbuf_stmf_buf;
71410725SJohn.Forte@Sun.COM 	dbuf->db_xfer_status = (status == STMF_SUCCESS) ?
71510725SJohn.Forte@Sun.COM 	    STMF_SUCCESS : STMF_FAILURE;
71610725SJohn.Forte@Sun.COM 
71710725SJohn.Forte@Sun.COM 	/*
71810725SJohn.Forte@Sun.COM 	 * COMSTAR currently requires port providers to support
71910725SJohn.Forte@Sun.COM 	 * the DB_SEND_STATUS_GOOD flag even if phase collapse is
72010725SJohn.Forte@Sun.COM 	 * not supported.  So we will roll our own... pretend we are
72110725SJohn.Forte@Sun.COM 	 * COMSTAR and ask for a status message.
72210725SJohn.Forte@Sun.COM 	 */
72310725SJohn.Forte@Sun.COM 	if ((dbuf->db_flags & DB_SEND_STATUS_GOOD) &&
72410725SJohn.Forte@Sun.COM 	    (status == STMF_SUCCESS)) {
72510725SJohn.Forte@Sun.COM 		/*
72610725SJohn.Forte@Sun.COM 		 * It's possible the task has been aborted since the time we
72710725SJohn.Forte@Sun.COM 		 * looked it up.  We need to release the hold before calling
72810725SJohn.Forte@Sun.COM 		 * pppt_lport_send_status and as soon as we release the hold
72910725SJohn.Forte@Sun.COM 		 * the task may disappear.  Calling pppt_task_done allows us
73010725SJohn.Forte@Sun.COM 		 * to determine whether the task has been aborted (in which
73110725SJohn.Forte@Sun.COM 		 * case we will stop processing and return) and mark the task
73210725SJohn.Forte@Sun.COM 		 * "done" which will prevent the task from being aborted while
73310725SJohn.Forte@Sun.COM 		 * we are trying to send the status.
73410725SJohn.Forte@Sun.COM 		 */
73510725SJohn.Forte@Sun.COM 		if (pppt_task_done(pppt_task) != PPPT_STATUS_SUCCESS) {
73610725SJohn.Forte@Sun.COM 			/* STMF will free task and buffer(s) */
73710725SJohn.Forte@Sun.COM 			pppt_task_rele(pppt_task);
73810725SJohn.Forte@Sun.COM 			return;
73910725SJohn.Forte@Sun.COM 		}
74010725SJohn.Forte@Sun.COM 		pppt_task_rele(pppt_task);
74110725SJohn.Forte@Sun.COM 
74210725SJohn.Forte@Sun.COM 		if (pppt_lport_send_status(pppt_task->pt_stmf_task, 0)
74310725SJohn.Forte@Sun.COM 		    != STMF_SUCCESS) {
74410725SJohn.Forte@Sun.COM 			/* Failed to send status */
74510725SJohn.Forte@Sun.COM 			dbuf->db_xfer_status = STMF_FAILURE;
74610725SJohn.Forte@Sun.COM 			stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf,
74710725SJohn.Forte@Sun.COM 			    STMF_IOF_LPORT_DONE);
74810725SJohn.Forte@Sun.COM 		}
74910725SJohn.Forte@Sun.COM 	} else {
75010725SJohn.Forte@Sun.COM 		pppt_task_rele(pppt_task);
75110725SJohn.Forte@Sun.COM 		stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf, 0);
75210725SJohn.Forte@Sun.COM 	}
75310725SJohn.Forte@Sun.COM }
75410725SJohn.Forte@Sun.COM 
75510725SJohn.Forte@Sun.COM /*ARGSUSED*/
75610725SJohn.Forte@Sun.COM stmf_status_t
pppt_lport_send_status(scsi_task_t * task,uint32_t ioflags)75710725SJohn.Forte@Sun.COM pppt_lport_send_status(scsi_task_t *task, uint32_t ioflags)
75810725SJohn.Forte@Sun.COM {
75910725SJohn.Forte@Sun.COM 	pppt_task_t *ptask =		task->task_port_private;
76010725SJohn.Forte@Sun.COM 	stmf_ic_msg_t			*msg;
76110725SJohn.Forte@Sun.COM 	stmf_ic_msg_status_t		ic_msg_status;
76210725SJohn.Forte@Sun.COM 
76310725SJohn.Forte@Sun.COM 	/*
76410725SJohn.Forte@Sun.COM 	 * Mark task completed.  If the state indicates it was aborted
76510725SJohn.Forte@Sun.COM 	 * then we don't need to respond.
76610725SJohn.Forte@Sun.COM 	 */
76710725SJohn.Forte@Sun.COM 	if (pppt_task_done(ptask) == PPPT_STATUS_ABORTED) {
76810725SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
76910725SJohn.Forte@Sun.COM 	}
77010725SJohn.Forte@Sun.COM 
77110725SJohn.Forte@Sun.COM 	/*
77210725SJohn.Forte@Sun.COM 	 * Send status.
77310725SJohn.Forte@Sun.COM 	 */
77410725SJohn.Forte@Sun.COM 	msg = stmf_ic_scsi_status_msg_alloc(
77510725SJohn.Forte@Sun.COM 	    ptask->pt_task_id,
77610725SJohn.Forte@Sun.COM 	    ptask->pt_sess->ps_session_id,
77710725SJohn.Forte@Sun.COM 	    ptask->pt_lun_id,
77810725SJohn.Forte@Sun.COM 	    0,
77910725SJohn.Forte@Sun.COM 	    task->task_scsi_status,
78010725SJohn.Forte@Sun.COM 	    task->task_status_ctrl, task->task_resid,
78110725SJohn.Forte@Sun.COM 	    task->task_sense_length, task->task_sense_data, 0);
78210725SJohn.Forte@Sun.COM 
78310725SJohn.Forte@Sun.COM 	ic_msg_status = stmf_ic_tx_msg(msg);
78410725SJohn.Forte@Sun.COM 
78510725SJohn.Forte@Sun.COM 	if (ic_msg_status != STMF_IC_MSG_SUCCESS) {
78610725SJohn.Forte@Sun.COM 		pppt_task_sent_status(ptask);
78710725SJohn.Forte@Sun.COM 		stmf_send_status_done(ptask->pt_stmf_task,
78810725SJohn.Forte@Sun.COM 		    STMF_FAILURE, STMF_IOF_LPORT_DONE);
78910725SJohn.Forte@Sun.COM 		return (STMF_FAILURE);
79010725SJohn.Forte@Sun.COM 	} else {
79110725SJohn.Forte@Sun.COM 		pppt_task_sent_status(ptask);
79210725SJohn.Forte@Sun.COM 		stmf_send_status_done(ptask->pt_stmf_task,
79310725SJohn.Forte@Sun.COM 		    STMF_SUCCESS, STMF_IOF_LPORT_DONE);
79410725SJohn.Forte@Sun.COM 		return (STMF_SUCCESS);
79510725SJohn.Forte@Sun.COM 	}
79610725SJohn.Forte@Sun.COM }
79710725SJohn.Forte@Sun.COM 
79810725SJohn.Forte@Sun.COM void
pppt_lport_task_free(scsi_task_t * task)79910725SJohn.Forte@Sun.COM pppt_lport_task_free(scsi_task_t *task)
80010725SJohn.Forte@Sun.COM {
80110725SJohn.Forte@Sun.COM 	pppt_task_t *ptask = task->task_port_private;
80210725SJohn.Forte@Sun.COM 	pppt_sess_t *ps = ptask->pt_sess;
80310725SJohn.Forte@Sun.COM 
80410725SJohn.Forte@Sun.COM 	pppt_task_free(ptask);
80510725SJohn.Forte@Sun.COM 	pppt_sess_rele(ps);
80610725SJohn.Forte@Sun.COM }
80710725SJohn.Forte@Sun.COM 
80810725SJohn.Forte@Sun.COM /*ARGSUSED*/
80910725SJohn.Forte@Sun.COM stmf_status_t
pppt_lport_abort(stmf_local_port_t * lport,int abort_cmd,void * arg,uint32_t flags)81010725SJohn.Forte@Sun.COM pppt_lport_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
81110725SJohn.Forte@Sun.COM     uint32_t flags)
81210725SJohn.Forte@Sun.COM {
81310725SJohn.Forte@Sun.COM 	scsi_task_t	*st = (scsi_task_t *)arg;
81410725SJohn.Forte@Sun.COM 	pppt_task_t	*ptask;
81510725SJohn.Forte@Sun.COM 
81610725SJohn.Forte@Sun.COM 	ptask = st->task_port_private;
81710725SJohn.Forte@Sun.COM 
81810725SJohn.Forte@Sun.COM 	if (pppt_task_try_abort(ptask) == PPPT_STATUS_DONE) {
81910725SJohn.Forte@Sun.COM 		/*
82010725SJohn.Forte@Sun.COM 		 * This task is beyond the point where abort makes sense
82110725SJohn.Forte@Sun.COM 		 * and we will soon be sending status.  Tell STMF to
82210725SJohn.Forte@Sun.COM 		 * go away.
82310725SJohn.Forte@Sun.COM 		 */
82410725SJohn.Forte@Sun.COM 		return (STMF_BUSY);
82510725SJohn.Forte@Sun.COM 	} else {
82610725SJohn.Forte@Sun.COM 		return (STMF_ABORT_SUCCESS);
82710725SJohn.Forte@Sun.COM 	}
82810725SJohn.Forte@Sun.COM 	/*NOTREACHED*/
82910725SJohn.Forte@Sun.COM }
83010725SJohn.Forte@Sun.COM 
83110725SJohn.Forte@Sun.COM /*ARGSUSED*/
83210725SJohn.Forte@Sun.COM void
pppt_lport_ctl(stmf_local_port_t * lport,int cmd,void * arg)83310725SJohn.Forte@Sun.COM pppt_lport_ctl(stmf_local_port_t *lport, int cmd, void *arg)
83410725SJohn.Forte@Sun.COM {
83510725SJohn.Forte@Sun.COM 	switch (cmd) {
83610725SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_ONLINE:
83710725SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_OFFLINE:
83810725SJohn.Forte@Sun.COM 	case STMF_ACK_LPORT_ONLINE_COMPLETE:
83910725SJohn.Forte@Sun.COM 	case STMF_ACK_LPORT_OFFLINE_COMPLETE:
84010725SJohn.Forte@Sun.COM 		pppt_tgt_sm_ctl(lport, cmd, arg);
84110725SJohn.Forte@Sun.COM 		break;
84210725SJohn.Forte@Sun.COM 
84310725SJohn.Forte@Sun.COM 	default:
84410725SJohn.Forte@Sun.COM 		ASSERT(0);
84510725SJohn.Forte@Sun.COM 		break;
84610725SJohn.Forte@Sun.COM 	}
84710725SJohn.Forte@Sun.COM }
84810725SJohn.Forte@Sun.COM 
84910725SJohn.Forte@Sun.COM pppt_sess_t *
pppt_sess_lookup_locked(uint64_t session_id,scsi_devid_desc_t * lport_devid,stmf_remote_port_t * rport)85010725SJohn.Forte@Sun.COM pppt_sess_lookup_locked(uint64_t session_id,
851*12750SNattuvetty.Bhavyan@Sun.COM     scsi_devid_desc_t *lport_devid, stmf_remote_port_t *rport)
85210725SJohn.Forte@Sun.COM {
85310725SJohn.Forte@Sun.COM 	pppt_tgt_t				*tgt;
85410725SJohn.Forte@Sun.COM 	pppt_sess_t				*ps;
85510725SJohn.Forte@Sun.COM 	int					lport_cmp;
85610725SJohn.Forte@Sun.COM 
85710725SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&pppt_global.global_lock));
85810725SJohn.Forte@Sun.COM 
85910725SJohn.Forte@Sun.COM 	/*
86010725SJohn.Forte@Sun.COM 	 * Look for existing session for this ID
86110725SJohn.Forte@Sun.COM 	 */
86210725SJohn.Forte@Sun.COM 	ps = pppt_sess_lookup_by_id_locked(session_id);
86310725SJohn.Forte@Sun.COM 	if (ps == NULL) {
86410725SJohn.Forte@Sun.COM 		PPPT_INC_STAT(es_sess_lookup_no_session);
86510725SJohn.Forte@Sun.COM 		return (NULL);
86610725SJohn.Forte@Sun.COM 	}
86710725SJohn.Forte@Sun.COM 
86810725SJohn.Forte@Sun.COM 	tgt = ps->ps_target;
86910725SJohn.Forte@Sun.COM 
87010725SJohn.Forte@Sun.COM 	mutex_enter(&tgt->target_mutex);
87110725SJohn.Forte@Sun.COM 
87210725SJohn.Forte@Sun.COM 	/* Validate local/remote port names */
87310725SJohn.Forte@Sun.COM 	if ((lport_devid->ident_length !=
87410725SJohn.Forte@Sun.COM 	    tgt->target_stmf_lport->lport_id->ident_length) ||
875*12750SNattuvetty.Bhavyan@Sun.COM 	    (rport->rport_tptid_sz !=
876*12750SNattuvetty.Bhavyan@Sun.COM 	    ps->ps_stmf_sess->ss_rport->rport_tptid_sz)) {
87710725SJohn.Forte@Sun.COM 		mutex_exit(&tgt->target_mutex);
87810725SJohn.Forte@Sun.COM 		PPPT_INC_STAT(es_sess_lookup_ident_mismatch);
87910725SJohn.Forte@Sun.COM 		return (NULL);
88010725SJohn.Forte@Sun.COM 	} else {
88110725SJohn.Forte@Sun.COM 		lport_cmp = bcmp(lport_devid->ident,
88210725SJohn.Forte@Sun.COM 		    tgt->target_stmf_lport->lport_id->ident,
88310725SJohn.Forte@Sun.COM 		    lport_devid->ident_length);
884*12750SNattuvetty.Bhavyan@Sun.COM 		if (lport_cmp != 0 ||
885*12750SNattuvetty.Bhavyan@Sun.COM 		    (stmf_scsilib_tptid_compare(rport->rport_tptid,
886*12750SNattuvetty.Bhavyan@Sun.COM 		    ps->ps_stmf_sess->ss_rport->rport_tptid) != B_TRUE)) {
88710725SJohn.Forte@Sun.COM 			mutex_exit(&tgt->target_mutex);
88810725SJohn.Forte@Sun.COM 			PPPT_INC_STAT(es_sess_lookup_ident_mismatch);
88910725SJohn.Forte@Sun.COM 			return (NULL);
89010725SJohn.Forte@Sun.COM 		}
89110725SJohn.Forte@Sun.COM 
89210725SJohn.Forte@Sun.COM 		if (tgt->target_state != TS_STMF_ONLINE) {
89310725SJohn.Forte@Sun.COM 			mutex_exit(&tgt->target_mutex);
89410725SJohn.Forte@Sun.COM 			PPPT_INC_STAT(es_sess_lookup_bad_tgt_state);
89510725SJohn.Forte@Sun.COM 			return (NULL);
89610725SJohn.Forte@Sun.COM 		}
89710725SJohn.Forte@Sun.COM 	}
89810725SJohn.Forte@Sun.COM 	mutex_exit(&tgt->target_mutex);
89910725SJohn.Forte@Sun.COM 
90010725SJohn.Forte@Sun.COM 	return (ps);
90110725SJohn.Forte@Sun.COM }
90210725SJohn.Forte@Sun.COM 
90310725SJohn.Forte@Sun.COM pppt_sess_t *
pppt_sess_lookup_by_id_locked(uint64_t session_id)90410725SJohn.Forte@Sun.COM pppt_sess_lookup_by_id_locked(uint64_t session_id)
90510725SJohn.Forte@Sun.COM {
90610725SJohn.Forte@Sun.COM 	pppt_sess_t		tmp_ps;
90710725SJohn.Forte@Sun.COM 	pppt_sess_t		*ps;
90810725SJohn.Forte@Sun.COM 
90910725SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&pppt_global.global_lock));
91010725SJohn.Forte@Sun.COM 	tmp_ps.ps_session_id = session_id;
91110725SJohn.Forte@Sun.COM 	tmp_ps.ps_closed = 0;
91210725SJohn.Forte@Sun.COM 	ps = avl_find(&pppt_global.global_sess_list, &tmp_ps, NULL);
91310725SJohn.Forte@Sun.COM 	if (ps != NULL) {
91410725SJohn.Forte@Sun.COM 		mutex_enter(&ps->ps_mutex);
91510725SJohn.Forte@Sun.COM 		if (!ps->ps_closed) {
91610725SJohn.Forte@Sun.COM 			ps->ps_refcnt++;
91710725SJohn.Forte@Sun.COM 			mutex_exit(&ps->ps_mutex);
91810725SJohn.Forte@Sun.COM 			return (ps);
91910725SJohn.Forte@Sun.COM 		}
92010725SJohn.Forte@Sun.COM 		mutex_exit(&ps->ps_mutex);
92110725SJohn.Forte@Sun.COM 	}
92210725SJohn.Forte@Sun.COM 
92310725SJohn.Forte@Sun.COM 	return (NULL);
92410725SJohn.Forte@Sun.COM }
92510725SJohn.Forte@Sun.COM 
92610725SJohn.Forte@Sun.COM /* New session */
92710725SJohn.Forte@Sun.COM 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)92810725SJohn.Forte@Sun.COM pppt_sess_lookup_create(scsi_devid_desc_t *lport_devid,
929*12750SNattuvetty.Bhavyan@Sun.COM     scsi_devid_desc_t *rport_devid, stmf_remote_port_t *rport,
930*12750SNattuvetty.Bhavyan@Sun.COM     uint64_t session_id, stmf_status_t *statusp)
93110725SJohn.Forte@Sun.COM {
93210725SJohn.Forte@Sun.COM 	pppt_tgt_t		*tgt;
93310725SJohn.Forte@Sun.COM 	pppt_sess_t		*ps;
93410725SJohn.Forte@Sun.COM 	stmf_scsi_session_t	*ss;
93510725SJohn.Forte@Sun.COM 	pppt_sess_t		tmp_ps;
93610725SJohn.Forte@Sun.COM 	stmf_scsi_session_t	tmp_ss;
93710725SJohn.Forte@Sun.COM 	*statusp = STMF_SUCCESS;
93810725SJohn.Forte@Sun.COM 
93910725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_LOCK();
94010725SJohn.Forte@Sun.COM 
94110725SJohn.Forte@Sun.COM 	/*
94210725SJohn.Forte@Sun.COM 	 * Look for existing session for this ID
94310725SJohn.Forte@Sun.COM 	 */
944*12750SNattuvetty.Bhavyan@Sun.COM 	ps = pppt_sess_lookup_locked(session_id, lport_devid, rport);
94510725SJohn.Forte@Sun.COM 
94610725SJohn.Forte@Sun.COM 	if (ps != NULL) {
94710725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_UNLOCK();
94810725SJohn.Forte@Sun.COM 		return (ps);
94910725SJohn.Forte@Sun.COM 	}
95010725SJohn.Forte@Sun.COM 
95110725SJohn.Forte@Sun.COM 	/*
95210725SJohn.Forte@Sun.COM 	 * No session with that ID, look for another session corresponding
95310725SJohn.Forte@Sun.COM 	 * to the same IT nexus.
95410725SJohn.Forte@Sun.COM 	 */
95510725SJohn.Forte@Sun.COM 	tgt = pppt_tgt_lookup_locked(lport_devid);
95610725SJohn.Forte@Sun.COM 	if (tgt == NULL) {
95710725SJohn.Forte@Sun.COM 		*statusp = STMF_NOT_FOUND;
95810725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_UNLOCK();
95910725SJohn.Forte@Sun.COM 		return (NULL);
96010725SJohn.Forte@Sun.COM 	}
96110725SJohn.Forte@Sun.COM 
96210725SJohn.Forte@Sun.COM 	mutex_enter(&tgt->target_mutex);
96310725SJohn.Forte@Sun.COM 	if (tgt->target_state != TS_STMF_ONLINE) {
96410725SJohn.Forte@Sun.COM 		*statusp = STMF_NOT_FOUND;
96510725SJohn.Forte@Sun.COM 		mutex_exit(&tgt->target_mutex);
96610725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_UNLOCK();
96710725SJohn.Forte@Sun.COM 		/* Can't create session to offline target */
96810725SJohn.Forte@Sun.COM 		return (NULL);
96910725SJohn.Forte@Sun.COM 	}
97010725SJohn.Forte@Sun.COM 
97110725SJohn.Forte@Sun.COM 	bzero(&tmp_ps, sizeof (tmp_ps));
97210725SJohn.Forte@Sun.COM 	bzero(&tmp_ss, sizeof (tmp_ss));
97310725SJohn.Forte@Sun.COM 	tmp_ps.ps_stmf_sess = &tmp_ss;
974*12750SNattuvetty.Bhavyan@Sun.COM 	tmp_ss.ss_rport = rport;
97510725SJohn.Forte@Sun.COM 
97610725SJohn.Forte@Sun.COM 	/*
97710725SJohn.Forte@Sun.COM 	 * Look for an existing session on this IT nexus
97810725SJohn.Forte@Sun.COM 	 */
97910725SJohn.Forte@Sun.COM 	ps = avl_find(&tgt->target_sess_list, &tmp_ps, NULL);
98010725SJohn.Forte@Sun.COM 
98110725SJohn.Forte@Sun.COM 	if (ps != NULL) {
98210725SJohn.Forte@Sun.COM 		/*
98310725SJohn.Forte@Sun.COM 		 * Now check the session ID.  It should not match because if
98410725SJohn.Forte@Sun.COM 		 * it did we would have found it on the global session list.
98510725SJohn.Forte@Sun.COM 		 * If the session ID in the command is higher than the existing
98610725SJohn.Forte@Sun.COM 		 * session ID then we need to tear down the existing session.
98710725SJohn.Forte@Sun.COM 		 */
98810725SJohn.Forte@Sun.COM 		mutex_enter(&ps->ps_mutex);
98910725SJohn.Forte@Sun.COM 		ASSERT(ps->ps_session_id != session_id);
99010725SJohn.Forte@Sun.COM 		if (ps->ps_session_id > session_id) {
99110725SJohn.Forte@Sun.COM 			/* Invalid session ID */
99210725SJohn.Forte@Sun.COM 			mutex_exit(&ps->ps_mutex);
99310725SJohn.Forte@Sun.COM 			mutex_exit(&tgt->target_mutex);
99410725SJohn.Forte@Sun.COM 			PPPT_GLOBAL_UNLOCK();
99510725SJohn.Forte@Sun.COM 			*statusp = STMF_INVALID_ARG;
99610725SJohn.Forte@Sun.COM 			return (NULL);
99710725SJohn.Forte@Sun.COM 		} else {
99810725SJohn.Forte@Sun.COM 			/* Existing session needs to be invalidated */
99910725SJohn.Forte@Sun.COM 			if (!ps->ps_closed) {
100010725SJohn.Forte@Sun.COM 				pppt_sess_close_locked(ps);
100110725SJohn.Forte@Sun.COM 			}
100210725SJohn.Forte@Sun.COM 		}
100310725SJohn.Forte@Sun.COM 		mutex_exit(&ps->ps_mutex);
100410725SJohn.Forte@Sun.COM 
100510725SJohn.Forte@Sun.COM 		/* Fallthrough and create new session */
100610725SJohn.Forte@Sun.COM 	}
100710725SJohn.Forte@Sun.COM 
100810725SJohn.Forte@Sun.COM 	/*
100910725SJohn.Forte@Sun.COM 	 * Allocate and fill in pppt_session_t with the appropriate data
101010725SJohn.Forte@Sun.COM 	 * for the protocol.
101110725SJohn.Forte@Sun.COM 	 */
101210725SJohn.Forte@Sun.COM 	ps = kmem_zalloc(sizeof (*ps), KM_SLEEP);
101310725SJohn.Forte@Sun.COM 
101410725SJohn.Forte@Sun.COM 	/* Fill in session fields */
101510725SJohn.Forte@Sun.COM 	ps->ps_target = tgt;
101610725SJohn.Forte@Sun.COM 	ps->ps_session_id = session_id;
101710725SJohn.Forte@Sun.COM 
101810725SJohn.Forte@Sun.COM 	ss = stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0,
101910725SJohn.Forte@Sun.COM 	    0);
102010725SJohn.Forte@Sun.COM 	if (ss == NULL) {
102110725SJohn.Forte@Sun.COM 		mutex_exit(&tgt->target_mutex);
102210725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_UNLOCK();
102310725SJohn.Forte@Sun.COM 		kmem_free(ps, sizeof (*ps));
102410725SJohn.Forte@Sun.COM 		*statusp = STMF_ALLOC_FAILURE;
102510725SJohn.Forte@Sun.COM 		return (NULL);
102610725SJohn.Forte@Sun.COM 	}
102710725SJohn.Forte@Sun.COM 
102810725SJohn.Forte@Sun.COM 	ss->ss_rport_id = kmem_zalloc(sizeof (scsi_devid_desc_t) +
102910725SJohn.Forte@Sun.COM 	    rport_devid->ident_length + 1, KM_SLEEP);
103010725SJohn.Forte@Sun.COM 	bcopy(rport_devid, ss->ss_rport_id,
103110725SJohn.Forte@Sun.COM 	    sizeof (scsi_devid_desc_t) + rport_devid->ident_length + 1);
103210725SJohn.Forte@Sun.COM 
103310725SJohn.Forte@Sun.COM 	ss->ss_lport = tgt->target_stmf_lport;
103410725SJohn.Forte@Sun.COM 
1035*12750SNattuvetty.Bhavyan@Sun.COM 	ss->ss_rport = stmf_remote_port_alloc(rport->rport_tptid_sz);
1036*12750SNattuvetty.Bhavyan@Sun.COM 	bcopy(rport->rport_tptid, ss->ss_rport->rport_tptid,
1037*12750SNattuvetty.Bhavyan@Sun.COM 	    rport->rport_tptid_sz);
1038*12750SNattuvetty.Bhavyan@Sun.COM 
103910725SJohn.Forte@Sun.COM 	if (stmf_register_scsi_session(tgt->target_stmf_lport, ss) !=
104010725SJohn.Forte@Sun.COM 	    STMF_SUCCESS) {
104110725SJohn.Forte@Sun.COM 		mutex_exit(&tgt->target_mutex);
104210725SJohn.Forte@Sun.COM 		PPPT_GLOBAL_UNLOCK();
104310725SJohn.Forte@Sun.COM 		kmem_free(ss->ss_rport_id,
1044*12750SNattuvetty.Bhavyan@Sun.COM 		    sizeof (scsi_devid_desc_t) + rport_devid->ident_length + 1);
1045*12750SNattuvetty.Bhavyan@Sun.COM 		stmf_remote_port_free(ss->ss_rport);
104610725SJohn.Forte@Sun.COM 		stmf_free(ss);
104710725SJohn.Forte@Sun.COM 		kmem_free(ps, sizeof (*ps));
104810725SJohn.Forte@Sun.COM 		*statusp = STMF_TARGET_FAILURE;
104910725SJohn.Forte@Sun.COM 		return (NULL);
105010725SJohn.Forte@Sun.COM 	}
105110725SJohn.Forte@Sun.COM 
105210725SJohn.Forte@Sun.COM 	ss->ss_port_private = ps;
105310725SJohn.Forte@Sun.COM 	mutex_init(&ps->ps_mutex, NULL, MUTEX_DEFAULT, NULL);
105410725SJohn.Forte@Sun.COM 	cv_init(&ps->ps_cv, NULL, CV_DEFAULT, NULL);
105510725SJohn.Forte@Sun.COM 	avl_create(&ps->ps_task_list, pppt_task_avl_compare,
105610725SJohn.Forte@Sun.COM 	    sizeof (pppt_task_t), offsetof(pppt_task_t, pt_sess_ln));
105710725SJohn.Forte@Sun.COM 	ps->ps_refcnt = 1;
105810725SJohn.Forte@Sun.COM 	ps->ps_stmf_sess = ss;
105910725SJohn.Forte@Sun.COM 	avl_add(&tgt->target_sess_list, ps);
106010725SJohn.Forte@Sun.COM 	avl_add(&pppt_global.global_sess_list, ps);
106110725SJohn.Forte@Sun.COM 	mutex_exit(&tgt->target_mutex);
106210725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_UNLOCK();
106311132SPeter.Dunlap@Sun.COM 	stmf_trace("pppt", "New session %p", (void *)ps);
106410725SJohn.Forte@Sun.COM 
106510725SJohn.Forte@Sun.COM 	return (ps);
106610725SJohn.Forte@Sun.COM }
106710725SJohn.Forte@Sun.COM 
106810725SJohn.Forte@Sun.COM void
pppt_sess_rele(pppt_sess_t * ps)106910725SJohn.Forte@Sun.COM pppt_sess_rele(pppt_sess_t *ps)
107010725SJohn.Forte@Sun.COM {
107110725SJohn.Forte@Sun.COM 	mutex_enter(&ps->ps_mutex);
107210725SJohn.Forte@Sun.COM 	pppt_sess_rele_locked(ps);
107310725SJohn.Forte@Sun.COM 	mutex_exit(&ps->ps_mutex);
107410725SJohn.Forte@Sun.COM }
107510725SJohn.Forte@Sun.COM 
107610725SJohn.Forte@Sun.COM void
pppt_sess_rele_locked(pppt_sess_t * ps)107710725SJohn.Forte@Sun.COM pppt_sess_rele_locked(pppt_sess_t *ps)
107810725SJohn.Forte@Sun.COM {
107910725SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&ps->ps_mutex));
108010725SJohn.Forte@Sun.COM 	ps->ps_refcnt--;
108110725SJohn.Forte@Sun.COM 	if (ps->ps_refcnt == 0) {
108210725SJohn.Forte@Sun.COM 		cv_signal(&ps->ps_cv);
108310725SJohn.Forte@Sun.COM 	}
108410725SJohn.Forte@Sun.COM }
108510725SJohn.Forte@Sun.COM 
pppt_sess_destroy_task(void * ps_void)108610725SJohn.Forte@Sun.COM static void pppt_sess_destroy_task(void *ps_void)
108710725SJohn.Forte@Sun.COM {
108810725SJohn.Forte@Sun.COM 	pppt_sess_t *ps = ps_void;
108910725SJohn.Forte@Sun.COM 	stmf_scsi_session_t	*ss;
109010725SJohn.Forte@Sun.COM 
109111132SPeter.Dunlap@Sun.COM 	stmf_trace("pppt", "Session destroy task %p", (void *)ps);
109210725SJohn.Forte@Sun.COM 
109310725SJohn.Forte@Sun.COM 	ss = ps->ps_stmf_sess;
109410725SJohn.Forte@Sun.COM 	mutex_enter(&ps->ps_mutex);
109510725SJohn.Forte@Sun.COM 	stmf_deregister_scsi_session(ss->ss_lport, ss);
109610725SJohn.Forte@Sun.COM 	kmem_free(ss->ss_rport_id,
1097*12750SNattuvetty.Bhavyan@Sun.COM 	    sizeof (scsi_devid_desc_t) + ss->ss_rport_id->ident_length + 1);
1098*12750SNattuvetty.Bhavyan@Sun.COM 	stmf_remote_port_free(ss->ss_rport);
109910725SJohn.Forte@Sun.COM 	avl_destroy(&ps->ps_task_list);
110010725SJohn.Forte@Sun.COM 	mutex_exit(&ps->ps_mutex);
110110725SJohn.Forte@Sun.COM 	cv_destroy(&ps->ps_cv);
110210725SJohn.Forte@Sun.COM 	mutex_destroy(&ps->ps_mutex);
110310725SJohn.Forte@Sun.COM 	stmf_free(ps->ps_stmf_sess);
110410725SJohn.Forte@Sun.COM 	kmem_free(ps, sizeof (*ps));
110510725SJohn.Forte@Sun.COM 
110611132SPeter.Dunlap@Sun.COM 	stmf_trace("pppt", "Session destroy task complete %p", (void *)ps);
110710725SJohn.Forte@Sun.COM }
110810725SJohn.Forte@Sun.COM 
110910725SJohn.Forte@Sun.COM int
pppt_sess_avl_compare_by_id(const void * void_sess1,const void * void_sess2)111010725SJohn.Forte@Sun.COM pppt_sess_avl_compare_by_id(const void *void_sess1, const void *void_sess2)
111110725SJohn.Forte@Sun.COM {
111210725SJohn.Forte@Sun.COM 	const	pppt_sess_t	*psess1 = void_sess1;
111310725SJohn.Forte@Sun.COM 	const	pppt_sess_t	*psess2 = void_sess2;
111410725SJohn.Forte@Sun.COM 
111510725SJohn.Forte@Sun.COM 	if (psess1->ps_session_id < psess2->ps_session_id)
111610725SJohn.Forte@Sun.COM 		return (-1);
111710725SJohn.Forte@Sun.COM 	else if (psess1->ps_session_id > psess2->ps_session_id)
111810725SJohn.Forte@Sun.COM 		return (1);
111910725SJohn.Forte@Sun.COM 
112010725SJohn.Forte@Sun.COM 	/* Allow multiple duplicate sessions if one is closed */
112110725SJohn.Forte@Sun.COM 	ASSERT(!(psess1->ps_closed && psess2->ps_closed));
112210725SJohn.Forte@Sun.COM 	if (psess1->ps_closed)
112310725SJohn.Forte@Sun.COM 		return (-1);
112410725SJohn.Forte@Sun.COM 	else if (psess2->ps_closed)
112510725SJohn.Forte@Sun.COM 		return (1);
112610725SJohn.Forte@Sun.COM 
112710725SJohn.Forte@Sun.COM 	return (0);
112810725SJohn.Forte@Sun.COM }
112910725SJohn.Forte@Sun.COM 
113010725SJohn.Forte@Sun.COM int
pppt_sess_avl_compare_by_name(const void * void_sess1,const void * void_sess2)113110725SJohn.Forte@Sun.COM pppt_sess_avl_compare_by_name(const void *void_sess1, const void *void_sess2)
113210725SJohn.Forte@Sun.COM {
113310725SJohn.Forte@Sun.COM 	const	pppt_sess_t	*psess1 = void_sess1;
113410725SJohn.Forte@Sun.COM 	const	pppt_sess_t	*psess2 = void_sess2;
113510725SJohn.Forte@Sun.COM 	int			result;
113610725SJohn.Forte@Sun.COM 
1137*12750SNattuvetty.Bhavyan@Sun.COM 	/* Compare by tptid size */
1138*12750SNattuvetty.Bhavyan@Sun.COM 	if (psess1->ps_stmf_sess->ss_rport->rport_tptid_sz <
1139*12750SNattuvetty.Bhavyan@Sun.COM 	    psess2->ps_stmf_sess->ss_rport->rport_tptid_sz) {
114010725SJohn.Forte@Sun.COM 		return (-1);
1141*12750SNattuvetty.Bhavyan@Sun.COM 	} else if (psess1->ps_stmf_sess->ss_rport->rport_tptid_sz >
1142*12750SNattuvetty.Bhavyan@Sun.COM 	    psess2->ps_stmf_sess->ss_rport->rport_tptid_sz) {
114310725SJohn.Forte@Sun.COM 		return (1);
114410725SJohn.Forte@Sun.COM 	}
114510725SJohn.Forte@Sun.COM 
1146*12750SNattuvetty.Bhavyan@Sun.COM 	/* Now compare tptid */
1147*12750SNattuvetty.Bhavyan@Sun.COM 	result = memcmp(psess1->ps_stmf_sess->ss_rport->rport_tptid,
1148*12750SNattuvetty.Bhavyan@Sun.COM 	    psess2->ps_stmf_sess->ss_rport->rport_tptid,
1149*12750SNattuvetty.Bhavyan@Sun.COM 	    psess1->ps_stmf_sess->ss_rport->rport_tptid_sz);
115010725SJohn.Forte@Sun.COM 
115110725SJohn.Forte@Sun.COM 	if (result < 0) {
115210725SJohn.Forte@Sun.COM 		return (-1);
115310725SJohn.Forte@Sun.COM 	} else if (result > 0) {
115410725SJohn.Forte@Sun.COM 		return (1);
115510725SJohn.Forte@Sun.COM 	}
115610725SJohn.Forte@Sun.COM 
115710725SJohn.Forte@Sun.COM 	return (0);
115810725SJohn.Forte@Sun.COM }
115910725SJohn.Forte@Sun.COM 
116010725SJohn.Forte@Sun.COM void
pppt_sess_close_locked(pppt_sess_t * ps)116110725SJohn.Forte@Sun.COM pppt_sess_close_locked(pppt_sess_t *ps)
116210725SJohn.Forte@Sun.COM {
116310725SJohn.Forte@Sun.COM 	pppt_tgt_t	*tgt = ps->ps_target;
116410725SJohn.Forte@Sun.COM 	pppt_task_t	*ptask;
116510725SJohn.Forte@Sun.COM 
116611132SPeter.Dunlap@Sun.COM 	stmf_trace("pppt", "Session close %p", (void *)ps);
116710725SJohn.Forte@Sun.COM 
116810725SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&pppt_global.global_lock));
116910725SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&tgt->target_mutex));
117010725SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&ps->ps_mutex));
117110725SJohn.Forte@Sun.COM 	ASSERT(!ps->ps_closed); /* Caller should ensure session is not closed */
117210725SJohn.Forte@Sun.COM 
117310725SJohn.Forte@Sun.COM 	ps->ps_closed = B_TRUE;
117410725SJohn.Forte@Sun.COM 	for (ptask = avl_first(&ps->ps_task_list); ptask != NULL;
117510725SJohn.Forte@Sun.COM 	    ptask = AVL_NEXT(&ps->ps_task_list, ptask)) {
117610725SJohn.Forte@Sun.COM 		mutex_enter(&ptask->pt_mutex);
117710725SJohn.Forte@Sun.COM 		if (ptask->pt_state == PTS_ACTIVE) {
117810725SJohn.Forte@Sun.COM 			stmf_abort(STMF_QUEUE_TASK_ABORT, ptask->pt_stmf_task,
117910725SJohn.Forte@Sun.COM 			    STMF_ABORTED, NULL);
118010725SJohn.Forte@Sun.COM 		}
118110725SJohn.Forte@Sun.COM 		mutex_exit(&ptask->pt_mutex);
118210725SJohn.Forte@Sun.COM 	}
118310725SJohn.Forte@Sun.COM 
118410725SJohn.Forte@Sun.COM 	/*
118510725SJohn.Forte@Sun.COM 	 * Now that all the tasks are aborting the session refcnt should
118610725SJohn.Forte@Sun.COM 	 * go to 0.
118710725SJohn.Forte@Sun.COM 	 */
118810725SJohn.Forte@Sun.COM 	while (ps->ps_refcnt != 0) {
118910725SJohn.Forte@Sun.COM 		cv_wait(&ps->ps_cv, &ps->ps_mutex);
119010725SJohn.Forte@Sun.COM 	}
119110725SJohn.Forte@Sun.COM 
119210725SJohn.Forte@Sun.COM 	avl_remove(&tgt->target_sess_list, ps);
119310725SJohn.Forte@Sun.COM 	avl_remove(&pppt_global.global_sess_list, ps);
119410725SJohn.Forte@Sun.COM 	(void) taskq_dispatch(pppt_global.global_sess_taskq,
119510725SJohn.Forte@Sun.COM 	    &pppt_sess_destroy_task, ps, KM_SLEEP);
119610725SJohn.Forte@Sun.COM 
119711132SPeter.Dunlap@Sun.COM 	stmf_trace("pppt", "Session close complete %p", (void *)ps);
119810725SJohn.Forte@Sun.COM }
119910725SJohn.Forte@Sun.COM 
120010725SJohn.Forte@Sun.COM pppt_task_t *
pppt_task_alloc(void)120110725SJohn.Forte@Sun.COM pppt_task_alloc(void)
120210725SJohn.Forte@Sun.COM {
120310725SJohn.Forte@Sun.COM 	pppt_task_t	*ptask;
120410725SJohn.Forte@Sun.COM 	pppt_buf_t	*immed_pbuf;
120510725SJohn.Forte@Sun.COM 
120610725SJohn.Forte@Sun.COM 	ptask = kmem_alloc(sizeof (pppt_task_t) + sizeof (pppt_buf_t) +
120710725SJohn.Forte@Sun.COM 	    sizeof (stmf_data_buf_t), KM_NOSLEEP);
120810725SJohn.Forte@Sun.COM 	if (ptask != NULL) {
120910725SJohn.Forte@Sun.COM 		ptask->pt_state = PTS_INIT;
121010725SJohn.Forte@Sun.COM 		ptask->pt_read_buf = NULL;
121110725SJohn.Forte@Sun.COM 		ptask->pt_read_xfer_msgid = 0;
121210725SJohn.Forte@Sun.COM 		cv_init(&ptask->pt_cv, NULL, CV_DRIVER, NULL);
121310725SJohn.Forte@Sun.COM 		mutex_init(&ptask->pt_mutex, NULL, MUTEX_DRIVER, NULL);
121410725SJohn.Forte@Sun.COM 		immed_pbuf = (pppt_buf_t *)(ptask + 1);
121510725SJohn.Forte@Sun.COM 		bzero(immed_pbuf, sizeof (*immed_pbuf));
121610725SJohn.Forte@Sun.COM 		immed_pbuf->pbuf_is_immed = B_TRUE;
121710725SJohn.Forte@Sun.COM 		immed_pbuf->pbuf_stmf_buf = (stmf_data_buf_t *)(immed_pbuf + 1);
121810725SJohn.Forte@Sun.COM 
121910725SJohn.Forte@Sun.COM 		bzero(immed_pbuf->pbuf_stmf_buf, sizeof (stmf_data_buf_t));
122010725SJohn.Forte@Sun.COM 		immed_pbuf->pbuf_stmf_buf->db_port_private = immed_pbuf;
122110725SJohn.Forte@Sun.COM 		immed_pbuf->pbuf_stmf_buf->db_sglist_length = 1;
122210725SJohn.Forte@Sun.COM 		immed_pbuf->pbuf_stmf_buf->db_flags = DB_DIRECTION_FROM_RPORT |
122310725SJohn.Forte@Sun.COM 		    DB_DONT_CACHE;
122410725SJohn.Forte@Sun.COM 		ptask->pt_immed_data = immed_pbuf;
122510725SJohn.Forte@Sun.COM 	}
122610725SJohn.Forte@Sun.COM 
122710725SJohn.Forte@Sun.COM 	return (ptask);
122810725SJohn.Forte@Sun.COM 
122910725SJohn.Forte@Sun.COM }
123010725SJohn.Forte@Sun.COM 
123110725SJohn.Forte@Sun.COM void
pppt_task_free(pppt_task_t * ptask)123210725SJohn.Forte@Sun.COM pppt_task_free(pppt_task_t *ptask)
123310725SJohn.Forte@Sun.COM {
123410725SJohn.Forte@Sun.COM 	mutex_enter(&ptask->pt_mutex);
123510725SJohn.Forte@Sun.COM 	mutex_destroy(&ptask->pt_mutex);
123610725SJohn.Forte@Sun.COM 	cv_destroy(&ptask->pt_cv);
123710725SJohn.Forte@Sun.COM 	kmem_free(ptask, sizeof (pppt_task_t) + sizeof (pppt_buf_t) +
123810725SJohn.Forte@Sun.COM 	    sizeof (stmf_data_buf_t));
123910725SJohn.Forte@Sun.COM }
124010725SJohn.Forte@Sun.COM 
124110725SJohn.Forte@Sun.COM pppt_status_t
pppt_task_start(pppt_task_t * ptask)124210725SJohn.Forte@Sun.COM pppt_task_start(pppt_task_t *ptask)
124310725SJohn.Forte@Sun.COM {
124410725SJohn.Forte@Sun.COM 	avl_index_t		where;
124510725SJohn.Forte@Sun.COM 
124610725SJohn.Forte@Sun.COM 	ASSERT(ptask->pt_state == PTS_INIT);
124710725SJohn.Forte@Sun.COM 
124810725SJohn.Forte@Sun.COM 	mutex_enter(&ptask->pt_sess->ps_mutex);
124910725SJohn.Forte@Sun.COM 	mutex_enter(&ptask->pt_mutex);
125010725SJohn.Forte@Sun.COM 	if (avl_find(&ptask->pt_sess->ps_task_list, ptask, &where) == NULL) {
125110725SJohn.Forte@Sun.COM 		pppt_task_update_state(ptask, PTS_ACTIVE);
125210725SJohn.Forte@Sun.COM 		avl_insert(&ptask->pt_sess->ps_task_list, ptask, where);
125310725SJohn.Forte@Sun.COM 		mutex_exit(&ptask->pt_mutex);
125410725SJohn.Forte@Sun.COM 		mutex_exit(&ptask->pt_sess->ps_mutex);
125510725SJohn.Forte@Sun.COM 		return (PPPT_STATUS_SUCCESS);
125610725SJohn.Forte@Sun.COM 	}
125710725SJohn.Forte@Sun.COM 	mutex_exit(&ptask->pt_mutex);
125810725SJohn.Forte@Sun.COM 	mutex_exit(&ptask->pt_sess->ps_mutex);
125910725SJohn.Forte@Sun.COM 
126010725SJohn.Forte@Sun.COM 	return (PPPT_STATUS_FAIL);
126110725SJohn.Forte@Sun.COM }
126210725SJohn.Forte@Sun.COM 
126310725SJohn.Forte@Sun.COM pppt_status_t
pppt_task_done(pppt_task_t * ptask)126410725SJohn.Forte@Sun.COM pppt_task_done(pppt_task_t *ptask)
126510725SJohn.Forte@Sun.COM {
126610725SJohn.Forte@Sun.COM 	pppt_status_t	pppt_status = PPPT_STATUS_SUCCESS;
126710725SJohn.Forte@Sun.COM 	boolean_t	remove = B_FALSE;
126810725SJohn.Forte@Sun.COM 
126910725SJohn.Forte@Sun.COM 	mutex_enter(&ptask->pt_mutex);
127010725SJohn.Forte@Sun.COM 
127110725SJohn.Forte@Sun.COM 	switch (ptask->pt_state) {
127210725SJohn.Forte@Sun.COM 	case PTS_ACTIVE:
127310725SJohn.Forte@Sun.COM 		remove = B_TRUE;
127410725SJohn.Forte@Sun.COM 		pppt_task_update_state(ptask, PTS_DONE);
127510725SJohn.Forte@Sun.COM 		break;
127610725SJohn.Forte@Sun.COM 	case PTS_ABORTED:
127710725SJohn.Forte@Sun.COM 		pppt_status = PPPT_STATUS_ABORTED;
127810725SJohn.Forte@Sun.COM 		break;
127910725SJohn.Forte@Sun.COM 	case PTS_DONE:
128010725SJohn.Forte@Sun.COM 		/* Repeat calls are OK.  Do nothing, return success */
128110725SJohn.Forte@Sun.COM 		break;
128210725SJohn.Forte@Sun.COM 	default:
128310725SJohn.Forte@Sun.COM 		ASSERT(0);
128410725SJohn.Forte@Sun.COM 	}
128510725SJohn.Forte@Sun.COM 
128610725SJohn.Forte@Sun.COM 	mutex_exit(&ptask->pt_mutex);
128710725SJohn.Forte@Sun.COM 
128810725SJohn.Forte@Sun.COM 	if (remove) {
128910725SJohn.Forte@Sun.COM 		mutex_enter(&ptask->pt_sess->ps_mutex);
129010725SJohn.Forte@Sun.COM 		avl_remove(&ptask->pt_sess->ps_task_list, ptask);
129110725SJohn.Forte@Sun.COM 		mutex_exit(&ptask->pt_sess->ps_mutex);
129210725SJohn.Forte@Sun.COM 	}
129310725SJohn.Forte@Sun.COM 
129410725SJohn.Forte@Sun.COM 	return (pppt_status);
129510725SJohn.Forte@Sun.COM }
129610725SJohn.Forte@Sun.COM 
129710725SJohn.Forte@Sun.COM void
pppt_task_sent_status(pppt_task_t * ptask)129810725SJohn.Forte@Sun.COM pppt_task_sent_status(pppt_task_t *ptask)
129910725SJohn.Forte@Sun.COM {
130010725SJohn.Forte@Sun.COM 	/*
130110725SJohn.Forte@Sun.COM 	 * If STMF tries to abort a task after the task state changed to
130210725SJohn.Forte@Sun.COM 	 * PTS_DONE (meaning all task processing is complete from
130310725SJohn.Forte@Sun.COM 	 * the port provider perspective) then we return STMF_BUSY
130410725SJohn.Forte@Sun.COM 	 * from pppt_lport_abort.  STMF will return after a short interval
130510725SJohn.Forte@Sun.COM 	 * but our calls to stmf_send_status_done will be ignored since
130610725SJohn.Forte@Sun.COM 	 * STMF is aborting the task.  That's where this state comes in.
130710725SJohn.Forte@Sun.COM 	 * This state essentially says we are calling stmf_send_status_done
130810725SJohn.Forte@Sun.COM 	 * so we will not be touching the task again.  The next time
130910725SJohn.Forte@Sun.COM 	 * STMF calls pppt_lport_abort we will return a success full
131010725SJohn.Forte@Sun.COM 	 * status and the abort will succeed.
131110725SJohn.Forte@Sun.COM 	 */
131210725SJohn.Forte@Sun.COM 	mutex_enter(&ptask->pt_mutex);
131310725SJohn.Forte@Sun.COM 	pppt_task_update_state(ptask, PTS_SENT_STATUS);
131410725SJohn.Forte@Sun.COM 	mutex_exit(&ptask->pt_mutex);
131510725SJohn.Forte@Sun.COM }
131610725SJohn.Forte@Sun.COM 
131710725SJohn.Forte@Sun.COM pppt_task_t *
pppt_task_lookup(stmf_ic_msgid_t msgid)131810725SJohn.Forte@Sun.COM pppt_task_lookup(stmf_ic_msgid_t msgid)
131910725SJohn.Forte@Sun.COM {
132010725SJohn.Forte@Sun.COM 	pppt_tgt_t	*tgt;
132110725SJohn.Forte@Sun.COM 	pppt_sess_t	*sess;
132210725SJohn.Forte@Sun.COM 	pppt_task_t	lookup_task;
132310725SJohn.Forte@Sun.COM 	pppt_task_t	*result;
132410725SJohn.Forte@Sun.COM 
132510725SJohn.Forte@Sun.COM 	bzero(&lookup_task, sizeof (lookup_task));
132610725SJohn.Forte@Sun.COM 	lookup_task.pt_task_id = msgid;
132710725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_LOCK();
132810725SJohn.Forte@Sun.COM 	for (tgt = avl_first(&pppt_global.global_target_list); tgt != NULL;
132910725SJohn.Forte@Sun.COM 	    tgt = AVL_NEXT(&pppt_global.global_target_list, tgt)) {
133010725SJohn.Forte@Sun.COM 
133110725SJohn.Forte@Sun.COM 		mutex_enter(&tgt->target_mutex);
133210725SJohn.Forte@Sun.COM 		for (sess = avl_first(&tgt->target_sess_list); sess != NULL;
133310725SJohn.Forte@Sun.COM 		    sess = AVL_NEXT(&tgt->target_sess_list, sess)) {
133410725SJohn.Forte@Sun.COM 			mutex_enter(&sess->ps_mutex);
133510725SJohn.Forte@Sun.COM 			if ((result = avl_find(&sess->ps_task_list,
133610725SJohn.Forte@Sun.COM 			    &lookup_task, NULL)) != NULL) {
133710725SJohn.Forte@Sun.COM 				if (pppt_task_hold(result) !=
133810725SJohn.Forte@Sun.COM 				    PPPT_STATUS_SUCCESS) {
133910725SJohn.Forte@Sun.COM 					result = NULL;
134010725SJohn.Forte@Sun.COM 				}
134110725SJohn.Forte@Sun.COM 				mutex_exit(&sess->ps_mutex);
134210725SJohn.Forte@Sun.COM 				mutex_exit(&tgt->target_mutex);
134310725SJohn.Forte@Sun.COM 				PPPT_GLOBAL_UNLOCK();
134410725SJohn.Forte@Sun.COM 				return (result);
134510725SJohn.Forte@Sun.COM 			}
134610725SJohn.Forte@Sun.COM 			mutex_exit(&sess->ps_mutex);
134710725SJohn.Forte@Sun.COM 		}
134810725SJohn.Forte@Sun.COM 		mutex_exit(&tgt->target_mutex);
134910725SJohn.Forte@Sun.COM 	}
135010725SJohn.Forte@Sun.COM 	PPPT_GLOBAL_UNLOCK();
135110725SJohn.Forte@Sun.COM 
135210725SJohn.Forte@Sun.COM 	return (NULL);
135310725SJohn.Forte@Sun.COM }
135410725SJohn.Forte@Sun.COM 
135510725SJohn.Forte@Sun.COM static int
pppt_task_avl_compare(const void * void_task1,const void * void_task2)135610725SJohn.Forte@Sun.COM pppt_task_avl_compare(const void *void_task1, const void *void_task2)
135710725SJohn.Forte@Sun.COM {
135810725SJohn.Forte@Sun.COM 	const pppt_task_t	*ptask1 = void_task1;
135910725SJohn.Forte@Sun.COM 	const pppt_task_t	*ptask2 = void_task2;
136010725SJohn.Forte@Sun.COM 
136110725SJohn.Forte@Sun.COM 	if (ptask1->pt_task_id < ptask2->pt_task_id)
136210725SJohn.Forte@Sun.COM 		return (-1);
136310725SJohn.Forte@Sun.COM 	else if (ptask1->pt_task_id > ptask2->pt_task_id)
136410725SJohn.Forte@Sun.COM 		return (1);
136510725SJohn.Forte@Sun.COM 
136610725SJohn.Forte@Sun.COM 	return (0);
136710725SJohn.Forte@Sun.COM }
136810725SJohn.Forte@Sun.COM 
136910725SJohn.Forte@Sun.COM static pppt_status_t
pppt_task_try_abort(pppt_task_t * ptask)137010725SJohn.Forte@Sun.COM pppt_task_try_abort(pppt_task_t *ptask)
137110725SJohn.Forte@Sun.COM {
137210725SJohn.Forte@Sun.COM 	boolean_t	remove = B_FALSE;
137310725SJohn.Forte@Sun.COM 	pppt_status_t	pppt_status = PPPT_STATUS_SUCCESS;
137410725SJohn.Forte@Sun.COM 
137510725SJohn.Forte@Sun.COM 	mutex_enter(&ptask->pt_mutex);
137610725SJohn.Forte@Sun.COM 
137710725SJohn.Forte@Sun.COM 	switch (ptask->pt_state) {
137810725SJohn.Forte@Sun.COM 	case PTS_ACTIVE:
137910725SJohn.Forte@Sun.COM 		remove = B_TRUE;
138010725SJohn.Forte@Sun.COM 		pppt_task_update_state(ptask, PTS_ABORTED);
138110725SJohn.Forte@Sun.COM 		break;
138210725SJohn.Forte@Sun.COM 	case PTS_DONE:
138310725SJohn.Forte@Sun.COM 		pppt_status = PPPT_STATUS_DONE;
138410725SJohn.Forte@Sun.COM 		break;
138510725SJohn.Forte@Sun.COM 	case PTS_SENT_STATUS:
138610725SJohn.Forte@Sun.COM 		/*
138710725SJohn.Forte@Sun.COM 		 * Already removed so leave remove set to B_FALSE
138810725SJohn.Forte@Sun.COM 		 * and leave status set to PPPT_STATUS_SUCCESS.
138910725SJohn.Forte@Sun.COM 		 */
139010725SJohn.Forte@Sun.COM 		pppt_task_update_state(ptask, PTS_ABORTED);
139110725SJohn.Forte@Sun.COM 		break;
139210725SJohn.Forte@Sun.COM 	case PTS_ABORTED:
139310725SJohn.Forte@Sun.COM 		break;
139410725SJohn.Forte@Sun.COM 	default:
139510725SJohn.Forte@Sun.COM 		ASSERT(0);
139610725SJohn.Forte@Sun.COM 	}
139710725SJohn.Forte@Sun.COM 
139810725SJohn.Forte@Sun.COM 	mutex_exit(&ptask->pt_mutex);
139910725SJohn.Forte@Sun.COM 
140010725SJohn.Forte@Sun.COM 	if (remove) {
140110725SJohn.Forte@Sun.COM 		mutex_enter(&ptask->pt_sess->ps_mutex);
140210725SJohn.Forte@Sun.COM 		avl_remove(&ptask->pt_sess->ps_task_list, ptask);
140310725SJohn.Forte@Sun.COM 		mutex_exit(&ptask->pt_sess->ps_mutex);
140410725SJohn.Forte@Sun.COM 	}
140510725SJohn.Forte@Sun.COM 
140610725SJohn.Forte@Sun.COM 	return (pppt_status);
140710725SJohn.Forte@Sun.COM }
140810725SJohn.Forte@Sun.COM 
140910725SJohn.Forte@Sun.COM static pppt_status_t
pppt_task_hold(pppt_task_t * ptask)141010725SJohn.Forte@Sun.COM pppt_task_hold(pppt_task_t *ptask)
141110725SJohn.Forte@Sun.COM {
141210725SJohn.Forte@Sun.COM 	pppt_status_t	pppt_status = PPPT_STATUS_SUCCESS;
141310725SJohn.Forte@Sun.COM 
141410725SJohn.Forte@Sun.COM 	mutex_enter(&ptask->pt_mutex);
141510725SJohn.Forte@Sun.COM 	if (ptask->pt_state == PTS_ACTIVE) {
141610725SJohn.Forte@Sun.COM 		ptask->pt_refcnt++;
141710725SJohn.Forte@Sun.COM 	} else {
141810725SJohn.Forte@Sun.COM 		pppt_status = PPPT_STATUS_FAIL;
141910725SJohn.Forte@Sun.COM 	}
142010725SJohn.Forte@Sun.COM 	mutex_exit(&ptask->pt_mutex);
142110725SJohn.Forte@Sun.COM 
142210725SJohn.Forte@Sun.COM 	return (pppt_status);
142310725SJohn.Forte@Sun.COM }
142410725SJohn.Forte@Sun.COM 
142510725SJohn.Forte@Sun.COM static void
pppt_task_rele(pppt_task_t * ptask)142610725SJohn.Forte@Sun.COM pppt_task_rele(pppt_task_t *ptask)
142710725SJohn.Forte@Sun.COM {
142810725SJohn.Forte@Sun.COM 	mutex_enter(&ptask->pt_mutex);
142910725SJohn.Forte@Sun.COM 	ptask->pt_refcnt--;
143010725SJohn.Forte@Sun.COM 	cv_signal(&ptask->pt_cv);
143110725SJohn.Forte@Sun.COM 	mutex_exit(&ptask->pt_mutex);
143210725SJohn.Forte@Sun.COM }
143310725SJohn.Forte@Sun.COM 
143410725SJohn.Forte@Sun.COM static void
pppt_task_update_state(pppt_task_t * ptask,pppt_task_state_t new_state)143510725SJohn.Forte@Sun.COM pppt_task_update_state(pppt_task_t *ptask,
143610725SJohn.Forte@Sun.COM     pppt_task_state_t new_state)
143710725SJohn.Forte@Sun.COM {
143810725SJohn.Forte@Sun.COM 	PPPT_LOG(CE_NOTE, "task %p %d -> %d", (void *)ptask,
143910725SJohn.Forte@Sun.COM 	    ptask->pt_state, new_state);
144010725SJohn.Forte@Sun.COM 
144110725SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&ptask->pt_mutex));
144210725SJohn.Forte@Sun.COM 	ptask->pt_state = new_state;
144310725SJohn.Forte@Sun.COM 	cv_signal(&ptask->pt_cv);
144410725SJohn.Forte@Sun.COM }
1445