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